我有一个32位dll(无源代码),需要从64位C#应用程序访问。我已阅读this文章,并研究了here中的相应代码。我也阅读了this帖子。 我不确定我要问的是正确的问题,所以请帮助我。
有3个项目:dotnetclient
,x86Library
和x86x64
。 x86x64
的{{1}}加载x86LibraryProxy.cpp
并调用x86library.dll
函数:
GetTemperature
STDMETHODIMP Cx86LibraryProxy::GetTemperature(ULONG sensorId, FLOAT* temperature)
{
*temperature = -1;
typedef float (__cdecl *PGETTEMPERATURE)(int);
PGETTEMPERATURE pFunc;
TCHAR buf[256];
HMODULE hLib = LoadLibrary(L"x86library.dll");
if (hLib != NULL)
{
pFunc = (PGETTEMPERATURE)GetProcAddress(hLib, "GetTemperature");
if (pFunc != NULL)
调用dotnetclient
函数并打印结果:
GetTemperature
如果我将所有项目都构建为x86或x64,则所有这些都适用。我得到的温度结果为static void Main(string[] args)
{
float temperature = 0;
uint sensorId = 2;
var svc = new x86x64Lib.x86LibraryProxy();
temperature = svc.GetTemperature(sensorId);
Console.WriteLine($"temperature of {sensorId} is {temperature}, press any key to exit...");
。但是,整个想法是使用32位20
。这意味着x86x64Lib.dll
应该被构建为x64,dotnetclient
和x86Library
被构建为x86,对吗?如果这样做,我将得到x86x64
。
我应该将-1
和x86Library
构建为x86,将x86x64
构建为x64吗?如果这样做,我得到dotnetclient
会是什么问题?
澄清 似乎提供的示例仅在客户端和服务器均以32位或64位构建时才有效。但是,当客户端以64位构建而服务器以32位构建时,则不是。有人可以看看吗?
答案 0 :(得分:1)
恕我直言,最简单的方法是使用COM+ (Component Services),它是Windows的一部分,已有大约20年的历史(以前的版本以前称为MTS ...)。它为您提供代理基础结构,包括工具,UI和所需的一切。 但这意味着您必须使用COM,因此对此有所了解是很高兴的。
首先创建一个x86 COM DLL。我为此使用了ATL。创建一个ATL项目,向其中添加一个ATL简单对象,将该方法添加到IDL和实现中。
.idl(请注意[out,retval]属性,因此温度被视为包括.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";
用于测试目的的方法实现:
STDMETHODIMP GetTemperature(ULONG sensorId, FLOAT* temperature)
{
*temperature = sizeof(void*); // should be 4 in x86 :-)
return S_OK;
}
现在,您必须在32位注册表中注册该组件(实际上,如果您运行的是不带管理员权限的Visual Studio,那么在编译时它将抱怨该组件无法注册,这是预期的),因此在64位操作系统上,您必须使用管理员权限运行类似以下内容(请注意SysWow64):
c:\Windows\SysWOW64\regsvr32 x86Library.dll
完成此操作后,运行“组件服务”,浏览“计算机/我的电脑/ COM +应用程序”,右键单击并创建一个新应用程序。选择一个名称和一个“服务器应用程序”。这意味着您的组件将托管在COM +代理过程中。
完成此操作后,浏览“组件”,右键单击并创建一个新组件。确保选择“ 32位注册表”。您应该看到对象的ProgId。在我创建ATL项目的情况下,我将“ MyObject”添加为Progid,但否则可以将其命名为“ x86Library.MyObject”或“ x86LibraryLib.MyObject” ...如果不存在,则说明您犯了一些错误较早。
就是这样。现在,此.NET程序将始终能够运行,编译为AnyCpu或x86或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
}
}
您可以使用Component Services UI配置代理(激活,关闭等)。它还具有一个API,因此您可以创建COM+ apps programmatically。
答案 1 :(得分:0)
您将无法直接从64位代码中调用32位代码(或相反),这简直不会发生。
还有其他选择,例如创建32位COM主机程序,然后将调用转发到DLL。再加上您使用DCOM标准编组,以便您的64位进程可以连接到32位主机。
但是,如果要重新编译32位DLL,几乎可以肯定是最好的选择。