为32位DLL编写COM / ATL包装器的正确方法

时间:2013-06-20 18:52:48

标签: c# c++ com 32bit-64bit atl

我有一个关于为32位DLL正确编写COM / ATL包装器的问题。

这是问题所在。正如我的其他一些问题所暗示的那样,我经常需要在大型代码库上执行编码工作,其中包括从不同供应商的恐惧链接的库。我们的软件可以在各种机器上运行,可以在各种架构上运行。这段代码主要用C#编写,C ++ DLL链接或编译/链接,然后在必要时从C#调用P /(在我看来,比托管C ++更容易实现)。

无论如何,一个这样的程序包含C#代码,它必须与几个64位DLL连接,源不可用。该软件的目标主机均为64位。没问题。因此,在AnyCPU模式下运行的C#会自动生成为64位(没有WoW),并且能够无缝地P / Invoke这些预编译的第三方64位DLL。

有一个这样的DLL,我只能使用32位版本。无法获得此DLL的64位版本。我有1.)32位DLL,一个包含函数导出的头文件(即#define EXP __declspec(dllexport),EXP BOOL WINAPI DLL_Function(IN int myInt,OUT int * result);和3.)相应的32位lib文件。

经过广泛的研究,我了解到,显然,COM / ATL是从64位进程访问32位DLL的正确方法。显然,我在WoW下生成了一个32位的COM进程,并与它进行交互。从架构的角度来看听起来不错,但我找不到任何有关如何专门执行此操作的教程或说明。我已经尝试过使用Visual Studio 2010的ATL向导,但我仍然不知道如何正确地执行此操作。有自动化工具吗?任何模板或教程?我保证我已尽最大努力搜索网络,并且只是想知道1.)如果我以正确的方式接近这个问题,或者2.)你知道任何资源吗?或者3。)任何人都有这种通用的IPC模板吗?

从我在SO上看到的,似乎这样的图像不匹配对于程序员来说是一个常见的问题,但是我还没有找到任何详细的解释(或至少指向详细的解释),除了“使用COM / ATL”。我以前的一篇帖子产生了一个响应,其中P / Invoke签名调用的问题已经非常详细地充实了,这太棒了 - 我想知道我们是否可以启动一个“确定的”64/32位跨架构讨论就在这里!

谢谢!

-Kadaj

编辑:我已经了解http://blog.mattmags.com/2007/06/30/accessing-32-bit-dlls-from-64-bit-code/,并了解架构,但我想知道实施细节。

2 个答案:

答案 0 :(得分:1)

您可以在几分钟内获得简约的ATL解决方案。

分步说明:

  1. 创建空解决方案
  2. 使用Visual Studio向导添加ATL项目。这将是C ++,ATL项目,可执行EXE - 您将需要EXE,因为这将是托管您的32位代码的独立32位进程
  3. 在项目中,您添加类,ATL简单对象,所有默认值 - 您将拥有一个类(例如CFoo)以及IDispatch派生的接口IFoo
  4. 您向IFoo接口添加方法,并在CFoo类中添加相应的实现,例如: CFoo::Bar
  5. C ++部分已完成,构建并确保它已注册COM(可执行文件只能使用/regserver参数运行一次)
  6. 添加C#项目,将其位数强制为x64,将COM引用添加到上面步骤5中构建的ATL COM服务器
  7. 将[STAThread]添加到您的C#代码并从C#调用Bar - 您已完成!
  8. C#:

    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            HostLib.Foo foo = new HostLib.Foo();
            foo.Bar();
        }
    }
    

    C ++ IDL:

    [
        // ...
    ]
    interface IFoo : IDispatch
    {
        [id(1)] HRESULT Bar();
    };
    

    C ++:

    // IFoo
        STDMETHOD(Bar)()
        {
            MessageBox(GetActiveWindow(), _T("Hello, 32-bit World!"),
                _T("Information"), MB_OK);
            return S_OK;
        }
    

    64位C#代码启动32位COM EXE并调用Bar方法。

    来源:Trac / SVN

答案 1 :(得分:1)

最终,您需要在32位进程中托管32位dll,并将数据与64位进程进行编组。

首先,我应该解释一下COM和DCOM是什么:

COM

在C / C ++ / VB6 / etc之上提供了一个约定,它通过定义的接口标准化调用和交换数据。它还有一个注册表,用于将对象的相关dll加载到您的进程中。

DCOM

介绍编组和代理的概念,您可以在其中调用接口,但是它的一个代理将包装参数的命令推送到另一个进程的命令管道,等待结果并解压缩响应。该过程可以在不同的计算机上,甚至具有不同的处理器体系结构。

所以你可以使用DCOM来解决你的问题,但学习曲线很大,而且它对你想要的东西来说几乎太强大了。

您需要查看应用程序所需的体系结构以确定正确的解决方案,但我将介绍一些高级主体。

如果您创建一个32位.Net进程/服务来托管DLL,那么您可以研究一种在64位和32位进程之间执行IPC的技术之一。您需要决定是否要为每个64位进程分配一个或每个系统一个进程,以及它的生命周期应该是什么。 然后,您需要找到一种交换数据的方法,并整理调用。

  • WCF 可能是一个很好的(但很复杂的)赌注,如果你想要每台机器一个主机进程并且具有相对复杂的接口。

  • JSON RPC / HTTP 可能是另一个更轻量级的解决方案,您需要注意安全性。

  • STDIO 如果你可以逃脱它,编写一个32位命令行应用程序,只需通过STDIO管道数据,这很容易保护并具有一定的优雅unix。

这些解决方案的优点在于,您可以尽可能多地保留.Net土地,这将减少学习曲线。