アプリケーションマニフェスト

Delphi のアプリケーションマニフェスト

Delphi でアプリケーションマニフェストがサポートされたのは Delphi 7 からです。

バージョン 外部マニフェスト 内部マニフェスト
XPMan 使用 IDE が生成 カスタム
Delphi 2 ~ 6 実行ファイル名.manifest を実行ファイルと同じ場所に置く - - リソースファイルを {$R} で埋め込むか、リソースエディタで直接書き換える
Delphi 7 ~ 2006 TXPmanifest をフォームに貼るか、XPMan を uses 節に加える
Delphi 2007 ~XE プロジェクトオプションでランタイムテーマを有効にする
Delphi XE2 ~ XPMan に効果はない プロジェクトオプションでカスタムマニフェストを指定する

アプリケーションマニフェストの優先順位は、XP の場合 "外部マニフェスト > 内部マニフェスト" で、 Vista またはそれ以降の場合、"内部マニフェスト > 外部マニフェスト" となります。つまり、XP でのみ "内部マニフェストを外部マニフェストでオーバライドする" という手法が使えます。

古い Delphi でアプリケーションマニフェストを利用するには? (~ Delphi 6)

 "Windows XP 対応アプリを作る (Delphi VCL Tips)" に詳細があります。

XPMan / TXPManifest (Delphi 7 ~)

 Delphi 7 ~ 2006 でアプリケーションマニフェストを埋め込むには XPMan を利用します。TXPManifest をフォームに貼るのは無駄なので、uses 節に XPMan を加えるのがいいと思います。

 TXPmanifest の正体は中身のないコンポーネントです。TXPmanifest が定義されている XPMan.pas を uses 節に加えると WindowsXP.res をリソースとしてリンクします。逆に言えば、フォーム上の TXPmanifest を削除しても、uses 節に XPMan が残っていればアプリケーションマニフェストリソースはリンクされてしまいます。

 Delphi 2007 以降では XPMan / TXPmanifest を使わず、プロジェクトオプションで "ランタイムテーマを有効にする" を選択すべきでしょう。

 XE2 以降の場合、TXPmanifest を貼ったり XPMan を uses 節に加える事にもはや何の意味もありません。WindowsXP.res はリンクされないからです。

画像は XE3 で TXPmanifest を貼ったアプリケーションをコンパイルして実行した結果です。

"ランタイムテーマを有効にする" と XPMan (Delphi 2007~XE)

 "ランタイムテーマを有効にする" にチェックが入っている場合と、"ランタイムテーマを有効にする" にチェックが入っておらず、XPMan が uses 節に加えられている場合ではアプリケーションに埋め込まれたアプリケーションマニフェストの内容が異なります。

"ランタイムテーマを有効にする" チェック時のアプリケーションマニフェストの例 (Delphi 2007)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    type="win32"
    name="CodeGear RAD Studio"
    version="11.0.2902.10471" 
    processorArchitecture="*"/>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
        type="win32"
        name="Microsoft.Windows.Common-Controls"
        version="6.0.0.0"
        publicKeyToken="6595b64144ccf1df"
        language="*"
        processorArchitecture="*"/>
    </dependentAssembly>
  </dependency>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel
          level="asInvoker"
          uiAccess="false"/>
        </requestedPrivileges>
    </security>
  </trustInfo>
</assembly>

XPMan 使用時のアプリケーションマニフェストの例 (Delphi 2007)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
        type="win32"
        name="DelphiApplication"
        version="1.0.0.0"
        processorArchitecture="*"/>
  <dependency>
        <dependentAssembly>
          <assemblyIdentity
                type="win32"
                name="Microsoft.Windows.Common-Controls"
                version="6.0.0.0"
                publicKeyToken="6595b64144ccf1df"
                language="*"
                processorArchitecture="*"/>
        </dependentAssembly>
  </dependency>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <security>
          <requestedPrivileges>
                <requestedExecutionLevel
                  level="asInvoker"
                  uiAccess="false"/>
          </requestedPrivileges>
        </security>
  </trustInfo>
</assembly>

"ランタイムテーマを有効にする" チェック時には、アプリケーション名に "RAD Studio" が、version には Delphi のビルドバージョンが埋め込まれます。

"ランタイムテーマを有効にする" にチェックを入れて、XPMan が uses された状態だと、マニフェストリソースが 2 つ登録されます。恐らく IDE が設定しているアプリケーションマニフェストが優先されると思いますが、誤動作の原因になりかねないので "ランタイムテーマを有効にする" と XPMan は排他で使用して下さい。

XPMan で Vista 以降のアプリケーションマニフェストに対応するには? (Delphi 7 ~ 2006)

Delphi 7 ~ 2006 において XPMan が uses 節に加えられた時のアプリケーションマニフェストは次のようなものになっています。

XPMan 使用時のアプリケーションマニフェストの例 (Delphi 7)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
        type="win32"
    name="DelphiApplication"
    version="1.0.0.0" 
        processorArchitecture="*"/>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
        type="win32"
        name="Microsoft.Windows.Common-Controls"
        version="6.0.0.0"
        publicKeyToken="6595b64144ccf1df"
        language="*"
        processorArchitecture="*"/>
    </dependentAssembly>
  </dependency>
</assembly>

見ての通り、trustInfo 要素がありません。Vista 以降のアプリケーションマニフェストにするには、2007 ~ XE の $(BDS)\lib フォルダに存在する WindowsXP.res をコピーして持ってくるか、以下の手順で WindowsXP.res を修正します。

  1. WindowsXP.res のバックアップを取る
  2. XN Resource Editor で WindowsXP.res を開く
  3. XP Theme Manifest を開く
  4. </assembly> の上に、以下を追加する
      <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <security>
          <requestedPrivileges>
            <requestedExecutionLevel
              level="asInvoker"
              uiAccess="false"/>
            </requestedPrivileges>
        </security>
      </trustInfo>
  5. 保存して終了する。

アプリケーションマニフェストに requestedExecutionLevel 要素の level 属性が存在する場合には UAC によるフォルダやレジストリの仮想化は行われません

管理者権限での実行が必要なアプリケーションで UAC プロンプトを表示するようにするには? (Vista 以降の OS への対応)

HKEY_LOCAL_MACHINE のレジストリをいじる (書き込む) アプリケーションや、ドライブルート、Program Files、システムフォルダへアクセスするようなアプリケーションは管理者権限が必要です。右クリックして "管理者として実行" しなければ正常動作しないアプリケーションがこれに該当します。

          level="asInvoker"

この level 属性の値を requireAdministrator へ変更すれば、アプリケーション起動時に自動で UAC プロンプトが表示されるようになります。

説明 コメント
asInvoker アプリケーションは、アプリケーションを開始したプロセスと同じアクセス許可で実行されます。 [管理者として実行] を選択すると、アプリケーションをより高いアクセス許可に昇格させることができます。Delphi 2007 以降のアプリケーションマニフェストのデフォルトです。
highestAvailable アプリケーションは、可能な限り高いアクセス許可レベルで実行されます。 アプリケーションを開始するユーザーが管理者グループのメンバーである場合、このオプションは requireAdministrator と同じです。 使用可能な最も高いアクセス許可レベルが、開始したプロセスのレベルより高い場合は、資格情報の入力が求められます。
requireAdministrator アプリケーションは管理者のアクセス許可で実行されます。 アプリケーションを開始するユーザーは、管理者グループのメンバーである必要があります。 開始したプロセスが管理者のアクセス許可で実行されない場合は、資格情報の入力が求められます。

"requireAdministrator を指定すれば管理者権限で動作する" という訳ではありません。管理者権限が必要なアプリケーションの起動時に、昇格用の UAC プロンプトを出すための設定です。

逆に "asInvoker" で ([管理者として実行] する事なしに) 動作させるためには、HKEY_LOCAL_MACHINE を読み取り専用で開く (TRegistryTRegIniFile の create に KEY_READ を指定する) ように変更したり、環境ファイルを実行ファイルと同じ場所ではなく、アプリケーションデータパス (%APPDATA%) に保存する (または HKEY_CURRENT_USER なレジストリに保存する) ようにする等の工夫が必要となります。

Windows Vista 互換モードの解除 (Windows 7 以降)

Windows 7 で新しく追加された要素である compatibility 要素が存在しないアプリケーションは Windows 7 以降の OS において Windows Vista モードで動作します

モードの確認にはリソースモニタ (resmon.exe) を使います。[オペレーティングシステムのコンテキスト] は標準では表示されていないので、ヘッダを右クリックして [列の選択(S)...] を選び、"オペレーティングシステムのコンテキスト" にチェックを入れます。

アプリケーションマニフェストに以下を追加するとネイティブモードにする事ができます。

  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
        <application>
                <!--Windows 10-->
                <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
                <!--Windows 8.1-->
                <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
                <!--Windows 8-->
                <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
                <!--Windows 7-->
                <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
                <!--Windows Vista-->
                <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
        </application>
  </compatibility>

ネイティブモード動作させるための ID (GUID) は OS 毎に異なり、新しい Windows がリリースされる都度 Microsoft から発行される事になっています。

よほど特殊な事をしていない限り、Delphi アプリケーションは ネイティブモードで動作させる事が可能だと思います。以下のサンプルを参考にしてカスタムマニフェストを組み込んでみるのもいいかもしれません。

ネイティブモード対応のカスタムマニフェストの例
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
        type="win32"
        name="DelphiApplication"
        version="1.0.0.0"
        processorArchitecture="*"/>
  <dependency>
        <dependentAssembly>
          <assemblyIdentity
                type="win32"
                name="Microsoft.Windows.Common-Controls"
                version="6.0.0.0"
                publicKeyToken="6595b64144ccf1df"
                language="*"
                processorArchitecture="*"/>
        </dependentAssembly>
  </dependency>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <security>
          <requestedPrivileges>
                <requestedExecutionLevel
                  level="asInvoker"
                  uiAccess="false"/>
          </requestedPrivileges>
        </security>
  </trustInfo>
  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
        <application>
                <!--Windows 10-->
                <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
                <!--Windows 8.1-->
                <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
                <!--Windows 8-->
                <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
                <!--Windows 7-->
                <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
                <!--Windows Vista-->
                <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
        </application>
  </compatibility>
</assembly>

ネイティブモードのテストは入念に行ってください。ネイティブモードで動作すれば PCA (プログラム互換性アシスタント) の影響を受けなくなったりするので、アプリケーションが高速化する可能性があります。

なお、PCA が問題を修正した履歴は レジストリの [HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Compatibility Assistant\Persisted] にあります。

IDE が生成するアプリケーションマニフェストのデフォルト設定を変更するには? (Delphi XE2 以降)

$(BDS)\bin にある default_app.manifest を書き換えます。

Delphi 2007~XE ではアプリケーションマニフェストを、恐らく bds.exe (または delphicoreidennn.bpl) 内部にあるマニフェストから生成しています。つまり、アプリケーションマニフェストのデフォルト設定を変更するのは事実上不可能です。

アプリケーション内で管理者権限で動作しているかそうでないかを判断する

アプリケーションが管理者権限で動作しているかそうでないかを判断するには IsUserAnAdmin() API を使います (Windows XP 以降)。IsUserAnAdmin() API は Delphi 2010 以降であれば (Winapi.)ShlObj 内で定義されています。Vista 以降でしか判断する必要がないのであれば、(System.)SysUtils.CheckWin32Version() を併用します。

See Also:

※ アプリケーションマニフェストの重要情報は部分的に散在しており、日本語に翻訳されていないものも多く見受けられます。


 BACK