带有 32 位 VB6 COM 对象的 64 位 C#

Posted

技术标签:

【中文标题】带有 32 位 VB6 COM 对象的 64 位 C#【英文标题】:64 bit C# with a 32 bit VB6 COM object 【发布时间】:2010-10-11 07:57:08 【问题描述】:

我有一个 32 位进程内 STA VB6 dll。很遗憾,我对此无能为力。我的 C# 组件极大地受益于 64 位。无论如何从我的 64 位进程调用/接口这个 32 位 dll 吗?任何形式的包装或任何东西?

【问题讨论】:

Access x86 COM from x64 .NET的可能重复 【参考方案1】:

您可以在代理中加载(例如)仅 32 位的 DLL,并通过以下方式从 64 位进程访问它。

如果有可用的编组器,这将起作用,通常会有一个带有类型库的组件,因为它们通常使用标准编组器。如果对象需要自定义代理/存根,它将无法工作,因为 64 位版本不存在,或者您一开始就不会遇到这个问题。

如何注册第三方 32 位组件以供 64 位客户端使用

首先您需要一个 AppID。如果 DLL 已经有 AppID,您应该使用它。您可以通过查看您感兴趣的 CoClass 的 CLSID 键来查找。

这里使用的示例是Capicom.HashedDataCapicom.EncryptedData 类。 Capicom 只有 32 位。

AppID: CAPICOM 没有 AppID,所以对于 AppID,我只使用了 EncryptedData 类的 CLSID。

CLSID:您需要一个您希望能够从 64 位客户端创建的每个类的 CLSID 列表。在这个例子中,它只是 EncryptedData 和 HashedData。

注册:根据示例创建一个包含详细信息的注册表文件,并将其加载到注册表中。

您应该使用 32 位版本的 Regedit 来执行此操作,因为它是 32 位组件。如果您想要从 32 位访问 64 位组件,请使用另一个。 (这是因为 32 位兼容层的注册表虚拟化 - 使用匹配的 regedit 位数版本可以为您解决这个问题,确保您编辑正确的注册表虚拟化版本。

Windows Registry Editor Version 5.00


;;; Capicom AppID - just using the Capicom.EncryptedData CLSID
;;; Use default surrogate = empty string
[HKEY_CLASSES_ROOT\AppID\A440BD76-CFE1-4D46-AB1F-15F238437A3D]
"DllSurrogate"=""

;;; Capicom.EncryptedData
[HKEY_CLASSES_ROOT\CLSID\A440BD76-CFE1-4D46-AB1F-15F238437A3D]
AppID="A440BD76-CFE1-4D46-AB1F-15F238437A3D"

;;; Capicom.HashedData - use same AppID for all!!!!!
[HKEY_CLASSES_ROOT\CLSID\CE32ABF6-475D-41F6-BF82-D27F03E3D38B]
AppID="A440BD76-CFE1-4D46-AB1F-15F238437A3D"

保存到myComponent-dllhost.reg 文件,然后就可以离开了。

c:\windows\sysWow64\regedit.exe "myComponent-dllhost.reg"

您现在应该能够从 64 位脚本/COM 主机访问 Capicom.HashedData 和 Capicom.EncryptedData。

注意事项:

这仅适用于基本的 OLE 自动化类型。任何与 VBScript 或 javascript 中的 Windows Scripting Host 脚本兼容的对象都应该没问题。 您只需将 AppID 添加到可直接创建的对象中。那基本上是那些有 InprocServer32 条目的。从工厂生成的对象或仅作为子对象可用的对象不必添加 AppID。 如果已经有 AppID,您只需添加空字符串 "DllSurrogate" 条目。就是这样! 这将不会影响 DLL 的正常客户端。只要位数匹配,它们就会像以前一样继续在进程中加载​​。唯一不同的是,它可以从不同位数的客户端在进程外实例化。

【讨论】:

这里写着“添加空字符串“dllhost”条目”你的意思是说“DllSurrogate 条目”吗?【参考方案2】:

本文Dealing with Legacy 32-bit Components in 64-bit Windows帮你:

我找到了这个解决方案,请参阅article : • 将项目类型从进程内转换为进程外 • 使用 COM+ 作为主机(这对我有用) • 使用 dllhost 作为代理主机

【讨论】:

dllhost 代理似乎是迄今为止最直接的方法。这个问题的另一个答案有更详细的解释。 ***.com/a/8908105/3195477【参考方案3】:

32 位 COM 组件将不得不耗尽进程。

在开始创建包装器之前,请检查 COM+(对象服务)是否会托管它。

【讨论】:

我认为在 COM+ 中托管作为服务器应用程序会起作用。当然取决于 dll 但好主意。 嗨,Richard,我对 COM+ 非常陌生。您能否稍微扩展您的答案(或将我引导到有关如何执行此操作的资源)?感谢您的帮助。 我的 COM+ 技能已经过时了,我已经有好几年没有认真地使用 COM+了。确保您初始化 DCOM 安全性是必须的,然后遵循 MSDN。【参考方案4】:

没有直接的方法可以做到这一点。

由于您无法移植 VB6 inproc dll,我建议您编写一个 32 位进程外服务器,该服务器实现相同的接口并将其委托给 VB6 代码。然后,您的 64 位应用程序可以调用进程外服务器,因为 COM 将负责在进程之间封送类型。

它不漂亮,它会工作!

【讨论】:

是的,有办法做到这一点,请参阅我的答案以获取详细说明。 在进程外进行可能是一种选择,但无法完成的说法似乎是不正确的。 @DaveInCaz _ 我不是说不能做,而是说没有直接的方法可以做到——有区别。您不能将 32 位 DLL 加载到 64 位进程中,但您可以将其加载到 32 位进程中并作为进程外服务器访问它。 公平点,虽然我想我一直认为 com 是相当间接的,所以代理过程的额外层对我来说似乎不是一个很大的概念差异。

以上是关于带有 32 位 VB6 COM 对象的 64 位 C#的主要内容,如果未能解决你的问题,请参考以下文章

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

从 64 位应用程序加载/与 vb6 COM dll 交互

如何在VB6中表示64位整数?

VB6插件注册

64 到 32 位互操作 - 如何?

如何在 64 位平台上创建连接到 32 位驱动程序的数据源?