誰もがはまる「DLL 地獄」("DLL Hell")。
Windows XP SP1 以降の Window OS では、それを回避するために「Registration-Free COM」(Reg-Free COM)という仕組みが用意されており、COM(ActiveX) DLL/OCX を Side-by-Side 実行させることができます。
具体的には、マニフェストファイルを添えて配置することにより、レジストリ登録することなく、アプリケーションごとに異なるバージョンの依存コンポーネントを参照できます。
以下にその手順を説明します。
※DLL/OCX によっては対応できないケースがあるかもしれませんが、多くの場合はこの方法で構成できると思います。
例となるケース
対象となる依存コンポーネントの識別子(任意)
CodeOne.Windows.Controls
配布したい依存コンポーネント
CodeOne.Windows.Controls.Common.dll
CodeOne.Windows.Controls.TreeGrid.ocx
依存コンポーネントのバージョン
1.0.0.0
組み込むアプリケーション
SampleApplication.exe
依存コンポーネントの構成
1. 開発環境に依存ファイルを含めた対象コンポーネントをレジストリ登録しておく。
2. アプリケーションディレクトリの直下に [CodeOne.Windows.Controls] フォルダを作成する。
3. マニフェストファイル『CodeOne.Windows.Controls.manifest』を BOM 付 UTF-8 で作成し、[CodeOne.Windows.Controls] フォルダに配置する。
<?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="CodeOne.Windows.Controls"
type="win32"
/>
<!-- ここに依存コンポーネントの file 要素(複数繰り返し)を記述 -->
</assembly>
4. Visual Studio(2005~)を [管理者として実行] し、「Windows フォーム」プロジェクトを新規作成する。
5. 対象の DLL/OCX を参照設定に追加し、[分離] プロパティを True に設定する。
6. 発行フォルダにローカルディレクトリ(publish など)を指定して [発行] する。
7. 発行フォルダに作成された exe.manifest の 要素(複数繰り返し)のうち、依存コンポーネント分(プロジェクト自身の config を除く)をすべてコピーし、『CodeOne.Windows.Controls.manifest』の の上に貼り付ける。
8. [CodeOne.Windows.Controls] フォルダに配布する DLL, OCX を配置する。
アプリケーションへの組み込み
1. 上で構成した依存コンポーネントをアプリケーションディレクトリにコピーする。
2. アプリケーションディレクトリに『SampleApplication.exe.manifest』を BOM 付 UTF-8 で作成し、コンポーネントの依存を定義する。
<?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="CodeOne.SampleApplication"
type="win32"
/>
<description>サンプルアプリケーションです。</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="CodeOne.Windows.Controls"
version="1.0.0.0"
processorArchitecture="x86"
/>
</dependentAssembly>
</dependency>
<!-- 必要に応じて dependency を追加 -->
</assembly>
3. アプリケーションディレクトリに次の VB6 ランタイムファイルを配置する。
msvbvm60.dll
vb6jp.dll
※VB6 ランタイムは XP 以降の Windows OS に組み込まれている。msvbvm60.dll は SySWOW64 に配置されているはずだが、たとえば VB6 sp6 で開発した場合、sp6 の msvbvm60.dll でないと日本語が文字化けする可能性があるため、念のためアプリケーションディレクトリに個別配置しておく。
※ADO 等のデータアクセスコンポーネント(旧 MDAC)は、Windows DAC として Vista 以降の Windows OS に組み込まれている。
4. ファイル構成は以下のようになる。
├ SampleApplication.exe
├ SampleApplication.exe.manifest
├ msvbvm60.dll
├ vb6jp.dll
└ [CodeOne.Windows.Controls]
├ CodeOne.Windows.Controls.manifest
├ CodeOne.Windows.Controls.Common.dll
└ CodeOne.Windows.Controls.TreeGrid.ocx
配置
Windows インストーラの場合
・プロジェクトファイル出力を削除して、EXE と manifest を手動で追加する。
・COM の [Register] プロパティはすべて vsifrNone に設定する。
動作の補足
レジストリ登録のない状態でアプリケーションを実行してマニフェストが読み込まれると、レジストリ登録された状態と同様に、ほかのディレクトリからも参照できるようになる。
レジストリ登録された後にマニフェストが読み込まれた場合、ほかのディレクトリから参照されるのはレジストリ登録された方になる。
exe.manifest がなくても依存コンポーネントのマニフェストが自動検出されることもあるようだが、検出されないコンポーネントもあるので配置した方がよい。
注意点/トラブルシューティング
-
関連する複数の DLL/OCX の manifest を出力する際、重複する参照クラスがあってエラーになることがある(ActiveReportsViewer の arpro2 など)。
その場合は一方の DLL/OCX を別のプロジェクトに分けて出力し、マージしたうえで重複クラスをコメントアウトする。 -
同一 progid, tlbid で clsid の異なる comClass 要素が複数作成された場合、そのまま実行するとエラーになるので、先頭以外(2 つ目以降の重複要素)をコメントアウトして動作を確認する。
-
アプリケーション起動時にエラー「このアプリケーションのサイド バイ サイド構成が正しくないため、アプリケーションを開始できませんでした。」が発生する場合、 単位でコメントアウトして起動を確認すると原因を絞り込むことができるが、一度起動に成功すると、コメントアウトを戻しても同じ場所ではエラーが発生しなくなる可能性があるため、注意が必要。
-
.exe.manifest と依存コンポーネントの .manifest で version が合わないと実行時にエラー「プロシージャの呼び出し、または引数が不正です。」が発生する。
-
COM Interop(COM 相互運用)DLLの場合、RegAsm またはマニフェストの DLL 埋め込みが必要となる。
-
「このアプリケーションの構成が正しくないため、アプリケーションを開始できませんでした。」
⇒ Windows XP で動かす場合、sp1 以上が必須となる。 -
GrapeCity の表計算コンポーネント SPREAD の『SPR32X30.ocx』(3.0.0.31)で実行時に落ちてしまうことがある。
(イベントログの発生モジュールは「ntdll.dll」)
⇒ 3.0.0.52 にアップデートする。