2013-10-10 71 views
11

TL; DRregsvr32生成的所有注册表项必须存在于SxS reg-free-COM清单中,反之亦然?清单中的注册免费COM需要哪些标签?


我想要免费注册COM去第三方组件。

Readingupon的主题,我发现有提到的几个元素,可以放入清单:

From the docs,我们可以添加以下标签清单来描述一个COM组件:

  • assemblyIdentity - 这真的只是描述了“抽象assembly”据我可以告诉
  • comClass - 介绍COM类(IID在terface)。它会出现,这总是需要的。
  • typelib - 什么时候?
  • comInterfaceExternalProxyStub - 什么时候?
  • ​​- 什么时候?

From the other docs for HKEY_LOCAL_MACHINE\SOFTWARE\Classes我们可以看到有几个类别的COM注册表项:

使用regsvr42提取东西,我想regfree的dll产生仅包含comClass条目,没有类型库或ProxyStub条目清单。 (并且我交叉检查了写入的密钥,所述的DLL,pdm.dll,MS的进程调试管理器仅写入这些密钥,即在注册表中没有明显的类型库或代理存根信息。)

如果注册表只包含与comClass有关的信息,那么这是否意味着此信息在SxS清单中是足够的,或者可能需要清单中的其他信息?


顺便说一句,我注意到注册表中包含VersionIndependentProgId,并且具有附加在末尾的一个版本号的ProgId。该清单仅具有ProgId条目,该文档状态:

的ProgID:与 COM组件相关联版依赖性编程标识符。 ProgID的格式是 <vendor>.<component>.<version>

但该文档还规定

comClass元素可以有<progid>...</progid>元素 孩子,这列出的版本有关的ProgID。

and they say progid属性应该是版本无关的。

那么,这里放什么?当客户端没有请求特定版本时,它甚至是重要的吗?

+0

PDM不会有类型库,它没有IDispatch接口,您必须使用CoCreateInstance()。而且它像一个免费线程进程组件一样嘎嘎,所以不需要代理/存根。这里究竟出了什么问题? –

+0

@Hans,谢谢。没有任何事情会出现这样的错误,但我不确定是否有任何潜在的缺陷。 (COM总是让我觉得我失去了一些东西。)如果你能帮助我解开上面的两个或三个实际有用的问题,我会很感激。否则,我很高兴,你似乎认为一切都是我命令:-) –

回答

11

assemblyIdentity元素始终是必需的,是清单管道的一部分。您必须始终提供comClass元素,它将替代HKLM\Software\Classes\CLSID注册表项并用于使客户端的CoCreateInstance()调用起作用。该文件元素命名COM服务器可执行文件。

其余的键是可选的,他们需要使编组工作。当客户端调用需要在不同的线程上进行时,会发生封送。那么总是发生在服务器和客户端处于不同的进程中时,对于进程外服务器或当服务器在另一台计算机上运行时。当comClass元素中指定的ThreadingModel需要它时,它可能会发生。换句话说,当COM对象在一个线程上创建,但在另一个线程上调用时,服务器不是线程安全的。

RPC实现封送处理,但它有一个工作要做,它需要帮助。它需要知道函数的参数是什么,以及返回类型。这样它就可以正确地将它们的值序列化成一个数据包,这个数据包可以通过网络传输,或者传递给另一个线程中的代码。这是代理的工作。存根在接收端运行并反序列化参数以构建堆栈帧并进行调用。函数返回值以及任何通过引用传递的参数值然后返回给调用者。否则进行调用的代码根本没有意识到它没有直接调用该函数。

有四种基本情况:

  • 的COM服务器不支持被称为这样的一切,必须始终从创建它在相同的线程中使用。停在那里,不需要向清单添加任何东西。

  • COM服务器实现了IMarshal interface。当它无法找到另一种编组呼叫的方式时,由COM自动查询。这是非常罕见的,除了COM服务器聚合自由线程编组的情况。换句话说,它本身完全是线程安全的,不需要任何帮助,并且始终在进程中运行。 PDM很可能会这样工作。停在那里,不需要向清单添加任何东西。

  • COM服务器作者通过用IDL语言编写服务器的接口描述来启动他的项目。然后由MIDL编译。它可用的一个选项是从IDL声明中自动生成代码,这些代码可用于构建实现代理和存根的独立DLL。 IDL足够丰富,可以描述函数参数类型和用法的详细信息,以允许通过此自动生成的代码完成封送处理。有时IDL属性不够用,COM作者会写一个自定义编组器。 COM在运行时加载该DLL以自动创建代理和存根对象。

  • 针对COM自动化子集(IDispatch接口),Windows有一个内置编组器,它知道如何编组符合子集要求的调用。很常见。它使用类型库来发现函数声明。

后两个项目符号需要使用HKLM\Software\Classes\Interface,它具有用于每个接口的IID的条目。这就是COM如何发现如何创建代理和界面的存根。如果找不到密钥,则会回到IMarshal。您必须使用comInterfaceExternalProxyStub元素来替换注册表项。使用comInterfaceProxyStub是一种特殊情况,即当COM服务器可执行文件包含代理和存根代码而不是单独的文件时。例如,在ATL项目中的一个选项,打开“允许合并代理/存根”向导选择。

最后一个项目符号还需要使用typelib元素,因此内置编组器可以找到它需要的类型库。

当COM客户端通过IDispatch使用后期绑定时,progId是必需的,客户端的运行时支持库中的CreateObject()辅助函数是样板。例如,用于任何脚本宿主。

有一些关于如何创建COM服务器的内幕知识当然有帮助,请务必联系供应商或作者寻求建议。可以通过观察注册服务器注册时注册哪些注册表项来进行反向设计,SysInternals的ProcMon工具是查看该注册表的最佳方式。基本的东西去寻找:

  • 如果你看到它写HKLM\Software\Classes\Interface键,那么你可以认为你必须提供comInterface |外部| ProxyStub元素

  • 如果你看到它写{00020420-0000 -0000-C000-000000000046}对于ProxyStubClsid32键,则可以假定它使用的是标准编组器,并且必须使用comInterfaceExternalProxyStub元素以及typelib元素。然后您应该看到它会写入IID的TypeLib注册表项以及HKLM \ Software \ Classes \ Typelib注册表项中的条目。后者给出了类型库的路径。几乎总是和COM服务器一样,将类型库作为资源嵌入是非常普遍的。如果它是单独的(一个.tlb文件),那么你必须部署它。

  • 如果ProxyStubClsid32键值是另一个GUID,那么您可以假设它使用自己的代理/存根DLL。然后您应该看到它为代理编写CLSID键,它的InProcServer32键为您提供了DLL的路径。如果该文件名与服务器的文件名相匹配,那么您可以假定代理/存根代码已合并,您必须改用comInterfaceProxyStub元素。如果不是那么comInterfaceExternalProxyStub是必需的,您必须部署DLL

  • 如果您看到它在HKLM\Software\Classes中编写ProgID,然后使用progid元素,完全如跟踪中所示。

+0

令人惊叹。谢谢。 :-) pdm。dll是一个有趣的案例,因为有第二个DLL,msdbg2.dll * *似乎*包括用于调试接口的ProxyStubs。 (例如,msdbg2.dll是Visual Studio需要的,以便能够附加到进程)但是,我们使用pdm.dll(调试vbscript)的方式似乎并不需要msdbg2.dll中的ProxStub,因为我们的代码高兴地工作没有msdbg2.dll。 (虽然,如果注册,msdbg2.dll将通过pdm.dll加载 - 不知道它究竟做了什么。)嗯。这一切都是如此混乱。 –