Calling function from 64bit app from a 32bit dll

混江龙づ霸主 提交于 2019-12-08 01:31:29

IMHO, the easiest way to do this is to use COM+ (Component Services) which is part of Windows for like 20 years or so (previous versions used to be called MTS...). It provides the surrogate infrastructure for you with tools, UI, and everything you need. But that means you'll have to use COM, so it's good to know a bit of COM for this.

First create an x86 COM DLL. I've used ATL for that. Created an ATL project, added an ATL simple object to it, added the method to the IDL and implementation.

.idl (note the [out, retval] attributes so the temperature is considered a return value for higher level languages including .NET):

import "oaidl.idl";
import "ocidl.idl";

[
  object,
  uuid(f9988875-6bf1-4f3f-9ad4-64fa220a5c42),
  dual,
  nonextensible,
  pointer_default(unique)
]
interface IMyObject : IDispatch
{
  HRESULT GetTemperature(ULONG sensorId, [out, retval] FLOAT* temperature);
};
[
  uuid(2de2557f-9bc2-42ef-8c58-63ba77834d0f),
  version(1.0),
]
library x86LibraryLib
{
  importlib("stdole2.tlb");
  [
    uuid(b20dcea2-9b8f-426d-8d96-760276fbaca9)
  ]
  coclass MyObject
  {
    [default] interface IMyObject;
  };
};

import "shobjidl.idl";

Method implementation for testing purposes:

STDMETHODIMP GetTemperature(ULONG sensorId, FLOAT* temperature)
{
  *temperature = sizeof(void*); // should be 4 in x86 :-)
  return S_OK;
}

Now, you must register this component in the 32-bit registry (in fact, if you're running Visual Studio w/o admin rights, it will complain at compile time that the component cannot be registered, that's expected), so on a 64-bit OS, you must run something like this (note SysWow64) with admin rights:

c:\Windows\SysWOW64\regsvr32 x86Library.dll

Once you've done that, run "Component Services", browse "Computers/My Computer/COM+ Applications", right click and create a New Application. Choose a name and a "Server application". It means your component will be hosted in COM+ surrogate process.

Once you've done that, browse "Components", right click and create a New Component. Make sure you select "32-bit registry". You should see your object's ProgId. In my case when I created my ATL project I added "MyObject" as a Progid, but otherwise it could be named something like "x86Library.MyObject" or "x86LibraryLib.MyObject"... If it's not there, than you made some mistake earlier.

That's it. Now, this .NET program will always be able to run, compiled as AnyCpu or x86 or x64:

class Program
{
    static void Main(string[] args)
    {
        var type = Type.GetTypeFromProgID("MyObject"); // the same progid
        dynamic o = Activator.CreateInstance(type);
        Console.WriteLine(o.GetTemperature(1234)); // always displays 4
    }
}

You can use Component Services UI to configure your surrogate (activation, shutdown, etc.). It also has an API so you can create COM+ apps programmatically.

You are not going to be able to directly call 32-bit code from 64-bit code (or the other way around), it simply is not going to happen.

There are alternatives, such as creating a 32-bit COM host program that then forwards calls to the DLL. Coupled with that you use DCOM standard marshalling so your 64-bit process can connect to the 32-bit host.

But if recompiling the 32-bit DLL is at all an option that is almost certainly your best option.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!