从64位.NET程序使用32位COM服务器

时间:2010-11-17 12:30:57

标签: .net com interop 32bit-64bit

我在使用COM Interop时遇到了一些问题,情况如下:

32位COM Exe服务器(用C ++编程)提供了一个类,其中包含一些处理第三方硬件的成员函数(此硬件也将COM Exe Server绑定到32位,因为制造商没有支持64位)。

我想在64位.NET(C#)应用程序中使用32位COM Exe Server ...首先,我尝试在Visual Studio 2010中添加对Exe Server的引用,并创建了一个Interop- DLL。这个Interop-DLL为我提供了必要的功能,其中一个被声明为:

int Initialize(ref string callingApplicationPath);

C ++中的原始声明如下所示:

LONG Class::Initialize(BSTR* callingApplicationPath)

......在IDL中也是如此:

[id(1)] LONG Initialize([in] BSTR* callingApplicationPath);

但是,当我想通过Interop-DLL从C#调用此函数时,它会抛出BadImageFormatException。看起来Interop-DLL是一个32位DLL(也许有可能生成64位DLL?)。

我的下一次尝试是使用以下代码实例化Exe Server:

Type type = Type.GetTypeFromProgID("OurCompany.Class");
Object o = Activator.CreateInstance(type);
Object[] args = { Marshal.StringToBSTR(str) };
Object result = type.InvokeMember("Initialize", BindingFlags.InvokeMethod, null, o, args);

另一方面,这段代码会抛出一个TargetInvocationException(更具体地说:0x80020005(DISP_E_TYPEMISMATCH))。不幸的是我无法找到我必须从C#传递给函数的类型...我在Marshal类中尝试了所有的StringToXXX函数但似乎没有任何工作:/我想我在这里缺少一些简单的东西,但我看不出来。

非常感谢任何帮助!

最好的问候

基督教

3 个答案:

答案 0 :(得分:1)

默认情况下,.NET字符串由COM Interop编译到C ++中的LPTSTR。因此,您必须使用MarshalAs属性将任何其他类型的非托管字符串(包括BSTR)显式封送到.NET字符串中。 尝试

 int Initialize([MarshalAs(UnmanagedType.BStr)] ref string callingApplicationPath);

答案 1 :(得分:1)

IDL声明

[id(1)] LONG Initialize([in] BSTR* str);    

毫无意义。当您将BSTR作为in参数传递时,只需将其“按值”传递:

[id(1)] LONG Initialize([in] BSTR str);

然后你不需要在C#代码中做任何特殊的事情 - 只需在那里传递string并且编组将自动完成。

当然,您还必须更改方法实现签名。

答案 2 :(得分:0)

由于.net使用的公共语言运行库,只有少数情况下您必须使用托管代码区分32位和64位。然而,这仅适用于.net envoirement。如果您尝试访问非托管资源,则位格式很重要,因为所有地址(导出的接口)都是静态的,而不是为64位编译。

你仍然可以使用一个非常简单的构造来完成你的任务;
创建一个32位的.net包装器并通过wcf将它连接到你的64位应用程序。我建议为你的com / unmanaged服务器创建一个混合模式的c ++包装器,并将一个基于wcf的层写在“pure”clr(c#,vb.net等)中作为你的主应用程序的连接点。