开发者

Use 32bit COM Server from a 64bit .NET Program

开发者 https://www.devze.com 2023-01-26 01:41 出处:网络
I\'m having some trouble with COM Interop, the situation is as follows: A 32-Bit COM Exe Server (that was programmed in C++) offers a class with some member functions that deal with 3rd party hardwar

I'm having some trouble with COM Interop, the situation is as follows:

A 32-Bit COM Exe Server (that was programmed in C++) offers a class with some member functions that deal with 3rd party hardware (This hardware also ties the COM Exe Server to 32-Bit, since the manufacturer doesn't support 64-Bit).

I want to use the 32-Bit COM Exe Server in a 64-Bit .NET (C#) Application... At first I tried to add a reference to the Exe Server in Visual Studio 2010 and it created an Interop-DLL. This Interop-DLL provided me with the necessary functions, one of them being declared as:

int Initialize(ref string callingApplicationPath);

The original declaration in C++ looks like this:

LONG Class::Initialize(BSTR* callingApplicationPath)

...and like this in IDL:

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

However, when I want to call this function from C# via the Interop-DLL, it throws a BadImageFormatException. Looks like the Interop-DLL is a 32-Bit DLL (Maybe there's a possibility to generate a 64-Bit-DLL?).

My next attempt was to instantiate the Exe Server with this code:

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);

This code, on the other hand, throws a TargetInvocationException (More specifically: 0x80020005 (DISP_E_TYPEMISMATC开发者_如何学运维H)) at my head. Unfortunately I was unable to find out what type I have to pass in to the function from C#... I tried all the StringToXXX-functions in the Marshal-class but nothing seems to work :/ I guess I'm missing something simple here, but I don't see what.

Any help is greatly appreciated!

Best Regards

Christian


The IDL declaration

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

makes no sense. When you pass a BSTR as an in parameter just pass it "by value":

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

then you will not need to do anything special in C# code - just pass string there and marshalling will be done automatically.

Of course you'll have to change the method implementation signature as well.


By default, .NET strings are marshalled by COM Interop to LPTSTR in C++. Thus you have to explicitly marshal any other type of unmanaged string (including BSTR) to and from a .NET string using the MarshalAs attribute.
Try

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


Due to the common language runtime used by .net there are only a few cases where you have to distinguish between 32 and 64 bit using managed code. However this is only true for the .net envoirement. If you try to access unmanaged resources the bit format matters, since all the adresses (exported interface) are quite static and not compiled for 64 bit.

Still you could uses a quite simple constuct to achive your task;
Create a 32 bit .net wrapper and conenct it via wcf to your 64 bit application. I'd suggest creating a mixed mode c++ wrapper to your com/unmanaged server and placing a wcf based layer written in "pure" clr (c#, vb.net, etc) as the conenction point to your main application.

0

精彩评论

暂无评论...
验证码 换一张
取 消