A Worked Example of a COM Bridge for Calling a 64-bit DLL from a 32-bit App

· · COM, Windows Development, 32bit, 64bit

Wanting to call a 64-bit DLL from a 32-bit app is a fairly typical requirement on Windows. Especially when you want to keep existing assets in place and use only the 64-bit side’s functionality, a COM bridge architecture tends to be the practical answer.

Table of Contents

  1. The Scenario
  2. The Solution
  3. Processing Flow (Sequence Diagram)
  4. Sample Code (Conceptual)
  5. Complete Sample Code
  6. References

1. The Scenario

This is the case where you want to keep an existing 32-bit app as is, but use processing that lives in a 64-bit DLL. The problem is that a 32-bit process cannot load a 64-bit DLL. This is an OS-level constraint - it is not something you can work around with clever tricks.

The typical situation looks like this.

  • The existing 32-bit app is a large asset and cannot be migrated any time soon
  • The 64-bit DLL has new functionality, or its dependencies are 64-bit only
  • You want to call it from the 32-bit side “with types”

With this combination, the in-process route is closed off from the start.

2. The Solution

The basic solution is to separate via out-of-proc COM (an EXE server). The 64-bit DLL is called from a 64-bit COM server (EXE), and the 32-bit app uses it through COM.

The flow is as follows.

  1. Build a 64-bit COM LocalServer (EXE) that calls the 64-bit DLL internally
  2. Share the COM interface (IDL/TypeLib) to expose the types
  3. The 32-bit app calls COM “with types” (communicating via proxy/marshaling)

There are caveats, though.

  • 32-bit and 64-bit registrations are separate (including WOW6432Node)
  • Custom structs require marshaling design
  • IPC overhead exists, so be careful with high-frequency calls

In short, the proven approach is to “move the 64-bit processing into a separate process and bridge it with COM.”

3. Processing Flow (Sequence Diagram)

The following shows the flow when the 32-bit app invokes processing in the 64-bit DLL.

Handled by the registered COM marshaling infrastructure64bit DLL64bit COM Server(EXE)COM Stub(64bit side)RPC/IPC(inter-process communication)COM Proxy(32bit side)32bit client app64bit DLL64bit COM Server(EXE)COM Stub(64bit side)RPC/IPC(inter-process communication)COM Proxy(32bit side)32bit client appMarshal the parametersUnmarshal the parametersMarshal the return valueUnmarshal the return valueICalcService.Add(1, 2)Serialized dataTransferred across the process boundaryAdd(1, 2)Native function callResult: 3Result: 3Serialized resultTransferred across the process boundaryResult: 3

Key points:

  • The 32-bit app can make type-safe calls through the ICalcService interface
  • The COM runtime crosses the process boundary using the registered proxy/stub DLL, the TypeLib marshaler, the standard marshaler, and so on
  • Because of the inter-process communication overhead, batching work is preferable to many fine-grained calls

4. Sample Code (Conceptual)

The following is a conceptual sketch. In practice you also need registration, TypeLib generation, and so on.

// Shared interface (IDL equivalent)
[ComVisible(true)]
[Guid("7A4B5B23-0A2F-4D2B-9D4D-8A2A92B8B001")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ICalcService
{
    int Add(int a, int b);
}

// 64bit COM LocalServer (EXE side)
[ComVisible(true)]
[Guid("1C9B6F4D-1E9A-4E61-9A4F-6A0F1D2D9A11")]
[ClassInterface(ClassInterfaceType.None)]
public class CalcService : ICalcService
{
    public int Add(int a, int b)
    {
        // Call the 64bit DLL here
        return a + b;
    }
}

// 32bit app side (client)
Type t = Type.GetTypeFromProgID("KomuraSoft.CalcService");
var calc = (ICalcService)Activator.CreateInstance(t);
int result = calc.Add(1, 2);

With this shape, the 32-bit side can work “with types.” COM uses proxies/stubs internally and makes the call over IPC for you.

5. Complete Sample Code

A working implementation of the concept above is published on GitHub.

Call64bitDLLFrom32bitProc - GitHub

The repository contains the following:

  • Call64bitDLLFrom32bitProc/ - 64bit COM LocalServer (EXE)
  • X64DLL/ - 64bit DLL (the actual processing)
  • X86App/ - 32bit client (WinForms)
  • scripts/ - COM server registration/unregistration scripts

If you build and register it following the steps in the README, you can see a 32-bit process actually calling a 64-bit DLL.

6. References

  • Component Object Model (COM) overview https://learn.microsoft.com/en-us/windows/win32/com/component-object-model–com–portal
  • COM LocalServer32 registration https://learn.microsoft.com/en-us/windows/win32/com/localserver32
  • COM interface basics https://learn.microsoft.com/en-us/windows/win32/com/the-component-object-model
  • COM Interop (use from .NET) https://learn.microsoft.com/en-us/dotnet/standard/native-interop/cominterop

Recent articles sharing the same tags. Deepen your understanding with closely related topics.

These topic pages place the article in a broader service and decision context.

This article connects naturally to the following service pages.

Author Profile

Profile page for the article author.

Go Komura

Representative of KomuraSoft LLC

Focused on Windows software development, technical consulting, and investigations into failures that are difficult to reproduce.

Back to the Blog