64 位托管进程:进程外 32 位 COM 服务器非默认接口不可用

Posted

技术标签:

【中文标题】64 位托管进程:进程外 32 位 COM 服务器非默认接口不可用【英文标题】:64-bit managed process: out-of-proc 32-bit COM server non-default interfaces not available 【发布时间】:2021-09-17 13:54:34 【问题描述】:

我正在将最初用 VB6 编写的 Excel 加载项迁移到托管代码和 64 位 Excel。该加载项通过 COM 代理与一些旧的 32 位 COM DLL 服务器进行互操作,并且遇到了一个问题,即只有 coclass 各自默认接口中的方法和属性在运行时可用。尝试调用组件公开的任何其他接口中的方法和属性会导致 System.MissingMethodExceptions。

当迁移的插件与 32 位 Excel 一起使用并且服务器在进程中运行时,非默认接口可用。

有什么办法可以使非默认接口在 64 位模式下可用于加载项?

【问题讨论】:

一般来说,不仅仅是配置。发现 COM 规则(代理/存根、编组、线程模型、套间)只有在您退出进程时才被开发人员理解(或简单地忽略)是一种常见情况。必须修改 DLL,或者您必须在其上编写一个 COM 正确的 32 位包装器(另一个 dll),以便您可以从 64 位使用该包装器。 有资源吗?我所能找到的只是对自定义代理的模糊暗示。 您只需要一个代理:您当前使用的那个。我正在谈论的包装器将是一个 32 位 DLL,与您的 32 位 DLL 同步。它的目的只是向 COM 世界的其他部分公开相同(或几乎)的 COM 接口,但与进程外客户端/代理兼容。这只是要编写的自定义代码。您不会再直接在 COM 中使用 32 位 DLL。 你能给我举个例子吗? 否,因为它完全取决于您的 32 位 DLL 及其表现出的确切问题。这里没有什么神奇之处,这不一定是一件容易的事。如果您有一个小型的现有复制项目,我们可以尝试做一些事情。 【参考方案1】:

解决方案是使用类型库编组(也称为通用编组),使用 oleaut32.dll 中系统提供的编组引擎。通用封送拆收器可与任何自定义接口一起使用,前提是参数与变体兼容。

要将通用封送处理程序用于接口,该接口使用 oleautomation 标记,如以下示例接口所示:

[
    object,
    oleautomation, 
    uuid(23D4EC0B-96DA-4D18-82BD-40E3AA0483FD),
    version(1.0),
    dual,
    helpstring("Description of ICustomInterface1"),
    pointer_default(unique)
]
interface ICustomInterface1 : IDispatch

    // Methods and properties …

通用编组还需要以下注册表项:

HKCR\TypeLib

HKCR\TypeLib\0

HKCR\TypeLib\0\win32 = “类型库文件路径”

HKCR\TypeLib\Flags

HKCR\TypeLib\HelpDir = “帮助文件夹路径”

[HKEY_CLASSES_ROOT\Interface @="接口名称"

[HKEY_CLASSES_ROOT\Interface\ProxyStubClsid32 ="00020424-0000-0000-C000-000000000046"

HKCR\Interface

使用此类型信息,通用封送拆收器在运行时创建代理存根,无需自定义代理存根 DLL。

在我们的例子中,鉴于组件是基于 ATL 的,一旦接口被标记为“oleautomation”并重建组件,就会自动创建注册表条目。对于非 ATL 项目,这可以通过 Win32 API 的 LoadTypeEx() 以编程方式完成(我没有尝试过)。

一旦完成,我们基于 ATL 的组件的非默认接口就可以在我们迁移到 VB.NET Excel COM 插件的进程外使用。

所有这些都在“开发人员的 COM 和 ATL 3.0 研讨会”的第 5 章中有详细说明。

【讨论】:

这远不是一般的案例解决方案。这只是因为您的 DLL 完全兼容 COM 自动化并且您很幸运(即使使用 oleautomation,它仍然可能会失败,具体取决于实现)。通常,像这样的 COM 对象已经正确配置、编译和注册。这也很幸运,因为您拥有 ATL(您应该在问题中提到它是您拥有源代码的 ATL 项目)。对于非 ATL 项目,这不太可能起作用。既然你有源代码,为什么不把它移植到 x64 上呢?如果写得好,可能只是编译的问题 将整个堆栈移植到 x64 不在此版本的范围内,可能需要几年时间才能得到管理层的授权。迁移此加载项的唯一原因是 64 位 Office 很流行,并且客户要求 64 位兼容性。

以上是关于64 位托管进程:进程外 32 位 COM 服务器非默认接口不可用的主要内容,如果未能解决你的问题,请参考以下文章

通过 COM 在 64 位进程中使用 32 位 DLL

使用 C++ 从 32 位进程访问 64 位 dll

32位程序下调用64位函数——进程32位模式与64位模式切换

x64 上的 x86 远程调试器服务

从 32 位进程获取 64 位进程的命令行字符串

如何从 32 位进程启动 64 位进程