👏
64bitアプリから32bit DLLを呼ぶ(COMサロゲート)
やりたいこと
32bitで作られたC++のCOM DLLがあり、これを64bitのWPFから呼びたい。
サンプル
前提
DLLはCOMを想定しているので、以下のようなものとする。
- COMとして公開されている
-
regsvr32で登録できる - CLSIDを持っている
サンプルとして足し算ができるだけのDLLをATL(Active Template Library)で作成する。



SimpleCalculator.cpp
STDMETHODIMP CSimpleCalculator::Add(LONG a, LONG b, LONG* result)
{
if (result == nullptr)
return E_POINTER;
*result = a + b;
return S_OK;
}
呼び出し側はこう。

MainWindow.xaml.cs
Guid clsid = new Guid("480B42D8-3934-47FF-B20D-5FC280FEC649");
Type? t = Type.GetTypeFromCLSID(clsid);
if (t == null)
{
// CLSID未登録
return;
}
dynamic obj = Activator.CreateInstance(t)!;
int result = obj.Add(2, 3);
dynamicなのでIDispatch経由。型安全ではないけどサンプルなのでこれで。
やること
COMサロゲートを使う。
まずDLLをCOMとして登録する。管理者権限で以下を実行。
regsvr32 SimpleCom32.dll
Visual Studioを管理者権限で起動してビルドすれば自動で登録される(vcxprojの
RegisterOutputがtrueなので)。
次に、レジストリに以下を追加。(いずれもHKLM)
CLSID側(32bit側)
HKLM\SOFTWARE\Classes\WOW6432Node\CLSID\{CLSID}
AppID = {CLSID}
AppID側
HKLM\SOFTWARE\Classes\AppID\{CLSID}
DllSurrogate = ""
空文字にするのがポイント。これでデフォルトのサロゲート(dllhost.exe)が使われる。
結果

DllSurrogate登録前

DllSurrogate登録後
タスクマネージャーではdllhost.exeが存在し、ちゃんと32bitのサロゲートプロセス経由で動いてることが確認できる。
何が起きているか
WPF (64bit)
↓ CoCreateInstance
COM ランタイム
↓ AppID + DllSurrogate を参照
dllhost.exe(32bit)
↓ DLL をロード
SimpleCom32.dll (32bit)
別プロセスに逃がしてるだけ。COMのマーシャリングが間に入るので、呼び出し側からは普通のCOMオブジェクトに見える。
補足
COM DLL限定(CoCreateInstanceで生成できてCLSIDがあるやつ)。
普通のC++ DLL(LoadLibraryで使うやつ)やMFC DLLは同一プロセス前提なので、この方法は使えない。
ATLプロジェクトを作るとProxy/Stub DLL用のプロジェクトが自動で生成される。
COMで別プロセスと通信するときにデータの受け渡し(マーシャリング)を仲介するためのDLLらしいので今回は不要。
まとめ
- 64bitから32bit DLLはそのままでは扱えない
- COM DLLならCOMサロゲートで呼べる
- レジストリに
AppIDとDllSurrogateを追加するだけ -
IDispatchベースならProxy/Stub DLLも不要 - 普通のDLLやMFC DLLには使えない
taskkill /IM dllhost.exe /F
Discussion