2007/01/01 月曜日
あけましておめでとうございます。おそらく今年はバージョン5の公開によってActiveBasicの大きな節目となる年になることでしょう。そう言いつつ新年最初の話はVisual C++の話です(ぇ。
Visual C++ 2005から、その動的リンク版 (DLL)のランタイムは、Windows XPから搭載されたSide-by-Sideを活用するものとなり、単純にランタイムDLLをEXEと同梱すれば良いというわけにはいかなくなりました。そう思われている節が強いように私は感じていますが、実はそうでもありません。
Side-by-Sideは、複数のバージョンのアセンブリ(DLLなどの集合)を共存・選択する仕組みです。1つのアセンブリは複数のファイルからなっていても構いません。例えば、VC++ 2005のランタイムのアセンブリは「Microsoft.VC80.CRT」という名前ですが、これはmsvcr80.dll, msvcp80.dll, msvcm80.dllの3つからなっています。
Side-by-Sideでは、アセンブリを共有アセンブリとプライベートアセンブリの2種類に分類しています。共有アセンブリは%WINDIR%\WinSxS以下に置かれシステム全体で共有されるもの、プライベートアセンブリはアプリケーションの存在するフォルダの下に置かれ、そのアプリケーションだけが使うものとなっています。
共有アセンブリはシステムにインストールするものという雰囲気ですが、プライベートアセンブリはインストーラを必要とせず単にファイルをコピーするだけで実行できるようにできています。つまり、これを使えば、VC++ 2005でもランタイムDLLをEXEに同梱できるのです。
まず、次のような内容のファイルを作成し、EXEと同じフォルダに「Microsoft.VC80.CRT.manifest」(assembly/assemblyIdentityのname属性に拡張子manifestを付けたもの)という名前で保存します。ちなみに、このMicrosoft.VC80.CRTのバージョンはSP1のものです。SP1を当てていない場合は適宜正しいバージョンを記してください。またx64/IA-64の場合は適宜processorArchitecture属性を書き換えてください(試していませんが)。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
type="win32"
name="Microsoft.VC80.CRT"
version="8.0.50727.762"
processorArchitecture="x86"/>
<file name="msvcr80.dll"/>
<file name="msvcp80.dll"/>
</assembly>
assembly/fileのname属性で、このアセンブリに含まれるファイルを指定します。共有アセンブリのMicrosoft.VC80.CRTは3つのファイルからなっていましたが、こちらは実際EXEが参照している(実行に必要な)ものだけを記述すれば十分です(つまりこの例の場合EXEはmsvcr80.dllとmsvcp80.dllのみを必要とするということです)。
それが済んだら、今作ったマニフェストに記載したファイル(ここではmsvcr80.dllとmsvcp80.dll)を、そのマニフェストがあるフォルダへコピーします。これで準備は完了です。
勿論、EXEにもマニフェストが必要です(/MD付けてコンパイルすれば特に不要と指定しない限り自動的に作られるはずです)。内容は特に書き換える必要はありません。当然EXE側のアセンブリは、リソースとしてEXEに埋め込んで構わないはずです。さあ実行してみてください。心配ならランタイムをインストールしていない(そしてWindows XP以上が稼動してる)他のPCへ持っていって実行してみてください。
結局、マニフェストさえ用意すれば、従来どおりランタイムDLLを同梱して配布できるということです。ここまでで言い忘れましたが、Microsoft.VC80.CRT.manifestをアセンブリマニフェスト、EXE側のほうをアプリケーションマニフェストと呼びます。アセンブリを提供する側と利用する側という立場の違いです。
ところで、プライベートアセンブリは、EXEのあるフォルダのサブフォルダに置くこともできます。EXEのあるフォルダに、アセンブリ名(先の例ではMicrosoft.VC80.CRT)と同名のフォルダを作り、そこへアセンブリマニフェストと本体のファイル(msvcr80.dllら)を移動します。ただし、こうするとWindows XPより以前のバージョンではside-by-sideがなく従来の手順でDLLを探すため、おそらくDLLが見つからないというエラーになるでしょう。そのため個人的にはEXEと同じフォルダにアセンブリマニフェストと本体を置くほうが便利だと思います。
本日の記事は、殆どGoogleで見付けたGotDotNet掲示板の内容の焼き直しです。
私は、その記述を基に自作のDLLをプライベートアセンブリ化できないかと試行錯誤していました。結果としてはできましたが、その話は次回にします。
12月 22nd, 2007 at 23:58:07
マニフェストをこの記事のように書いてDLLとともに実行ファイルのところにおいてもRedistributableRuntimePackageがインストールされていない環境では構成が違うというエラーが出ます。ちなみにアプリケーションマニフェストはexe埋め込みです。DLLのバージョン等はビルド環境と同一のものです。
12月 23rd, 2007 at 22:09:44
すみません。現在、試せる環境がないのですが、とりあえずMSDNライブラリンの関係するところを2ヶ所、示しておきます。
http://msdn2.microsoft.com/ja-jp/library/ms235532(VS.80).aspx
http://msdn2.microsoft.com/en-us/library/aa375193.aspx