32bitアプリから64bit DLLを呼ぶCOMブリッジ実例

· · COM, Windows開発, 32bit, 64bit

32bit アプリから 64bit DLL を呼び出したい、という要件は Windows ではかなり典型的です。 特に既存資産を残したまま 64bit 側の機能だけ使いたいとき、COM ブリッジの構成が現実的な解になりやすいです。

目次

  1. 想定状況
  2. 解決方法
  3. 処理の流れ(シーケンス図)
  4. サンプルコード(イメージ)
  5. 完全なサンプルコード
  6. 参考資料

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経由で使います。

流れは次の通りです。

  1. 64bitのCOM LocalServer(EXE)を用意し、内部で64bit DLLを呼び出す
  2. COMインターフェース(IDL/TypeLib)を共有し、型を公開する
  3. 32bitアプリはCOMを「型付き」で呼び出す(Proxy/Marshalでやり取り)

ただし注意点もあります。

  • 32bit/64bitの登録は別(WOW6432Node含む)
  • 独自構造体はマーシャリング設計が必要
  • IPCのオーバーヘッドがあるため、高頻度呼び出しは注意

つまり、「64bitの処理を別プロセスに逃がして、COMで橋渡しする」のが王道です。

3. 処理の流れ(シーケンス図)

以下は、32bitアプリが64bit DLLの処理を呼び出すときの流れです。

登録済みのCOMマーシャリング基盤が処理64bit DLL64bit COM Server(EXE)COM Stub(64bit側)RPC/IPC(プロセス間通信)COM Proxy(32bit側)32bit クライアントアプリ64bit DLL64bit COM Server(EXE)COM Stub(64bit側)RPC/IPC(プロセス間通信)COM Proxy(32bit側)32bit クライアントアプリパラメータをマーシャリングパラメータをアンマーシャリング戻り値をマーシャリング戻り値をアンマーシャリングICalcService.Add(1, 2)シリアライズされたデータプロセス境界を越えて転送Add(1, 2)ネイティブ関数呼び出し結果: 3結果: 3シリアライズされた結果プロセス境界を越えて転送結果: 3

ポイント:

  • 32bitアプリは ICalcService インターフェースを通じて型安全に呼び出せる
  • COMランタイムは、登録済みの Proxy/Stub DLL、TypeLib マーシャラー、標準マーシャラーなどを使ってプロセス境界を越える
  • プロセス間通信のオーバーヘッドがあるため、細かい呼び出しより一括処理が望ましい

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

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

この記事は次のサービスページにつながります。近い入口からご覧ください。

著者プロフィール

記事の著者プロフィールページです。

小村 豪

合同会社小村ソフト 代表

Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る