代码之家  ›  专栏  ›  技术社区  ›  Christian

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

  •  5
  • Christian  · 技术社区  · 14 年前

    我在处理COM Interop时遇到一些问题,具体情况如下:

    一个32位COM EXE服务器(用C++编程)提供了一个类,它具有处理第三方硬件的一些成员函数(该硬件还将COM EXE服务器连接到32位,因为制造商不支持64位)。

    我想在64位.NET(C)应用程序中使用32位的com exe服务器…首先,我尝试在Visual Studio 2010中添加对exe服务器的引用,它创建了一个互操作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服务器:

    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-u-typemismatch))。不幸的是,我无法找出我必须从C传递给函数的类型。我尝试了marshal类中的所有StringToxx函数,但似乎没有任何效果。/我想我这里缺少了一些简单的东西,但我看不到什么。

    非常感谢您的帮助!

    最好的问候

    基督教的

    3 回复  |  直到 14 年前
        1
  •  1
  •   sharptooth    14 年前

    IDL声明

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

    毫无意义。当你通过 BSTR 作为一个 in 参数“按值”传递:

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

    那么你就不需要在C代码中做任何特殊的事情了-只要通过 string 在那里,编组将自动完成。

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

        2
  •  1
  •   weismat    14 年前

    默认情况下,.NET字符串由COM互操作在C++中编组到LPTSTR。因此,必须使用marshalas属性显式地将任何其他类型的非托管字符串(包括bstr)封送到.NET字符串或从该字符串封送。
    尝试

     int Initialize([MarshalAs(UnmanagedType.BStr)] ref string callingApplicationPath);
    
        3
  •  0
  •   Jaster    14 年前

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

    不过,你还是可以用一个非常简单的结构来完成你的任务;
    创建一个32位.NET包装器,并通过wcf将其连接到64位应用程序。我建议在COM/非托管服务器上创建一个混合模式C++包装,并将一个基于WCF的层放置在“纯”CLR(C、V.NET等)中作为您的主要应用程序的连接点。