2007年09月26日

Vista で動くプログラムを書くために 〜UAC編〜

はてなブックマークに登録

■ はじめに

今年(2007年) 1 月末にマイクロソフト社が発売した Windows Vista は今なお様々な話題を集めています。 発売から半年余を経た現在、普及率はまだあまり高くありませんが、現在主流の Windows XP は 販売もサポートも次第にフェードアウトしてゆく運命にあり、今後 Windows 用プログラムの開発を行う際には Vista での動作に留意する必要があります。
Vista 初出の仕様のうち、一般のアプリケーション開発者にとって最も重要なものは次の二点と言えるでしょう。

  • UAC (ユーザアカウント制御) による管理ユーザ権限の抑制
  • JIS2004 対応に伴う日本語文字セットの拡張
随所で取り沙汰されているように、旧バージョンの Windows や他のプラットフォームとの間でテキストデータをやりとりする 上で後者は悩ましい話題です。しかし、前者への考慮が不十分なプログラムは、それが原因でインストールさえ できないケースがあるため影響はより直接的です。 今回は、Vista の UAC 環境でも正しく動作するプログラムを開発する上で最低限抑えておくべきポイントをまとめてみます。

目次

基本的な考え方

Windows Vista の UAC (User Account Control) 機能の主目的はマルウェア対策です。UAC が有効であれば 管理ユーザであってもログオンセッション中の権限は標準ユーザと同等以下の内容に制限され、 特権の必要な操作に際してはシステムからユーザへ確認の問い合わせが行われます。
UAC の有効/無効はコントロールパネルから切り替えることができますが、デフォルトでは有効に設定されており、 また、安全弁として用意されているこの機能をあえて無視する必然性はないでしょう。 そのため、プログラム開発においては、ユーザ環境で UAC が有効であっても無効であっても、さらには途中で それが切り替えられても、プログラムの動作に問題が発生しないように注意する必要があります。

UAC 対策に際して最初に考えるべきことは「このプログラムの実行には管理者権限が必要か?」という点です。 もし標準ユーザの権限で運用可能な処理内容であれば UAC 環境でもプログラムの変更なしに動作する可能性が 十分にありますし、 仮にそのままでは動作しなかったとしても、おそらくはプログラムデザインをわずかに変更することで対応できるケースが ほとんどでしょう。

この点を見極めるための項目を以下に挙げてみます。もし、あなたのプログラムがこれらに触れていないか、 あるいはプログラムの目的を変更することなく各項目の内容に準じた改修が可能であれば UAC のハードルは おそらく容易にクリアできるはずです。
もし、そうではなく管理者権限が必須の処理を行っている場合にはプログラム実行時にそのプロセスの権限を「昇格」させるための措置が必要となります。


「%PROGRAMFILES% 下に更新対象ファイルを置かない」

C:\Program Files フォルダ配下にプログラムの実行ファイルを配置することは一般的ですが、更新を前提とする データファイル(.ini ファイル等)を配置すべきではありません。 UAC 環境においては %PROGRAMFILES% フォルダ下のファイルへの書き込みはシステムよってトラップされ、 実際には別のフォルダ(※)下に保存されます。これは「ファイルの仮想化(Virtualization)」と呼ばれるものです。 この仮想化機能は UAC に対応していないプログラムの互換性維持のみを目的に提供されているものであり、 MS 社はこれに依存しないことを推奨しています。
また、仮想化は UAC が有効な場合にのみ実施されるため、これに依存してしまうと、UAC 有効時に仮想化を経て 保存されたデータが UAC が無効化された状況ではプログラムへ反映されないという問題を誘発します。

(※) C:\Users\[アカウント名]\AppData\Local\VirtualStore というロケーションであり、「バーチャルストア」と呼ばれます


「%SYSTEMROOT% 下のファイルを操作対象としない」

C:\Windows フォルダ下のファイルを直接操作するプログラムはアウトです。 ちなみに、同フォルダ配下のファイルも上記の仮想化の対象となります。


「%SYSTEMDRIVE% 直下にファイルを出力しない」

C:ドライブのルートフォルダへファイルを出力することはできません。 「必ず存在するパス」であることを理由に決め打ちで %SYSTEMDRIVE% へファイルを出力する プログラムは意外と多いものですが、その操作は確実に失敗します。


「2000〜XP 世代のシステム既定のパスを直接指定しない」

Windows 2000 や XP では、APPDATA や LOCAL_APPDATA は以下の内容でした。 (%SYSTEMDRIVE% が C: の場合)

<APPDATA>
C:\Documents and Settings\[アカウント名]\Application Data

<LOCAL_APPDATA>
C:\Documents and Settings\[アカウント名]\Local Settings\Application Data
しかし、Vista ではこれらのパスは変更されています(※)。 付録参照
<APPDATA>
C:\Users\[アカウント名]\AppData\Roaming

<LOCAL_APPDATA>
C:\Users\[アカウント名]\AppData\Local
これらのシステム既定のパスを使用する場合は必ず SHGetFolderPath 等の API で照会すべきです。
(※) 実際にはシンボリックリンクとジャンクションの組み合せにより、旧来の各パスは Vista での新しい上記のパスへリンクされていますが、 こういった救済措置には依存しない方が賢明でしょう。 ちなみに、互換性維持のために設置されたこれらのリンクにはすべて Hidden 属性が設定されています。

「All Users 用の更新対象データを無造作に設置しない」

Windows 2000 や XP では、All Users 用のプログラムデータの保存場所は以下のロケーションでした。 (%SYSTEMDRIVE% が C: の場合)

<COMMON_APPDATA>
C:\Documents and Settings\All Users\Application Data
Vista では次のパスに変更されています。 付録参照
<COMMON_APPDATA>
C:\ProgramData
このパスは Vista 初出&既定の %PROGRAMDATA% フォルダに相当します。 このフォルダ配下のファイルもまた仮想化の対象となるため注意が必要です。 つまり、この場所にプログラム用のデータを保存する場合、プログラムから読み込みを 行うのみであれば各ユーザのログオンセッション上のプロセスから正しく参照することができますが、 各ユーザによってデータの更新が行われるケースでは、データファイルに対する権限が不足していると ファイルの仮想化によりユーザ個別のバーチャルストアへのリダイレクトが発生するため混乱の原因となります。 これを回避するには、該当するデータファイルの権限をあらかじめ操作しておくか、あるいは はじめからこの場所を使用せず、ユーザごとの LOCAL_APPDATA フォルダを使用すべきでしょう。

「レジストリの HKLM\Software 以下のエントリを操作しない」

「HKEY_LOCAL_MACHINE\Software」下のエントリへの書き込みは仮想化され、以下へリダイレクトされます。 HKEY_CURRENT_USER\Software\Classes\VirtualStore\MACHINE\SOFTWARE
そのため、たとえば所定のアプリケーション用の更新データをアカウント間で共有することを目的に レジストリを使用することは適切ではありません。


「インストーラは??」

上に書いたすべての項目はユーザの PC へセットアップされた実行ファイルとデータに関する話題です。 そして、それらのリソースをセットアップするために使用されるインストーラもまた単なる実行形式のファイルですから UAC の影響を受けるはずです。 しかし、インストーラ本体は処理の過程においてしばしばシステムの深部へアクセスする必要があるため、 Vista はインストーラには例外的な対応を行います。

そもそも Windows Installer など UAC に対応したビルダによって生成されたインストーラであれば問題は ありませんし、MS 社自身も Windows Installer の使用を推奨しています。 しかし、世の中には MS 社製以外のビルダは山ほどあり、現時点では UAC に対応していない製品が 多数を占めるでしょう。 そういった事情を考慮してか、Vista では実行ファイルがインストーラであるか否かの判定を 独自の方法で行っていると MS 社は説明しています。

その一環として、実行ファイル名に "Setup" "Install" "Update" といった文字列が含まれていれば それをインストーラとみなすというダイナミックな対応も組み込まれています。 この措置は状況によっては開発者にとって非常に有用なものとなるでしょう。
ある実行ファイルがインストーラと判断された場合、その実行時にシステムは権限昇格可否をユーザへ確認し、 昇格が了承されれば TrustedInstaller という特殊な権限でプログラムを起動します。 このプロセスにはシステム全体への特権でのアクセスが容認されます。



付録

筆者の手元にある Windows Vista/ XP/ 2000 の各環境において SHGetFolderPath API を呼び出し、 システム既定フォルダの主なものをリストアップしてみました。
(%TEMP% 分は GetTempPath API で取得したパスをロングネームで表現したものです)
あくまでも固有の環境での結果ではありますが、Vista のフォルダ構成を把握するための一助となれば幸いです。

                 <Windows Vista Business>

                CSIDL_PROFILE = C:\Users\[アカウント名]
               CSIDL_PERSONAL = C:\Users\[アカウント名]\Documents
             CSIDL_MYPICTURES = C:\Users\[アカウント名]\Pictures
       CSIDL_DESKTOPDIRECTORY = C:\Users\[アカウント名]\Desktop
              CSIDL_TEMPLATES = C:\Users\[アカウント名]\AppData\Roaming\Microsoft\Windows\Templates
                CSIDL_APPDATA = C:\Users\[アカウント名]\AppData\Roaming
          CSIDL_LOCAL_APPDATA = C:\Users\[アカウント名]\AppData\Local
         CSIDL_INTERNET_CACHE = C:\Users\[アカウント名]\AppData\Local\Microsoft\Windows\Temporary Internet Files
       CSIDL_COMMON_DOCUMENTS = C:\Users\Public\Documents
         CSIDL_COMMON_APPDATA = C:\ProgramData
CSIDL_COMMON_DESKTOPDIRECTORY = C:\Users\Public\Desktop
          CSIDL_PROGRAM_FILES = C:\Program Files
   CSIDL_PROGRAM_FILES_COMMON = C:\Program Files\Common Files
                CSIDL_WINDOWS = C:\Windows
                 CSIDL_SYSTEM = C:\Windows\system32
                       %TEMP% = C:\Users\[アカウント名]\AppData\Local\Temp\

                 <Windows XP Professional>

                CSIDL_PROFILE = C:\Documents and Settings\[アカウント名]
               CSIDL_PERSONAL = C:\Documents and Settings\[アカウント名]\My Documents
             CSIDL_MYPICTURES = C:\Documents and Settings\[アカウント名]\My Documents\My Pictures
       CSIDL_DESKTOPDIRECTORY = C:\Documents and Settings\[アカウント名]\デスクトップ
              CSIDL_TEMPLATES = C:\Documents and Settings\[アカウント名]\Templates
                CSIDL_APPDATA = C:\Documents and Settings\[アカウント名]\Application Data
          CSIDL_LOCAL_APPDATA = C:\Documents and Settings\[アカウント名]\Local Settings\Application Data
         CSIDL_INTERNET_CACHE = C:\Documents and Settings\[アカウント名]\Local Settings\Temporary Internet Files
       CSIDL_COMMON_DOCUMENTS = C:\Documents and Settings\All Users\Documents
         CSIDL_COMMON_APPDATA = C:\Documents and Settings\All Users\Application Data
CSIDL_COMMON_DESKTOPDIRECTORY = C:\Documents and Settings\All Users\デスクトップ
          CSIDL_PROGRAM_FILES = C:\Program Files
   CSIDL_PROGRAM_FILES_COMMON = C:\Program Files\Common Files
                CSIDL_WINDOWS = C:\WINDOWS
                 CSIDL_SYSTEM = C:\WINDOWS\system32
                       %TEMP% = C:\Documents and Settings\[アカウント名]\Local Settings\Temp

                 <Windows 2000 Professional>

                CSIDL_PROFILE = C:\Documents and Settings\[アカウント名]
               CSIDL_PERSONAL = C:\Documents and Settings\[アカウント名]\My Documents
             CSIDL_MYPICTURES = C:\Documents and Settings\[アカウント名]\My Documents\My Pictures
       CSIDL_DESKTOPDIRECTORY = C:\Documents and Settings\[アカウント名]\fXNgbv
              CSIDL_TEMPLATES = C:\Documents and Settings\[アカウント名]\Templates
                CSIDL_APPDATA = C:\Documents and Settings\[アカウント名]\Application Data
          CSIDL_LOCAL_APPDATA = C:\Documents and Settings\[アカウント名]\Local Settings\Application Data
         CSIDL_INTERNET_CACHE = C:\Documents and Settings\[アカウント名]\Local Settings\Temporary Internet Files
       CSIDL_COMMON_DOCUMENTS = C:\Documents and Settings\All Users\Documents
         CSIDL_COMMON_APPDATA = C:\Documents and Settings\All Users\Application Data
CSIDL_COMMON_DESKTOPDIRECTORY = C:\Documents and Settings\All Users\fXNgbv
          CSIDL_PROGRAM_FILES = C:\Program Files
   CSIDL_PROGRAM_FILES_COMMON = C:\Program Files\Common Files
                CSIDL_WINDOWS = C:\WINNT
                 CSIDL_SYSTEM = C:\WINNT\system32
                       %TEMP% = C:\Documents and Settings\[アカウント名]\Local Settings\Temp
klab_gijutsu2 at 12:14│Comments(2)TrackBack(1)win 

トラックバックURL

この記事へのトラックバック

1. 設定ファイルはどこへ?(バーチャルストアについて)|Vista Tips  [ ホームページの素 ]   2008年11月16日 15:36
Vista に今まで通りにソフトをインストールすると設定ファイルが見つからないってことありませんか?

この記事へのコメント

1. Posted by すがり   2007年10月15日 17:32
>「2000〜XP 世代のシステム既定のパスを直接指定しない」
2000でもNT3.51とかそのあたりからアップデートしてきた場合は違うパスの場合もありませんでしたっけ?
アップデート版の2000は対象外ってことですか。
2. Posted by tanabe   2007年10月15日 20:12
>すがりさん
ご指摘の状況で、クリーンインストールの場合とは具体的なパスが異なっていたかどうかはちょっと記憶にないのですが、いずれにせよ「そのパスをプログラムから決め打ちで指定すべきではない」という点は共通とお考え下さい。コメントをありがとうございました。

この記事にコメントする

名前:
URL:
  情報を記憶: 評価: 顔   
 
 
 
Blog内検索
Archives
このブログについて
DSASとは、KLab が構築し運用しているコンテンツサービス用のLinuxベースのインフラです。現在5ヶ所のデータセンタにて構築し、運用していますが、我々はDSASをより使いやすく、より安全に、そしてより省力で運用できることを目指して、日々改良に勤しんでいます。
このブログでは、そんな DSAS で使っている技術の紹介や、実験してみた結果の報告、トラブルに巻き込まれた時の経験談など、広く深く、色々な話題を織りまぜて紹介していきたいと思います。
最新コメント