第三方组件的COM代理

13

我正在编写一个小的DLL组件,需要访问两个第三方组件来合并数据,其中一个只支持32位,另一个只支持64位。它们都已经用TypeLib注册,并且是Automation兼容的,所以封送应该不是问题。

如果我正确理解了文档,那么除非组件还具有AppID和DllSurrogate键,否则没有办法强制在代理中加载;由于两者都是第三方组件,我有些不愿修改它们的注册信息。

有没有一种方法可以在没有AppID的情况下激活组件中的对象,在代理进程中从没有任何额外依赖的DLL组件中进行?或者有人能解释一下为什么这样做是不好的吗?


1
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682432%28v=vs.85%29.aspx - Hans Passant
1
一个自定义代理也需要服务器组件有一个AppID,这样COM才知道在哪个代理中实例化类?如果我添加了这个,这将影响所有客户端,而不仅仅是我的组件,我宁愿避免这种情况(另外,标准代理应该可以正常工作)。 - Simon Richter
Raymond Chen建议,资源管理器可以以某种方式CoCreateInstance未注册DllSurrogate键的对象,以便在代理中创建它们 - 我很感兴趣如何实现。 - Simon Richter
@SimonRichter,我怀疑Explorer只是使用一个辅助对象,控制其注册,从外部创建该对象,并由此创建插件。 - Ben
1个回答

10

是的,您可以通过代理加载一个(例如)只有32位的DLL,并以以下方式从64位进程中访问它。前提是必须有可用的编组程序,因为对于具有类型库的组件通常使用标准编组程序,所以一般情况下都会有。如果对象需要自定义代理/存根,则不会存在64位版本,否则在第一次遇到该问题时就不存在了,这时候无法工作。

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

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

您应该使用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 Automation类型。任何与Windows Scripting Host VBScript或JavaScript脚本兼容的对象都应该是可以的。
  • 您只需要将AppID添加到可直接创建的对象中。那基本上就是具有InprocServer32条目的对象。从工厂生成或仅作为子对象可用的对象不必添加AppID。
  • 如果已经存在一个AppID,您只需要添加空字符串“DllSurrogate”项即可。就是这样!
  • 这不会影响DLL的普通客户端。只要位数匹配,它们将继续像以前一样在进程内加载。唯一的区别是,它将变得可能从不同位数的客户端实例化它。

我已经让它工作了,但我不太愿意修改其他组件(在这种情况下是Lotus Notes和Rational ClearCase)的注册表,因此我想知道是否有一种方法可以在不修改注册表的情况下完成这个任务。 - Simon Richter
2
不要害羞!另一方面,如果你真的想要的话,你可以创建一个帮助器组件,具有相同位数的方法HRESULT CreateObject([in] BSTR progID, [out, retval] IUnknown** ppRetVal)。让它在代理中创建对象并将其返回给你。 - Ben

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接