Windows XP では標準で "luna" と呼ばれるビジュアルスタイルが適用されています。
"luna" 以外にも様々なビジュアルスタイルが開発/配布されており、自由にデスクトップの概観を変更することができます。
ダイアログを使ったアプリケーションを作成するとよく分かるのですが、
Visual Studio 6.0 などで開発したダイアログベースのアプリケーションには、そのままでは、
たとえ XP 上でコンパイル・リンクしたとしても、ビジュアルスタイルが適用されません。
Visual Studio .NET で開発する場合には、プロジェクト作成時にオプションを選択しておけば、
ビジュアルスタイルに対応するために必要なコードがプロジェクトに追加されるため、何もしなくても
プログラムをビジュアルスタイルに対応させることができます。
プロジェクトの変更なしに簡単に対応する方法と、
Visual Studio 6.0 (VC++ のみ) のプロジェクトを変更することで対応する方法の 2 つを紹介します。
なお、この方法は Microsoft のサイトやネット上でもあちこちで紹介されていますので、詳細はそちらをご覧ください。
.NET で MFC アプリケーション プロジェクトを作成する際、
[MFC アプリケーション ウィザード] の設定値の中に [高度な機能] - [コモン コントロール マニフェスト]
というチェック項目があります。デフォルトではこのチェックは付いているのですが、このチェックを外してしまい、
マニフェスト無しにしてしまうと、たとえ .NET で作成したプログラムであっても
XP のビジュアルスタイルが適用されないアプリケーションが作成されます。
以下は、ダイアログベースのアプリケーションで、このチェックを付けたまま作成したプロジェクトと、
チェックを外して作成したプロジェクトの、それぞれをビルドしたプログラムを実行したものです。
[コモン コントロール マニフェスト] のチェックを付けたプロジェクト(マニフェスト有り)
[コモン コントロール マニフェスト] のチェックを外したプロジェクト(マニフェスト無し)
プロジェクトを作成し、そのままビルドしたためデフォルトの [OK]、[キャンセル] ボタンしか配置されておらず
分かりにくいかもしれませんが、ボタンの形状をよくみると、たしかにチェックを外したプロジェクト(マニフェスト無し)には
XP のビジュアルスタイルが適用されていません。
チェック項目 [コモン コントロール マニフェスト] についてのヘルプをみると、
となっています。XP のビジュアルスタイルを適用するためには、 プログラムに新しいコモンコントロール dll (バージョン 6) を使用させる必要があり、 そして、そのためには、マニフェストファイルを使ってプログラムが使用する dll のバージョンを指定しなければならない、 ということのようです。
Windows XP で導入された新しいコモンコントロール dll - comctl32.dll (バージョン 6) について、
Microsoft が公開している別のドキュメントをみてみます。
Windows XP ビジュアル スタイルの使用 - 日本語版最終更新日 2001 年 8 月 20 日 より引用
(この文書は暫定版であり、将来変更される可能性があります)
Windows XP オペレーティング システムで実行中のすべてのアプリケーションには、非クライアント領域があります。この領域には、 ウィンドウ枠と非クライアント スクロールバーが含まれます。既定では、ビジュアル スタイルは非クライアント領域に適用されます。 つまり、非クライアント領域の外観は、現在インストールされているビジュアル スタイルによって指定されます。 クライアント領域の一般的なコントロールにビジュアル スタイルを適用するには、ComCtl32.dll バージョン 6 以降を使用する必要があります。旧バージョンとは異なり、ComCtl32.dll のバージョン 6 は再配布することができません。 ダイナミック リンク ライブラリ (DLL) のバージョン 6 を使用するには、バージョン 6 が組み込まれているオペレーティング システムを使用する必要があります。Windows XP には、バージョン 5 とバージョン 6 の両方が付属しています。ComCtl32.dll バージョン 6 には、ユーザー コントロールとコモン コントロールの両方が含まれています。既定では、アプリケーションは、User32.dll で定義されたユーザー コントロールと、ComCtl32.dll バージョン 5 で定義されたコモン コントロールを使用します。
アプリケーションでビジュアル スタイルを使用する場合、ComCtl32.dll バージョン 6 が使用可能であれば使用することを示すアプリケーション マニフェストを追加する必要があります。バージョン 6 には、複数の新しいコントロールおよび従来のコントロール用の新しいオプションが含まれていますが、最大の変更は、 ウィンドウのコントロールの外観の変更をサポートすることです。
どうやらビジュアルスタイル適用の鍵は、プログラムが使用する comctl32.dll のバージョンが握っているようです。
プログラムから使用される共有 dll はシステムフォルダなどに格納されており、
ほとんどのプログラムがこれを共有して使っています。
従来は、同一共有 dll の異なるバージョンが同時にシステム内に存在することはできませんでした。
そのため、インストーラなどによって共有 dll が上書きされると、上書きされた dll に依存する
すべてのプログラムが影響を受けます。場合によると、それまで動作していたプログラムが
部分的または全体的に正しく動作できなくなってしまうこともありました。
これを DLL Hell (DLL 地獄) と呼び、できるだけ多くのバージョン/環境の Windows で動作する
アプリケーションを開発する際には、開発者の頭痛の種の 1 つでもありました。
Windows XP では Side-by-Side アセンブリ共有 という機能によって、この DLL Hell から逃れることができるようになりました。
この機能を使えば、同じ共有 dll の異なるバージョンが同時にシステム内に存在することができ、
また、プログラムも必要とする共有 dll のバージョンを指定して使用することができます。
新しいコモンコントロール dll
も Side-by-Side アセンブリ共有を使って利用できるように Windows XP に最初から組み込まれています。
(Side-by-Side アセンブリ共有機能は Windows 2000 からでも使用できたようですが、
同じ共有 dll の異なるバージョンがシステム内に存在できるようになったのは XP からのようです)。
私の使っている XP マシンの中を探してみると、以下の 3 つのバージョンの comctl32.dll が見つかりました。
※アセンブリバージョンは \WINDOWS\WinSxS\Manifests 下にある、対応するマニフェストファイルに記述されています。
また、フォルダ名やマニフェストファイル名にもアセンブリバージョンを考慮した名前が付けられています。
Side-by-Side アセンブリ共有を利用しないプログラムは従来通り (1) の comctl32.dll (バージョン 5) を使います。 一方、アセンブリ共有を利用する場合、(2) または (3) の comctl32.dll (バージョン 6) が使われることになります。
では、実際に マニフェストファイル で作成した 2 つのプログラムで、
それぞれ違うバージョンの comctl32.dll が呼びだされているかを確認してみます。
確認方法は簡単で、Visual Studio の IDE 環境でプログラムを起動すると、ロードされた dll の名前が [出力]
ウィンドウに表示されるので、この内容を確認します。
以下は、マニフェスト有りと無しのそれぞれのプログラムを実行した出力ウィンドウの表示です。
マニフェスト有り
マニフェスト無し
Side-by-Side アセンブリ共有 でみたように、
マニフェスト有りでは、新しいコモンコントロール dll (バージョン 6) のアセンブリバージョン 6.0.10.0
がロードされているのが分かります。
また、マニフェスト無しでは、システムフォルダ下のコモンコントロール dll (バージョン 5)
がロードされているのが分かります。
新しいコモンコントロール dll (バージョン 6) のアセンブリバージョン 6.0.10.0
もロードされていますが、少なくとも先にバージョン 5 がロードされ使用されているようです。
マニフェストファイルを使えば、自分の好きなコモンコントロールのバージョンをロードできることが分かりました。
では、その中身を見てみます。
以下は、.NET のウィザードでマニフェスト有りとして作成したプロジェクトに自動的に追加されていたマニフェストファイルの中身です。
<?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="Microsoft.Windows.ManifestTest" 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> </assembly>
最初の assemblyIdentity は、このアプリケーションのアセンブリ情報です。
description には、このアプリケーションの説明を記述します。日本語で記述する場合、
作成したマニフェストファイルを保存するときに、XML 定義の encoding に指定した文字コードで保存するよう
気をつけてください。
dependency には、このアプリケーションが必要とする共有アセンブリを列挙します。
各アセンブリの情報は、assemblyIdentity にそれぞれ記述します。
上のマニフェストファイルにはアセンブリが 1 つだけ列挙されており、
コモンコントロールのアセンブリバージョン "6.0.0.0" が指定されています。
ロードされる dll を確認する でみたように、
実際に、このマニフェストを使ったプログラムでロードされた dll のアセンブリバージョン は
"6.0.0.0" ではなく "6.0.10.0" でした。
assemblyIdentity の version にあるように、
メジャー、マイナーが同じものは以前のバージョンと後方互換性があるとみなされる(要はバグフィックス
版では、ビルド、リビジョンのみ変更する)ということなので、
同じメジャー、マイナーを持つアセンブリのうち、最新のものがロードされているようです。
長々とお待たせしてしまいました。では、既存のプログラムを
プロジェクトの変更なしに XP のビジュアルスタイルに対応させる方法をみてみます。
この方法はほんとに簡単で、マニフェストファイルの内容
のうち、version、name、
description を自分の好みに変更して、
"実行形式名.manifest" という名前で実行形式と同じフォルダに保存するだけです。
例えば、実行形式名が "hoge.exe" であれば、対応するマニフェストファイル名は "hoge.exe.manifest"
となります。このとき、ファイル名に ".exe" も含まれることに注意してください。"hoge.manifest"
ではなく、必ず "hoge.exe.manifest" とする必要があります。
以下は、"hoge.exe" に対応するマニフェストファイルの一例です。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity version="1.0.369.4989" processorArchitecture="X86" name="foo.bar.hoge" 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> </assembly>
これを、文字コードを UTF-8 で "hoge.exe.manifest" というファイル名で保存し、 "hoge.exe" と
同じフォルダに配置すれば、XP のビジュアルスタイルが "hoge.exe" に適用されます。
なお、もし "hoge.exe" がコモンコントロールを使わず、自前でユーザインタフェースを作成している場合は、
当然、ビジュアルスタイルは適用されませんのでご留意ください。
以下はマニフェストファイルにより XP ビジュアルスタイルが適用された例です。
適用前 | マニフェスト適用後 | |
※注意
マニフェストファイルを実行形式に後付けする場合、
作成したマニフェストファイルでプログラムが起動することを必ず確認しておく必要があります。
マニフェストファイルに記述した内容が間違っていると、プログラム起動時に、
のようなエラーが出てしまい、実行することができなくなってしまいます。 マニフェストファイルを削除または正しく修正すれば、きちんと起動できるようになるのですが、 万一、間違ったマニフェストファイルを付けたままプログラムを配布したりしてしまうと、 何も知らないユーザさんにはわけがわかりませんので、お気をつけください。
マニフェストを利用するのは同じですが、マニフェストをファイルとしてではなく、
プログラムのリソースとして定義します。ただし、この方法には、
Platform SDK, Feburary 2001 Edition (Windows XP Beta 2 対象)
以降の SDK が必要になります。以下の説明では Visual Studio 6.0 と Platform SDK July 2002 Edtion を使用しました。
適当なプロジェクトとマニフェストファイルを作成します。
Win32 SDK ベースのプロジェクト
と リソース用のマニフェストファイル
を用意しましたので、展開してご使用ください。
※リソース用のマニフェストファイルは
ビジュアルスタイルに対応する(プロジェクト変更なし) で使用したものとは、
description とファイル名が違うだけで、そのほかはまったく同じものです。
同じファイル名のままでリソースとして使用しても問題のないことは確認していますが、
ネットのあちこちで紹介されているソースが、ファイル名の ".exe" を除いた形式にしてありましたので、
お行儀があるのかしらんと思い、あわせました。
プロジェクトとマニフェストファイル "ManifestTest.manifest" を展開したら、
///////////////////////////////////////////////////////////////////////////// // // RT_MANIFEST // CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "res\\ManifestTest.manifest"追加する位置は ICON リソースの直後あたりがいいと思います。 Visual Studio 的にいえば、このファイルは手作業で編集してはいけないファイルなので、 直接編集がいやだという方は、Visual Studio でプロジェクトを開き、[ワークスペース] から [ResourceView] を選び、 [ManifestTest リソース] を右クリックして、ポップアップメニューを表示させ、インポートを選んでください。 [リソースのインポート] ダイアログが開くので、 [ファイルの種類] を [すべてのファイル] にし、"res" 下の "ManifestTest.manifest" を選択し、[インポート] を クリックします。[カスタムリソースのタイプ] ダイアログが表示されるので、RT_MANIFEST と入力して、 [OK] をクリックしてください。挿入されたリソースのプロパティを開き、リソース ID を "CREATEPROCESS_MANIFEST_RESOURCE_ID" としてください。このとき、ダブルクォーテーションで囲み文字列として ID を定義することで、resouce.h にも追加されず、再定義エラーも出さずに、コンパイルすることができます。
あとは、プロジェクトをコンパイルして、実行してみてください。
XP のビジュアルスタイルが適用されているのが分かると思います。
実行例
※補足
マニフェストファイル で作成したマニフェスト有りのプログラムでは、
.NET のウィザードによって作成されたコードに InitCommonControls() の呼び出しが追加されています。
BOOL CManifestTestApp::InitInstance() { // アプリケーション マニフェストが visual スタイルを有効にするために、 // ComCtl32.dll バージョン 6 以降の使用を指定する場合は、 // Windows XP に InitCommonControls() が必要です。さもなければ、ウィンドウ作成はすべて失敗します。 InitCommonControls();
コメントには 「InitCommonControls() が必要です。さもなければ、ウィンドウ作成はすべて失敗します。」 と恐ろしいことが書かれています。しかし、たしかに InitCommonControls() は、コモンコントロール dll が ロードされた状態にあることを保証してくれますが、呼び出さないからといって、 当該 dll がロードされないわけではありません。 通常のダイアログベースのプロジェクトでは、comctl32.dll が ロードされる設定になっているはずなので、特に呼び出さなくても大丈夫だと思います。 けれど、念のため、呼び出しておくのが安心への近道かもしれません。