COMが役立つケーススタディ-32bitアプリから64bit DLLを呼び出したいとき
COMが役立つケーススタディ-32bitアプリから64bit DLLを呼び出したいとき
目次
1. 想定状況
32bitの既存アプリを保ったまま、64bit DLLの処理を使いたいというケースです。
しかし、32bitプロセスは64bit DLLを読み込めません。これはOSレベルでの制約です。
よくある状況は次のようなものです。
- 既存の32bitアプリは資産として大きく、すぐには移行できない
- 64bit DLL側に新機能がある、または依存ライブラリが64bitのみ
- 32bit側から「型付きで」呼び出したい
このとき、「同一プロセス内で呼び出す」ことは不可能です。
2. 解決方法
解決の基本は、Out-of-proc COM(EXEサーバー)で分離することです。
64bit DLLは64bitのCOMサーバー(EXE)から呼び出し、32bitアプリはCOM経由で使います。
流れは次の通りです。
- 64bitのCOM LocalServer(EXE)を用意し、内部で64bit DLLを呼び出す
- COMインターフェース(IDL/TypeLib)を共有し、型を公開する
- 32bitアプリはCOMを「型付き」で呼び出す(Proxy/Marshalでやり取り)
注意点としては以下があります。
- 32bit/64bitの登録は別(WOW6432Node含む)
- 独自構造体はマーシャリング設計が必要
- IPCのオーバーヘッドがあるため、高頻度呼び出しは注意
つまり、「64bitの処理を別プロセスに逃がして、COMで橋渡しする」のが王道です。
3. 処理の流れ(シーケンス図)
以下は、32bitアプリが64bit DLLの処理を呼び出すときの流れです。
sequenceDiagram
participant App as 32bit クライアントアプリ
box rgba(100,100,255,0.1) COMが自動で処理(開発者は意識不要)
participant Proxy as COM Proxy
(32bit側)
participant RPC as RPC/IPC
(プロセス間通信)
participant Stub as COM Stub
(64bit側)
end
participant Server as 64bit COM Server
(EXE)
participant DLL as 64bit DLL
App->>Proxy: ICalcService.Add(1, 2)
rect rgba(100,100,255,0.1)
Note over Proxy: パラメータをマーシャリング
Proxy->>RPC: シリアライズされたデータ
RPC->>Stub: プロセス境界を越えて転送
Note over Stub: パラメータをアンマーシャリング
end
Stub->>Server: Add(1, 2)
Server->>DLL: ネイティブ関数呼び出し
DLL-->>Server: 結果: 3
Server-->>Stub: 結果: 3
rect rgba(100,100,255,0.1)
Note over Stub: 戻り値をマーシャリング
Stub-->>RPC: シリアライズされた結果
RPC-->>Proxy: プロセス境界を越えて転送
Note over Proxy: 戻り値をアンマーシャリング
end
Proxy-->>App: 結果: 3
ポイント:
- 32bitアプリは
ICalcServiceインターフェースを通じて型安全に呼び出せる - COMランタイムが自動的にProxy/Stubを生成・管理
- プロセス間通信のオーバーヘッドがあるため、細かい呼び出しより一括処理が望ましい
4. サンプルコード(イメージ)
以下は概念のイメージです。実際には登録やTypeLibの生成などが必要です。
// 共有インターフェース(IDL相当)
[ComVisible(true)]
[Guid("7A4B5B23-0A2F-4D2B-9D4D-8A2A92B8B001")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ICalcService
{
int Add(int a, int b);
}
// 64bit COM LocalServer(EXE側)
[ComVisible(true)]
[Guid("1C9B6F4D-1E9A-4E61-9A4F-6A0F1D2D9A11")]
[ClassInterface(ClassInterfaceType.None)]
public class CalcService : ICalcService
{
public int Add(int a, int b)
{
// ここで64bit DLLを呼び出す
return a + b;
}
}
// 32bitアプリ側(クライアント)
Type t = Type.GetTypeFromProgID("KomuraSoft.CalcService");
var calc = (ICalcService)Activator.CreateInstance(t);
int result = calc.Add(1, 2);
この形にすると、32bit側は「型付きで」扱えます。
COMが内部でプロキシ/スタブを使い、IPC経由で呼び出してくれます。
5. 完全なサンプルコード
上記の概念を実際に動作する形で実装したサンプルを GitHub で公開しています。
Call64bitDLLFrom32bitProc - GitHub
このリポジトリには以下が含まれています:
- Call64bitDLLFrom32bitProc/ - 64bit COM LocalServer (EXE)
- X64DLL/ - 64bit DLL(実処理)
- X86App/ - 32bit クライアント (WinForms)
- scripts/ - COM サーバー登録・解除スクリプト
README に記載の手順に従ってビルド・登録すれば、実際に 32bit プロセスから 64bit DLL を呼び出す動作を確認できます。
6. 参考資料
- Component Object Model (COM) の概要
https://learn.microsoft.com/en-us/windows/win32/com/component-object-model–com–portal - COM LocalServer32 の登録
https://learn.microsoft.com/en-us/windows/win32/com/localserver32 - COM インターフェースの基本
https://learn.microsoft.com/en-us/windows/win32/com/the-component-object-model - COM Interop(.NETからの利用)
https://learn.microsoft.com/en-us/dotnet/standard/native-interop/cominterop