公開日:2006/10/14
Windows Vistaの情報は、マイクロソフトのWindows Vistaに関するページへどうぞ。
RC1導入情報については、Windows Vista RC1 をインストールしてみましたへどうぞ。
Windows Vista RC2対応情報については、Windows Vista RC2 へ対応状況の調査結果へどうぞ。
Windows Vista (正式版)への対応については、Windows Vista (正式版)へ対応についてへどうぞ。
Windows Vista RC1 をインストールしてみましたから、およそ1ヶ月。Vistaへの対応は、過去のこれまでの新OSへの対応と比べて、とても難しいことになりそうだということがわかり始めてきました。
先日、MSDN会員向けに、Windows Vista RC2が提供され、さっそく導入してみることになりました。今回は、前回書ききれなかった新たな情報と共に、プログラミングスタイルをどのように変化させていかなければならないかについて、触れてみたいと思います。
なお、ここに書かれている情報には、Windows Vista RC2の挙動から得られる憶測が混じっています。一部正確でない情報があるかもしれませんので、情報の利用については、各自の責任でお願いいたします。また、RC2での挙動は、正式版になったときに変化する可能性がありますので、ご注意ください。

こちらが、Windows Vista RC2のデスクトップです。まぁ、RC1のときと、そんなに変わることはありませんが、画面右下のビルド番号が表示されている部分には「ビルド 5744」と表示されています。ちょっとサイドバーが重なって見にくくなっているかもしれませんね。

バージョン情報の詳細を見たい方は、上の画像を参照と言うことで。CCPU(環境情報の表示)による画面です。
バージョンは、6.0.5744 となります。余談ですが、バージョン番号は おなじみのGetVersionEx() APIで取得できます。Edition部分(上で言うところのUltimate)は、Windows Vistaより新しく提供されるAPI GetProductInfo() APIで取得できます。
ここらへんのコアな話は、また後ほど書くことにしましょう。
プログラマの視点から見たとき、Windows Vistaへ対応する上で気をつけなければならないことをまとめてみました。
上から見ていきましょう。
Windows XPまでであっても、制限ユーザーは存在していました。ただ、一般的な使用においては、できることが少なすぎて、敬遠されてきたのが実際です。プログラマ側も、過去のマイクロソフト製のOSが「基本的にリソースにアクセスし放題」であったため、その習慣に甘んじて「管理者権限を持つユーザーが使用することが基本」とするプログラムを作ってきました。
ところで、Unix等の別の系統のOSでは、これとは逆の考え方があります。つまり、常に管理者ユーザーで使っていると、
という危険があるため、基本的には制限ユーザーとして使うのです。ただし、制限ユーザーであっても、特定のコマンドを入力することで一時的に管理者ユーザーになり、必要な作業を行ったら再び制限ユーザーに戻ることができます。
これまで、Windowsはセキュリティ的に弱いというレッテルが貼られてきましたが、マイクロソフトではその原因の解決策として「Unix型の考え方を取り込もう」という考えを持ったようです。このことから、
といった動作が見られるようになっています。
例えば管理者ユーザーが「Program Files」配下にフォルダを作り、そこにファイルを移動する手順を考えてみます。例えば、デスクトップにある newrnsf7 フォルダの中身を、C:\Program Files\Rnsf7 に移動する手順を考えます。
何気ない手順なのですが、これがWindows Vistaにかかると、とんでもないことになります。













長旅おつかれさまでした。こんな感じで、何度も何度も認証が入ることにより、強固なOSを実現しようというのが、Windows Vistaでのやり方です。ちょっと、やり過ぎという感じがしないこともないですが、セキュリティが弱いというレッテルを解消するには、これくらい必要だというのが、マイクロソフトの見解なのでしょう。
っていうか、こんなにOKボタンを押しまくっていると、何も見ずにOKを押すクセがついてしまって、本当に危険な警告が出たときに対応できなくなっちゃうのではないかと心配になります。前に、株取引でも似たようなことがありましたし…。
マイクロソフトとしては、少しでも責任の一端をユーザーになすりつけたい、ってことでしょうか?(あなたがOKを押したからウィルスに感染したんだ!と) でもたしか、アメリカの訴訟だったかな? 説明書に危険性が書かれていなかったから訴訟に負けたケースがあるために、何でもかんでも説明書に書くようになっちゃって、今度は説明書に細かい説明を書きすぎたために、事故が起きたときに「どこに重要なことが書いてあるのかわからない」という理由で訴訟に負けたケースがあったとか。訴訟じゃなくて笑い話だったかもしれませんが。
Unixの場合、必要なときだけsuをして、必要が無くなったらexitするという手段があるのですが、これだと、コマンドを入力する度にsudoをする感じですよね。本当にこれが正しい対処法なのか、疑問が残ります。ってか、su相当のやり方にするわけにはいかなかったんですかね。GUIでは。
ファイル操作だとこんな感じです。対象がレジストリ等設定の場合についても同じで、確認のダイアログが表示されます。
例えばコントロール パネルから、「Windows ファイアウォールによるプログラムの許可」を選ぶとします。さっそく、例のダイアログがあらわれます。


レジストリ エディタ(regedit.exe)を使う場合も、やはり確認のダイアログが開きます。

問題となる動作の対象がユーザーの操作ではなく、プログラムの挙動だった場合はどうなるでしょうか。例えばいじくるつくーるで、こういった制限に触れるようなことになった場合、プログラマが何の対策も取っていないと、何の確認もされずに、いきなりアクセス拒否されます。

そのため、後述するような対策が必要になります。
最後に、ヘルプファイルの形式について。Windows Vistaからは、WinHelpの標準搭載が行われなくなります。マイクロソフトのWebサイトからのダウンロードを可能とするということなので、正確に「使えなくなる」というわけではなくなるものの、ヘルプをスムーズにユーザーに見てもらいたければ、WinHelpは使えないと思った方がよいでしょう。


こんな感じで、頭の痛いことを多数抱えながら、プログラミングを行っていかなければなりません。
ある著名な作家さん曰く、無理して(高い金を出して)(使い勝手の悪くなった)Windows Vistaを購入するよりも、使い慣れたWindows XPをチューニングし続けて使う方が良いのではないかと語っておられました。実際、Windows Vistaは画面表示に無駄な時間を割いていますし、セキュリティ云々といっても、ウィルス対策ソフトがいらなくなるほどではありません。
ユーザーはWindows XPのようなスタイルを望んでいるぞという意志をマイクロソフトに示すことにより、VistaにNoの姿勢をたたきつけ、次期OSからは元に戻させるといったこともできるかもしれません。ただ、セキュリティ的なリスクは必ず存在することを、全てのユーザが認識しなければなりませんが………。
[2006/11/14追記]
このユーザー アカウント 制御(UAC)について、レジストリの編集によりこれを抑止する方法が、Windows XPスマートチューニングに掲載されていました。
要は、HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System にあるDWORD値 EnableLUA を 0 にしてやるとのこと。
色々試してみたところ、デフォルトは1になっていてこれが「有効」を示し、0にすることで「無効」になる。値を削除すると1を意味するものとして扱われる、といった感じです。本日公開した「いじくるつくーる」のアップデートパッチより、いじくるつくーるもUACの無効化に対応しました。
Windows Vistaでも問題なく動作するアプリケーションはどのようになるでしょうか。とりあえず心配しなくて良いのは、
のように、慎ましやかにがんばっていたアプリケーションであると言えます。まぁ、2番目の項目は1番目の項目に含まれるんですけどね。
%APPDATA%は、Win9xやWinNT4では存在しないので、実質的にWin32系の全OS共通で使えるのは、レジストリということになりそうです。
そういうわけで、Windowsフォルダ配下に設定を保存していたり、Program Files配下にiniファイルを作っていたりするアプリケーションは、一斉に使えなくなる恐れがあります。特にゲームなんかでは、Program Files配下にスコアデータを保存しようとする傾向がありますから、注意が必要ですね。
(いちおう、マイクロソフトからは、大昔から「iniは将来的になくなるかもしれないからレジストリに設定を保存してね」と言われてきていますから、これを守っていれば、とりあえず設定保存に関しては大丈夫なアプリケーションができるでしょう)
(ちなみに、このあと色々とアプリケーションの動きを確認したところ、古いアプリケーションは、C:\Users\[ユーザー名]\AppData\Local\VirtualStore\Program Files\[フォルダ名]\[ファイル名].ini (バーチャルストアと呼ばれます)へ自動的にリダイレクトされました)
なお、マイクロソフトのドキュメントによれば、このバーチャルストアの機能は過去のプログラムへの互換性のために準備されたものであり、新たにプログラムを作るプログラマは、この機能に頼ってはならない、としています。
ところで気になったのは、次の2つ。
これが使えなくなると、色々と面倒くさいことになるので。
というわけで、いじくるつくーるのインストールを、WinSFX32M で実行してみました。





続いて、葦葉製作所のVirus Crasherにパッチを当ててみます。




色々心配はしたものの、とりあえず、最終的には目的の操作は果たすことができるようです。
マニフェストリソースを含まない、比較的古いプログラムであれば、Windows Vistaの下位互換機能が比較的有効に機能し、自動的に管理者権限を取得するための行動に出てくれますから、問題なく動作します。
しかし、中途半端にマニフェストを含む比較的新しいプログラムの場合、中途半端に権限情報が書いてあるんだか、なんなんだか、このダイアログが出てきてくれません。
そこで、ここではC/C++ネイティブプログラマ向けに、権限取得の方法を書いておこうと思います。
.NET Framework用のプログラムだと、プロジェクトの設定みたいなところで比較的簡単にできそうなので、ここでは割愛します。
まず、プログラム(exeファイル)がどういった性質のものであるかを、OSに伝えてやる必要があります。このためには、「マニフェスト」と呼ばれるファイルをexeファイルと同じフォルダに設置するか、exeに含めなければなりません。
exeファイルの場合、「(プログラムファイル名.exe).manifest」といった感じのファイル名にします。Rnsf7.exeが対象ならば、Rnsf7.exe.manifestです。
個別ファイルにするのがかっこう悪い場合は、exeに含めます。マニフェストはリンク工程の後にexeに結合してやるのですが、mt.exe を使うか、Visual Studio 2005であれば、プロジェクトの設定として追加します。
方法としては、マニフェストのファイルをプロジェクトフォルダに格納しておき、[プロジェクト] → [プロパティ] → [マニフェストツール] → [入力と出力]の「追加のマニフェストファイル」に $(ProjectDir)マニフェストファイル名 を入れておきます。これで、マニフェストをexeに追加することができます。
で、肝心のマニフェストとは何を書けばよいのでしょうか? そういえば、マニフェストというと、政権公約にも同じ言葉を使いますね。意味は同じだと思いますが、今回は全然関係ありません。
マニフェストは、XML形式で記述します。内容は、次のようにします。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.0"
processorArchitecture="X86"
name="INASOFT.Rnsf.Rnsf7"
type="win32"
/>
<description>アプリケーションの説明</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="X86"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
<ms_asmv3:trustInfo xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3" xmlns="urn:schemas-microsoft-com:asm.v3">
<ms_asmv3:security xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3">
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator" uiAccess="false">
</requestedExecutionLevel>
</requestedPrivileges>
</ms_asmv3:security>
</ms_asmv3:trustInfo>
</assembly>
上半分の青い部分は、従来から存在している、Windows XPのビジュアルスタイル(コモンコントロールのver.6.0)を使用するための宣言です。今回の題材は下半分の赤い部分となります。
こうしておくことで、アイコンの右下に「認証しますよ」マーク(4色の盾)が出てきます。こうすることにより、実行時に権限昇格のための認証が行われ、書き込みに特権が必要なレジストリキーにも、書き込みができるようになります。



「認識できないプログラムが…」とか言われていますけど、利用者には何だかわかっているわけですから、これでいちおう解決を見たと言っても良いでしょう(まぁ、認識できるプログラムにするというのはまた後日、ということで)。これで解決!!!……………と思ったら、甘い………。甘かったのです!!
まぁこれで万事解決する環境もあるでしょう。しかし、うちの開発環境(Windows XP SP2)で試しに実行した見たら、とんでもないことが起きました。
STOP C000021a Unknown Hard Error Unknown Hard Error
こんなイメージ。最悪です。ブルースクリーンです。筆者の顔もブルーです。
こんなの久しぶりに見ました………。どういうこっちゃと思って調べたら、Windows XP SP2のバグなのだそうです。
いちおう修正プログラムは準備しているが、追加のテストが必要かもしれないので、まだ公開できないとのこと。電話で問い合わせると入手できるそうですが、広く公開するプログラムがこれでは、あまり意味がありません。次のService Packを待てみたことが書いてあるし………いったい、どうすりゃいいんだ………。
で、あちこち調べてみたところ、v3 ではなく v2 と記述すると良いらしいとのこと。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.0"
processorArchitecture="X86"
name="INASOFT.Rnsf.Rnsf7"
type="win32"
/>
<description>アプリケーションの説明</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="X86"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
たしかに、こう記述することで、うまくいきました。ただ、v3の意味もv2の意味もよくわからないし、Vista RC2ではこれで動いても、Vista正式版では動かなくなるかもしれないし、ちょっと不安が残ります。
いちおう、requestedExecutionLevelについてもまとめておきます。
ちなみに、コントロール パネル-「管理ツール」-「ローカル セキュリティ ポリシー」-「セキュリティの設定」-「ローカル ポリシー」-「セキュリティ オプション」で、管理者になるための確認ダイアログ(昇格ダイアログ)を表示するかどうかのポリシーの設定があるそうです。ただし、ここをオフにすることは、限られた環境以外で行うことは奨励できないとのこと。まぁ、そうでしょうねぇ。
さて、すっきり!! デフラグについては、特殊な対応が必要です。
というのも、上のマニフェストの対応をしてしまうと、どうも、「シェル入れ替え」機能が働かなくなってしまうらしいのです。
逆に、マニフェストを入れなければ、レジストリへの書き込みを行うことができず、「環境復帰」という大事な仕事ができません。
というわけで、Windows Vistaでは、「シェル入れ替え」による すっきり実行は行うことができないということになりそうです。
最後に、プラットフォーム情報の取得についてです。この情報についても、将来的に変わる可能性があるので、ご注意くださいということで。
最初の方で、Edition部分(BusinessとかUltimateとか)は、Windows Vistaより新しく提供されるAPI GetProductInfo() APIを使うべしと書きました。
…が、Windows Vistaより新しく提供されるAPIを使ってしまうと、Windows XP以下の環境で動作させることができなくなってしまいます。これは、単純にAPIを呼び出さないようにif文で迂回させればよいというわけではなく、そもそも起動しなくなってしまうのです。といわけで、少し特殊な方法を使って、このAPIを呼び出すことになります。
// 関数定義
typedef BOOL (WINAPI *PFUNC_GetProductInfo)(DWORD, DWORD, DWORD, DWORD, PDWORD);
PFUNC_GetProductInfo pGetProductInfo = NULL;
DWORD dwReturnedProductType = 0;
// GetProcAddressにより、Kernel32.dll内のGetProductInfoのアドレスを直接取得
pGetProductInfo = (PFUNC_GetProductInfo)::GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "GetProductInfo");
if (pGetProductInfo) {
// GetProductInfoの呼出し
// 引数は、とりあえずVista or Server "Longhorn"(開発中)のv6.0で固定打ち
pGetProductInfo(6, 0, 0, 0, &dwReturnedProductType);
switch(dwReturnedProductType) {
case 0x00000006: //PRODUCT_BUSINESS
_putts(_T("Windows Vista Business"));
break;
case 0x00000010: //PRODUCT_BUSINESS_N
_putts(_T("[PRODUCT_BUSINESS_N]"));
break;
case 0x00000012: //PRODUCT_CLUSTER_SERVER
_putts(_T("[PRODUCT_CLUSTER_SERVER]"));
break;
case 0x00000008: //PRODUCT_DATACENTER_SERVER
_putts(_T("Windows Server \"Longhorn\" Datacenter Edition (Full installation)"));
break;
case 0x0000000C: //PRODUCT_DATACENTER_SERVER_CORE
_putts(_T("Windows Server \"Longhorn\" Datacenter Edition (Server Core installation)"));
break;
case 0x00000004: //PRODUCT_ENTERPRISE
_putts(_T("Windows Vista Enterprise"));
break;
case 0x0000000A: //PRODUCT_ENTERPRISE_SERVER
_putts(_T("Windows Server \"Longhorn\" Enterprise Edition (Full installation)"));
break;
case 0x0000000E: //PRODUCT_ENTERPRISE_SERVER_CORE
_putts(_T("Windows Server \"Longhorn\" Enterprise Edition (Server Core installation)"));
break;
case 0x0000000F: //PRODUCT_ENTERPRISE_SERVER_IA64
_putts(_T("Windows Server \"Longhorn\" Datacenter Enterprise Edition for Itanium-based Systems"));
break;
case 0x00000002: //PRODUCT_HOME_BASIC
_putts(_T("Windows Vista Home Basic"));
break;
case 0x00000005: //PRODUCT_HOME_BASIC_N
_putts(_T("[PRODUCT_HOME_BASIC_N]"));
break;
case 0x00000003: //PRODUCT_HOME_PREMIUM
_putts(_T("Windows Vista Home Premium"));
break;
case 0x00000013: //PRODUCT_HOME_SERVER
_putts(_T("[PRODUCT_HOME_SERVER]"));
break;
case 0x00000018: //PRODUCT_SERVER_FOR_SMALLBUSINESS
_putts(_T("[PRODUCT_SERVER_FOR_SMALLBUSINESS]"));
break;
case 0x00000009: //PRODUCT_SMALLBUSINESS_SERVER
_putts(_T("[PRODUCT_SMALLBUSINESS_SERVER]"));
break;
case 0x00000019: //PRODUCT_SMALLBUSINESS_SERVER_PREMIUM
_putts(_T("[PRODUCT_SMALLBUSINESS_SERVER_PREMIUM]"));
break;
case 0x00000007: //PRODUCT_STANDARD_SERVER
_putts(_T("Windows Server \"Longhorn\" (Full installation)"));
break;
case 0x0000000D: //PRODUCT_STANDARD_SERVER_CORE
_putts(_T("Windows Server \"Longhorn\" (Server Core installation)"));
break;
case 0x0000000B: //PRODUCT_STARTER
_putts(_T("[PRODUCT_STARTER]"));
break;
case 0x00000014: //PRODUCT_STORAGE_EXPRESS_SERVER
_putts(_T("[PRODUCT_STORAGE_EXPRESS_SERVER]"));
break;
case 0x00000015: //PRODUCT_STORAGE_STANDARD_SERVER
_putts(_T("[PRODUCT_STORAGE_STANDARD_SERVER]"));
break;
case 0x00000016: //PRODUCT_STORAGE_WORKGROUP_SERVER
_putts(_T("[PRODUCT_STORAGE_WORKGROUP_SERVER]"));
break;
case 0x00000001: //PRODUCT_ULTIMATE
_putts(_T("Windows Vista Ultimate"));
break;
case 0x00000011: //PRODUCT_WEB_SERVER
_putts(_T("[PRODUCT_WEB_SERVER]"));
break;
}
}
windows.hやstdio.hやtchar.hのインクルードを忘れずに。