1

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

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

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

有一个这样的 DLL,只有 32 位版本可供我使用。无法获得此 DLL 的 64 位版本。我有 1.) 32 位 DLL,2.) 包含函数导出的头文件(即 #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 位跨架构讨论到这里!

谢谢!

-卡达伊

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

4

2 回答 2

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 - 大功告成!

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

于 2013-06-20T19:27:53.740 回答
1

最终,您需要将 32 位 dll 托管在 32 位进程中,并将数据编组到 64 位进程和从 64 位进程中提取。

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

通讯

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

DCOM

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

因此,您可以使用 DCOM 来解决您的问题,但是学习曲线非常庞大,而且对于您想要的东西来说它几乎太强大了。

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

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

  • 如果您希望每台机器有一个主机进程并且具有相对复杂的接口,WCF可能是一个不错的(但复杂的)选择。

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

  • STDIO如果你能摆脱它,写一个 32 位命令行应用程序,然后通过 STDIO 管道传输数据,这很容易保护并且具有一定的 unix 般的优雅。

这些解决方案的好处是您可以尽可能多地留在 .Net 领域,这将减少学习曲线。

于 2013-06-20T19:36:19.410 回答