前回の記事「UAC (User Account Control)と C/C++ MFC アプリケーション(その1)」の続きです。
前回は、Application Manifests と Virtualization について解説しました。今回は、それらの組み合わせによるアプリケーションの挙動についてサンプルアプリケーションを元に解説します。
● マニフェストなし、または requestedExecutionLevel 要素記述なしの場合
この場合は、Virtualization 機能により、権限のないフォルダやレジストリキーへの書き込みがリダイレクトされ、エラー無く実行されます。ただし、この場合に注意が必要なのは、インストール時に設定情報などのファイルを %PorgramFiles% のインストールフォルダにインストールし、そのファイルをアプリケーション実行時に読み書き可能なモードで開いたりした場合に、%USERPROFILE%\AppData\Local\VirtualStore\Program Files\ 以下のフォルダにリダイレクトされるので、設定情報が読み込めないなどの不具合が発生する可能性があります。
図:サンプルアプリケーションの実行(マニフェスト無しの場合)

C:\Program Files\BitWiz\test.txt の作成に成功している(上図)が、C:\Program Files\BitWiz には test.txt が生成されていない(下図)。
図:サンプルアプリケーションの実行フォルダ

Virtualization(仮想化)機能により、C:\Users\\AppData\Local\VirtualStore\Program Files\BitWiz フォルダに test.txt が生成されている(下図)。
図:C:\Users\\AppData\Local\VirtualStore\Program Files\BitWiz フォルダ

サンプルアプリケーションの実行結果では、HKEY_LOCAL_MACHINE\SOFTWARE\BitWiz のレジストリキーのオープン(KEY_ALL_ACCESS)に成功しているが、実際は HKEY_CURRENT_USER\Software\Classes\VirtualStore\MACHINE\SOFTWARE\BitWiz キーがオープンされて値が取得されている。
図:レジストリキーのリダイレクト

● マニフェストありで、requestedExecutionLevel 要素記述ありの場合
Virtualization 機能は無効となり、仮想化(ファイルやレジストリのリダイレクション)は行われません。
■ asInvoker
requestedExecutionLevel 要素の level 属性値を asInvoker とした場合、親プロセスと同じ特権で実行されるため、書き込み権限のない C:\Program Files や HKEY_LOCAL_MACHINE への書き込みなどはエラーとなります。
図:サンプルアプリケーションの実行(マニフェストあり(asInvoker)の場合)

asInvoker 属性値により権限の昇格なしで実行されているため、ファイルの作成、レジストリキーのアクセスともに失敗している。Virtualization 機能も無効となり、リダイレクトも行われない。
■ highestAvailable / requireAdministrator
requestedExecutionLevel 要素の level 属性値に highestAvailable や requireAdministrator とすると、実行時に UAC 昇格確認ダイアログが表示される。
ここで、実行を許可すると C:\Program Files や HKEY_LOCAL_MACHINE への書き込みなどが可能となる。
図:実行時の UAC ダイアログ

実行時に必ず UAC 昇格確認ダイアログが表示される(上図)。
図:サンプルアプリケーションの実行(マニフェストあり(requireAdministrator)の場合)

ファイルの作成、レジストリキーのアクセス共に成功している(上図)。
図:サンプルアプリケーションの実行フォルダ

C:\Program Files\BitWiz\test.txt が生成されている。
また、マニフェストの requireAdministrator 属性値により、自動でアプリケーションアイコンにシールドアイコンが表示され、権限の昇格を行わないと実行できないことがわかる(上図)。
図:HKEY_LOCAL_MACHINE レジストリキーへのアクセス

指定どおり、HKEY_LOCAL_MACHINE\SOFTWARE\BitWiz レジストリキーのオープン(KEY_ALL_ACCESS)に成功している(上図)。
● インストーラ検出技術の条件に一致した場合
基本的には requestedExecutionLevel 要素の level 属性値が優先されますが、この要素記述が無い場合は "install" "setup" "update" などのキーワードがファイル名やバージョンリソースに含まれるとインストーラと判断され、UAC 昇格確認ダイアログが表示されることとなります。
図:ファイル名に "Setup" という文字列を含んだアプリケーション

マニフェストに requestedExecutionLevel 要素の記述を行っていないが、アプリケーションアイコンにシールドアイコンが表示されている(上図)。
図:インストーラとして検出されたアプリケーションの終了後に表示される確認ダイアログ

アプリケーション実行終了後、正しくインストールされたかの確認ダイアログが表示される(上図)。
さて、アプリケーションがインストーラとして検出される条件はどのようになっているのでしょうか?
以下は
「Installer Detection Technology」
http://technet.microsoft.com/en-us/windowsvista/aa905117.aspx
からの抜粋です。
Installer Detection only applies to:
1. 32 bit executables
2. Applications without a requestedExecutionLevel
3. Interactive processes running as a Standard User with LUA enabled
Before a 32 bit process is created, the following attributes are checked to determine whether it is an installer:
- Filename includes keywords like "install," "setup," "update," etc.
- Keywords in the following Versioning Resource fields: Vendor, Company Name, Product Name, File Description, Original Filename, Internal Name, and Export Name.
- Keywords in the side-by-side manifest embedded in the executable.
- Keywords in specific StringTable entries linked in the executable.
- Key attributes in the RC data linked in the executable.
- Targeted sequences of bytes within the executable.
ファイル名だけでなはく、バージョンリソースなどに含まれるキーワードでも判断されるようです。
● UAC 対応のシナリオ
■ 意図的に仮想化(Virtualization)させる場合
アプリケーションマニフェストに requestedExecutionLevel 要素の記述を行わない。
※注意点
インストール時等に C:\Program Files にコピーされたファイルなどへの読み書きを前提にしている場合、そのファイルをWriteで開く時点で C:\Users\\AppData\Local\VirtualStore\Program Files\ にリダイレクトされるので、ファイルが存在しないなどのエラーとなる。
■ 仮想化(Virtualization)を行わずに、且つファイルやレジストリへのアクセス権限も正しく行っていて、管理者権限での実行が不要な場合。もしくは実行ファイル名に "install", "setup", "update" などの文字を含める必要があるが、インストーラとして認識されたくない場合
アプリケーションマニフェストに requestedExecutionLevel 要素の記述を行い level 属性値を asInvoker とする。
■ 仮想化(Virtualization)は行いたくないが、Program Files や HKEY_LOCAL_MACHINE などへの書き込み参照が必要な場合
アプリケーションマニフェストに requestedExecutionLevel 要素の記述を行い level 属性値を requireAdministrator とする。
■ 仮想化(Virtualization)を行い、かつファイル名などに "install", "setup", "update" などの文字を含める必要がある場合
不可能。必ずインストーラとして認識されてしまい管理者権限に昇格しないと実行できないため、この場合は仮想化を行うことはできない。
● おわりに
Windows Vista 対応のアプリケーションを開発する場合、UAC への理解が必須と思われますが、慣れないうちはなかなかわかりにくいところです。
今回は、マニフェストをアプリケーションリソースに埋め込む方法でいろいろと試してみましたが、マニフェストを外部ファイルとして実行ファイルと同じフォルダに置いた場合、若干異なる動きをすることを確認しています。時間がとれればそのあたりも調べてみたいと思っていますが、とりあえずは、埋め込みマニフェストを使い、アプリケーションの権限昇格の要/不要を制御するか、Virtualization 機能を前提としたアプリケーション実装を行うことが確実でしょう。
また、Authenticode 証明書などでアプリケーションに署名を行うと、UAC の昇格確認ダイアログの表示が変わったりするのですが、今回は署名されている場合の説明は割愛します。