Mar*_* Ba 15 c++ com manifest side-by-side regfreecom
TL; DR是否所有生成的注册表项都regsvr32需要出现在SxS reg-free-COM清单中,反之亦然?
我正在尝试获得免注册的COM用于第三方组件.
读 了 关于主题,我发现有提到的几个要素,即可以放入一个清单:
从文档中,我们可以将以下标记添加到清单中以描述COM组件:
assemblyIdentity- 据我所知,这真的只是描述了"抽象集会 "comClass - 描述COM类(IID接口).看来,这总是需要的.typelib - 什么时候?comInterfaceExternalProxyStub - 什么时候?comInterfaceProxyStub - 什么时候?从其他文档HKEY_LOCAL_MACHINE\SOFTWARE\Classes我们可以看到COM注册表项有几个类别:
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{CLSID} 我假设大致相当于comClassHKEY_LOCAL_MACHINE\SOFTWARE\Classes\Interface\{IID}将对应于任何一个 comInterface[External]ProxyStub,但我真的不知道何时使用哪个(或两者)typelib清单条目?使用regsvr42来提取我试图注册的dll会产生一个只包含comClass条目,没有typelib或ProxyStub条目的清单.(我交叉检查写的密钥,有问题的DLL pdm.dll,MS的Process Debug Manager只写那些密钥,也就是说,注册表中没有明显的类型库或代理存根信息.)
如果注册表只包含与此相关的信息,comClass则表示此信息在SxS清单中是足够的,或者清单中是否需要其他信息?
另外,我注意到注册表包含a VersionIndependentProgId和a ProgId,其末尾附加了版本号.清单只有一个ProgId条目,文档说明:
progid:与COM组件关联的与版本相关的编程标识符.ProgID的格式是
<vendor>.<component>.<version>.
但文档也说明了这一点
该comClass元素可以有
<progid>...</progid>子元素,其中列出的版本有关的ProgID.
并且他们说 progid属性应该是版本独立的属性.
那么,放在这里的是什么?当客户端没有请求特定版本时,它是否重要?
Han*_*ant 16
始终需要assemblyIdentity元素,这是清单管道的一部分.您必须始终提供comClass元素,它替换HKLM\Software\Classes\CLSID注册表项并用于使客户端的CoCreateInstance()调用工作.文件元素命名COM服务器可执行文件.
其余的键是可选的,它们需要进行编组工作.当需要在不同的线程上进行客户端调用时,会发生封送.这将始终在服务器和客户端在不同的过程,进程外的一个服务器或服务器另一台机器上运行的情况下发生的.当comClass元素中指定的ThreadingModel需要它时,就会发生这种情况.换句话说,当COM对象在一个线程上创建但在另一个线程上调用时,服务器不是线程安全的.
RPC实现编组,但它有一项工作要做,它需要帮助.它需要知道函数的参数是什么,以及返回类型.这样它就可以将它们的值正确地序列化为一个数据包,该数据包可以通过网络传输或传递给另一个进行调用的线程中的代码.这是代理的工作.存根在接收端运行并反序列化参数以构建堆栈帧并进行调用.函数返回值以及通过引用传递的任何参数值然后返回给调用者.否则进行调用的代码根本没有意识到它没有直接调用函数.
有四种基本情况:
COM服务器根本不支持以这种方式调用,并且必须始终在创建它的同一个线程中使用.停在那里,无需向清单添加任何内容.
COM服务器实现IMarshal接口.当COM无法找到另一种编组呼叫的方法时,由COM自动查询.这种情况非常罕见,除了COM服务器聚合自由线程编组器的情况.换句话说,它本身是完全线程安全的,无需任何帮助,并且始终在进程中运行.PDM很可能以这种方式工作.停在那里,无需向清单添加任何内容.
COM服务器作者通过用IDL语言编写服务器的接口描述来启动他的项目.然后由MIDL编译.它可用的一个选项是从IDL声明自动生成代码,代码可用于构建实现代理和存根的单独DLL.IDL足以描述函数参数类型和用法的详细信息,以允许通过此自动生成的代码完成编组.有时IDL属性是不够的,COM作者然后编写自定义编组程序.COM在运行时加载该DLL以自动创建代理和存根对象.
Windows具有特定于COM自动化子集(IDispatch接口)的内置编组器,它知道如何编组满足子集要求的调用.很普通的.它使用类型库来发现函数声明.
后两个子弹需要使用HKLM\Software\Classes\Interface,它具有每个接口的IID条目.这就是COM如何找到如何为接口创建代理和存根.如果它找不到密钥,那么它就会回落到IMarshal.您必须使用comInterfaceExternalProxyStub元素替换注册表项.使用comInterfaceProxyStub是一种特殊情况,即代理和存根代码包含在COM服务器可执行文件中而不是单独的文件中.例如,ATL项目中的一个选项,通过"允许合并代理/存根"向导选项打开.
最后一个子弹还需要使用typelib元素,因此内置的编组器可以找到它需要的类型库.
当COM客户端通过IDispatch使用后期绑定时,需要progId,客户端的运行时支持库中的CreateObject()辅助函数是样板文件.例如,在任何脚本主机中使用.
掌握一些关于如何创建COM服务器的内幕知识肯定有帮助,请始终联系供应商或作者以获取建议.它可以进行反向工程,但是通过观察服务器注册时写入的注册表项,SysInternals的ProcMon工具是查看它的最佳方式.要寻找的基本要点:
如果您看到它写了HKLM\Software\Classes\Interface密钥,那么您可以假设您必须提供comInterface | External | ProxyStub元素
如果您看到它为ProxyStubClsid32键写入{00020420-0000-0000-C000-000000000046},那么您可以假设它正在使用标准编组器,您必须使用comInterfaceExternalProxyStub元素以及typelib元素.然后,您还应该看到它编写IID的TypeLib注册表项以及HKLM\Software\Classes\Typelib注册表项中的条目.后者给出了类型库的路径.几乎总是与COM服务器相同,将类型库作为资源嵌入非常常见.如果它是单独的(.tlb文件),那么您必须部署它.
如果ProxyStubClsid32键值是另一个guid,那么您可以假设它使用自己的代理/存根DLL.然后,您还应该看到它为代理写入CLSID密钥,其InProcServer32密钥为您提供DLL的路径.如果该文件名与服务器的文件名匹配,则可以假定代理/存根代码已合并,您必须使用comInterfaceProxyStub元素.如果没有,则需要comInterfaceExternalProxyStub,您必须部署DLL
如果你看到它写入ProgID HKLM\Software\Classes然后使用progid元素,完全如跟踪中所示.