読者です 読者をやめる 読者になる 読者になる

Visual C++ 9.0のランタイム問題

Visual C++ 9.0を使って共有DLL(/MD)でビルドしたコードを配布しようとすると(C++/CLIを利用すると必然的にこの状況になる)、CRTのDLLを配布する羽目になるんですが、これには、3つの方法があることになっています。

vcredist_x86.exeを利用する

この方法は、前もってランタイムをユーザーにインストールしてもらうという、ある意味では、もっともユーザーに負担をかける方法です。

Microsoft Visual C++ 2008 Redistributable Package (x86)

上記のURLからダウンロードしたセットアッププログラムを実行するだけなので、まぁ、最悪ともいえない方法ではあるのですが、このセットアップには困ったバグがあって、インストール時に、C:\の直下にファイルをぶちまけたあげくに、それらのファイルを消さずにインストールを完了してしまいます。何かのタイミングにC:\を除いて、その惨状に気づくという・・・。普通の人には、もはや、どのファイルが消しても良いファイルなのかわからなくなる状況です。

MSM(マージモジュール)を利用する

インストーラをMSIで作成するのはもはや時代の流れとしては当然なので、MSMを利用してランタイムをインストールするのは正攻法の中の正攻法といえるでしょう。通常、Visual Studioをインストールしていれば、

C:\Program Files\Common Files\Merge Modules

あるいは(x64版のOS)、

C:\Program Files (x86)\Common Files\Merge Modules

にたくさんインストールされているマージモジュールのうち、

Microsoft_VC90_CRT_x86.msm
policy_9_0_Microsoft_VC90_CRT_x86.msm

を利用するだけです。非常に簡単です。

・・・という感じに進めば話が簡単でいいんですが、実際には、WOW64下で動作するWindows Installer(つまり、32-bitの普通のアプリケーションのインストーラ)でこれらのマージモジュールを利用しても、ランタイムがインストールされないみたいなんです。少なくとも、WinSxSディレクトリの下には該当フォルダが作成されない!
うーん、何か簡単なことでも見落としているんでしょうか。*1

プライベートDLLとしてインストール

最後の手段は、自分のアプリケーションのディレクトリにランタイムをインストールしてしまうという方法です。なるべくなら避けたい方法なんですが、上記の2つの方法がなんともかんともという現状では、この方法を選ばざるを得ません。
しかしながら、XP、2003、Vista、2008といったOSでは、自分のアプリのディレクトリにファイルをぶちまけるということはやってはいけません。というか、VS2005以降のコンパイラを使っているのであれば、やっても無駄です。EXEファイルに暗黙のうちに埋め込まれたアプリケーションマニフェストがあなたの行く手を阻みます。いや、阻むというか、アプリケーションマニフェストによって、彼らは特定のバージョンのDLLとしかリンクしないようになっているんです。

このアプリケーションマニフェストっていうのは、平たくいうと、自分が動作を確認した特定のバージョンのDLL以外は使いたくないということを表明(manifest)するための手段です。
この仕組みが使われている例を挙げると、たとえば、Windows XPでは、互換性の低下を代償に見た目をそれ以前のOSと変えて今風にするバージョンのcomctl32.dllと、Windows 2000と代わり映えのしないバージョンのcomctl32.dllの2つが提供されており、アプリケーションはマニフェストを使って、同じ名前のDLLのどちらを使うかを選択できるようになりました。
XP以降のOSでは、このアプリケーションマニフェストを使って、様々なDLLのバージョン違いを共存させることが、OSレベルで可能になりました。もはや、古典的なPATHが通っているDLLをロードするなんてレベルではなくなっています。この仕組みは、正しくは、Side by Side (略してSxS)と呼ばれています。

前置きが長くなりましたが、具体的にどうやるかというと、exeが存在するフォルダにMicrosoft.VC90.CRTのようなフォルダをおいて、その中にランタイムを置くような形になります。

AppDir
  hogehoge.exe
  Microsoft.VC90.CRT
    Microsoft.VC90.CRT.manifest
    msvcm90.dll
    msvcp90.dll
    msvcr90.dll

ちなみにここで使っているランタイムのファイル群は、Visual Studioがインストールされていれば、

C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\redist\x86

の下にあるはずです。x64用は、amd64の下。

あとは、今更、そんな人はいないと思いますが、どう血迷っても、ランタイムをそのままsystem32の下にコピーするような暴挙には出ないでください。物事が悪い方向に行くことはあっても、改善する方向に動くことはないでしょう。

*1:その後の調査により、どうも、WiXの問題であることが露見。VS2008で作った簡易インストーラだったら動作する。WiX3.0ならうまくいくんだろうか・・・・。