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

发布于 2024-10-03 03:01:55 字数 1250 浏览 0 评论 0原文

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

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

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

int Initialize(ref string callingApplicationPath);

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

LONG Class::Initialize(BSTR* callingApplicationPath)

...在 IDL 中如下所示:

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

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

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

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

另一方面,此代码在我的脑海中抛出 TargetInitationException (更具体地说:0x80020005 (DISP_E_TYPEMISMATCH))。不幸的是,我无法找出必须从 C# 传递给函数的类型...我尝试了 Marshal 类中的所有 StringToXXX 函数,但似乎没有任何效果:/我想我在这里缺少一些简单的东西,但我不明白是什么。

非常感谢任何帮助!

最好的问候

克里斯蒂安

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

め可乐爱微笑 2024-10-10 03:01:55

IDL 声明

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

没有任何意义。当您将 BSTR 作为 in 参数传递时,只需“按值”传递它:

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

那么您不需要在 C# 代码中执行任何特殊操作 - 只需传递 string 在那里,编组将自动完成。

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

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.

云醉月微眠 2024-10-10 03:01:55

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

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

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);
掌心的温暖 2024-10-10 03:01:55

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

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文