作成日: 2003/03/26

自作のプログラムを Windows XP のビジュアルスタイルに対応させる

概要

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 のビジュアルスタイルが適用されていません。

チェック項目 [コモン コントロール マニフェスト] についてのヘルプをみると、

Microsoft Windows XP に同梱されている新しいコモン コントロール DLL を使用するためのアプリケーション マニフェストを生成します。

既存のアプリケーションで使用されている以前のバージョンのコモン コントロールが、 Version 6 のコモン コントロール DLL によって自動的に更新されることはありません。 Version 6 のコモン コントロール DLL を使用するには、 アプリケーションが新しい DLL を読み込めるようにするためのアプリケーション マニフェストを作成する必要があります。 Version 6 のコモン コントロール DLL は、Windows XP のテーマもサポートしています。

また、アプリケーション マニフェストによって、アプリケーションに必要なその他の DLL やその他のバージョンも指定できます。 Windows XP では、指定した DLL だけがアプリケーションと共に読み込まれることが保証されています。

となっています。XP のビジュアルスタイルを適用するためには、 プログラムに新しいコモンコントロール dll (バージョン 6) を使用させる必要があり、 そして、そのためには、マニフェストファイルを使ってプログラムが使用する dll のバージョンを指定しなければならない、 ということのようです。

新しいコモンコントロール dll

Windows XP で導入された新しいコモンコントロール dll - comctl32.dll (バージョン 6) について、 Microsoft が公開している別のドキュメントをみてみます。

Windows XP ビジュアル スタイルの使用 - 日本語版最終更新日 2001 年 8 月 20 日 より引用
(この文書は暫定版であり、将来変更される可能性があります)

ComCtl32.dll バージョン 6

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 のバージョンが握っているようです。

Side-by-Side アセンブリ共有

プログラムから使用される共有 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 下にある、対応するマニフェストファイルに記述されています。 また、フォルダ名やマニフェストファイル名にもアセンブリバージョンを考慮した名前が付けられています。

(1) \WINDOWS\system32\comctl32.dll
ファイルバージョン: 5.82.2800.1106
製品バージョン: 6.00.2800.1106

(2) \WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.10.0_x-ww_f7fb5805\comctl32.dll
ファイルバージョン: 6.0.2800.1106
製品バージョン: 6.00.2800.1106
アセンブリバージョン: 6.0.10.0

(3) \WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.0.0_x-ww_1382d70a\comctl32.dll
ファイルバージョン: 6.0.2600.0
製品バージョン: 6.0.2600.0
アセンブリバージョン: 6.0.0.0

Side-by-Side アセンブリ共有を利用しないプログラムは従来通り (1) の comctl32.dll (バージョン 5) を使います。 一方、アセンブリ共有を利用する場合、(2) または (3) の comctl32.dll (バージョン 6) が使われることになります。

ロードされる dll を確認する

では、実際に マニフェストファイル で作成した 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 は、このアプリケーションのアセンブリ情報です。

version
アプリケーションのアセンブリバージョンを記述します。 MSDN によると、左からメジャー、マイナー、ビルド、リビジョン の順に "mmmmm.nnnnn.ooooo.ppppp" のようにピリオドで区切って、 4 つのパートで構成しなければなりません。また、各パートの値は 0 から 65535 の範囲に収まっている必要があります。 なお、共有 dll ではメジャー、マイナーが同じものは、ビルド、リビジョンのみが違う以前のバージョンと 後方互換性があるとみなされます。
processorArchitecture
アプリケーションがターゲットとするプラットフォームのプロセッサタイプを指定します。 32-bit Windows では "x86"、64-bit Windows では "ia64" としなければなりません。
name
アプリケーションのアセンブリ名を記述します。 MSDN によると、アプリケーション独自の名前を付けることになっており、"Organization.Division.Name" のような 組織名.部局名.名前 のような形式が推奨されています(java で推奨されていたパッケージ名の形式にどこか似ています)。 .NET のウィザードで作成されたマニフェストファイルは "Microsoft.Windows.プロジェクト名" の形となっていますが、 特にこの形式に準じる必要はないようです。
type
アプリケーションのタイプを指定します。"win32" にしておかなければなりません。

description には、このアプリケーションの説明を記述します。日本語で記述する場合、 作成したマニフェストファイルを保存するときに、XML 定義の encoding に指定した文字コードで保存するよう 気をつけてください。

dependency には、このアプリケーションが必要とする共有アセンブリを列挙します。 各アセンブリの情報は、assemblyIdentity にそれぞれ記述します。

publicKeyToken
MSDN によると、 アセンブリがサインされる公開鍵の SHA-1 ハッシュを表す最後の 8 バイトを 16進で表記したものです。 このキーは Platform SDK で提供されるツール pktextract.exe を使い、公開鍵の証明書ファイルから抽出し、 また、鍵は、アセンブリ・カタログに署名するために使うものと同じ鍵である必要があり、 鍵長は、最低 2048 ビット以上必要です。
署名に関係しているようですが、私には意味不明。共有アセンブリを利用するだけなら、\WINDOWS\WinSxS\Manifests 下にある、使用したいアセンブリのマニフェストファイルから publicKeyToken の値をコピペするだけで済みます。
language
アセンブリの言語属性を、DHTML の言語コード指定形式で指定します。 なお、言語に関係なく使用できるアセンブリの場合、省略できるようです。
type, name, version, processorArchitecture
assemblyIdentity を参照ください。

上のマニフェストファイルにはアセンブリが 1 つだけ列挙されており、 コモンコントロールのアセンブリバージョン "6.0.0.0" が指定されています。
ロードされる dll を確認する でみたように、 実際に、このマニフェストを使ったプログラムでロードされた dll のアセンブリバージョン は "6.0.0.0" ではなく "6.0.10.0" でした。 assemblyIdentity の version にあるように、 メジャー、マイナーが同じものは以前のバージョンと後方互換性があるとみなされる(要はバグフィックス 版では、ビルド、リビジョンのみ変更する)ということなので、 同じメジャー、マイナーを持つアセンブリのうち、最新のものがロードされているようです。

ビジュアルスタイルに対応する(プロジェクト変更なし)

長々とお待たせしてしまいました。では、既存のプログラムを プロジェクトの変更なしに XP のビジュアルスタイルに対応させる方法をみてみます。
この方法はほんとに簡単で、マニフェストファイルの内容 のうち、versionnamedescription を自分の好みに変更して、 "実行形式名.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" を展開したら、

  1. "ManifestTest.manifest" をプロジェクトフォルダの "res" フォルダ下にコピーします。
  2. プロジェクトフォルダ下の "ManifestTest.rc" を開き、以下の行を追加します。
    /////////////////////////////////////////////////////////////////////////////
    //
    // 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 が ロードされる設定になっているはずなので、特に呼び出さなくても大丈夫だと思います。 けれど、念のため、呼び出しておくのが安心への近道かもしれません。

サンプルソース
ManifestTest.FromFile.zip (4.47 KB)
ビジュアルスタイルに対応する(プロジェクト変更なし) で、マニフェストによってビジュアルスタイルを適用する際にサンプルとして使用したプロジェクトです。 また、ビジュアルスタイルに対応する(プロジェクト変更あり) で、変更前のプロジェクトとしても使用しました。
ManifestTest.FromRes.zip (5.01 KB)
ビジュアルスタイルに対応する(プロジェクト変更あり) でリソースにマニフェストを追加した後のプロジェクトです。
ManifestTest.exe.manifest.zip (511 バイト)
ビジュアルスタイルに対応する(プロジェクト変更なし) で使用したマニフェストファイルです。
ManifestTest.manifest.zip (501 バイト)
ビジュアルスタイルに対応する(プロジェクト変更あり) で使用したマニフェストファイルです。