'Combine 32- and 64bit DLLs in one program

I need to load different hardware drivers that are provided in .dll files. The problem appears to be that the drivers for one device are given in a 64bit dll, the other device (rather old) apparently relies on drivers given in a 32bit dll. I want to control them through a program written in C# which will be run through a python wrapper.

Obviously I cant run both devices from one program directly but I need a way to address them depending on each other - for example: device 1 waiting for device 2 to finish some job. Is there any way to circumvent this issue or will I need to run them in two separate programs and manage actions depending on each other through the python wrapper?



Solution 1:[1]

On 64-bit Windows 64-bit processes can not use 32-bit DLLs and 32-bit processes can't use 64-bit DLLs. Microsoft has documented this:

On 64-bit Windows, a 64-bit process cannot load a 32-bit dynamic-link library (DLL). Additionally, a 32-bit process cannot load a 64-bit DLL.

You would need a 32-bit process that communicates with the 32-bit DLL and a 64-bit process to communicate with the 64-bit DLL. Microsoft says this:

However, 64-bit Windows supports remote procedure calls (RPC) between 64-bit and 32-bit processes (both on the same computer and across computers).

The problem then becomes one of how to have Python communicate with these processes. Some form of Interprocess Communication (IPC) would be needed. Microsoft created a technology decades ago that can do just that - COM interfaces using Out of Process COM servers (out-of-proc).

The general idea is:

  • Create a 64-bit out-of-proc COM server that wraps (and exposes) the needed methods and data of the 64-bit DLL.
  • Create a 32-bit out-of-proc COM server that wraps (and exposes) the needed methods and data of the 32-bit DLL.
  • Write either 32-bit or 64-bit client code that instantiates the COM objects and calls their interfaces. Python can be used as a COM client via win32com

COM provides an IPC mechanism under the hood that allows a 64-bit client to access a 64-bit out-of-proc COM server and for a 64-bit client to access a 32-bit out-of-proc server. You can even have 32-bit clients communicate with 32-bit and 64-bit out-of-proc COM servers as well.

I haven't done low level Windows work using the newer MS languages. When I had to do what you needed in your question the two main technologies that made it easy to write COM servers and COM interfaces were:

I had a preference for ATL since it didn't require the MFC library and had less overhead.

Solution 2:[2]

Yes you will need 2 separate processes, running from different executables. Only 32-bit executables can load 32-bit DLLs. (See @MichaelPetch's answer for useful suggestions for details of how to get one to communicate with the other with a remote-procedure-call mechanism that can simulate calling 32-bit functions from 64-bit code or vice versa.)

x86 32-bit and x86-64 are two separate architectures that just happen to be both executable by the same CPU, in different modes. Their machine-code is very similar but not compatible, and many other things are different too, including object file format, and ABI details like pointer width being 8 vs. 4 bytes.


Having a 64-bit process start a thread that does a jmp far to a 32-bit code segment is technically possible (because the GDT has 32 and 64-bit code segment entries), but that's insane and very poorly supported by everything including the DLL dynamic loading / symbol resolving code. (Also including the kernel, so this is not even safe: an interrupt or system call could return to 32-bit code in 64-bit mode if you tried this, because the kernel knows your thread / process started in 64-bit mode.)

You won't be able to convince a compiler to generate 32-bit code and link it with 64-bit code, even if you were using C on an OS where it was "safe" to do this. A higher-level managed language makes it even more unusable even if it was "safe" with hand-written asm.

I mention this just in case you're curious about what it would technically require to make this happen, not because anyone should ever do this.

But if it was safe, in theory you could write (by hand in asm) wrapper functions for every function in the 32-bit DLL that changes to 32-bit mode before calling the function.

Apparently this was a thing early 32-bit Windows; you could call 16-bit DLLs from 32-bit code via a "thunk" wrapper that the OS supplied. But there's no similar support for 32-bit DLLs from 64-bit code or vice versa.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2