Windows iCalFactory与32位和64位类型库并排

Windows iCalFactory与32位和64位类型库并排,windows,winapi,com,registry,typelib,Windows,Winapi,Com,Registry,Typelib,我有一个in-proc COM服务器,我想为其构建32位和64位版本。我可以毫无问题地做到这一点。然而,当两个版本都注册时,我遇到了一些问题 我没有使用ATL。在DllRegisterServer函数中,我正在使用。我通过调用DLL的路径来获取调用的实例,并使用REGKIND_NONE标志。我正在使用.idl和MIDL编译器创建我的类型库。我正在将类型库作为资源嵌入到我的.dll中。考虑到下面的前两个项目(一切都按预期进行),我这样做似乎没有任何问题 如果我只注册32位,那么在32位客户机中一

我有一个in-proc COM服务器,我想为其构建32位和64位版本。我可以毫无问题地做到这一点。然而,当两个版本都注册时,我遇到了一些问题

我没有使用ATL。在DllRegisterServer函数中,我正在使用。我通过调用DLL的路径来获取调用的实例,并使用REGKIND_NONE标志。我正在使用.idl和MIDL编译器创建我的类型库。我正在将类型库作为资源嵌入到我的.dll中。考虑到下面的前两个项目(一切都按预期进行),我这样做似乎没有任何问题

  • 如果我只注册32位,那么在32位客户机中一切正常,而在64位客户机(类未注册)中则会出现预期的故障
  • 如果我只注册64位,那么在64位客户机中一切正常,在32位客户机(类未注册)中会出现预期的故障
  • 如果我先注册64位,然后注册32位,那么在32位客户机中一切正常,但在64位客户机中会失败。如果我随后注销32位服务器,64位客户端将继续失败。如果我重新注册64位服务器(无论是否注销),64位客户端都可以工作
  • 如果我先注册32位,然后注册64位,那么在64位客户机中一切正常,但在32位客户机中会失败。如果随后注销64位服务器,32位客户端将继续失败。如果我重新注册32位服务器(无论是否注销),32位客户端都可以工作
当我注册两个服务器时,后一个调用似乎会破坏前一个调用的注册表设置

至于我得到的错误:

  • 只要注册了正确的服务器,就始终有效。在32位客户机中,只要注册了32位服务器(即使也注册了64位服务器),它就可以工作。对于64位客户端和64位服务器,同上
  • 在任何可行的情况下,我都可以调用对象上的方法。我可以在单元之间封送接口(我正在使用全局接口表),并且可以调用封送接口上的方法
  • 我得到的错误与接口已编组到的单元中的错误特别相关。我可以在封送的接口上毫无问题地查询。但是当我用异步接口的IID调用时,我收到了错误E_NOINTERFACE
  • 如前一列表中所述,只要上次注册的服务器与客户端具有相同的目标平台,我就不会收到此错误
我现在正试图挖掘我的注册表,弄清楚在注册过程中到底发生了什么变化,但由于注册表重定向器的存在,这并不是那么简单。当我发现注册表信息时,我会更新这篇文章。

弄明白了

在64位操作系统上运行时,RegisterTypeLib和RegisterTypeLibForUser始终同时写入32位和64位条目(即使进程为32位)。这在大多数情况下都是完全可以接受的,因为只有接口和类型库元数据被写入。编写接口键时,RegisterTypeLib/RegisterTypeLibForUser将ProxyStubClsid32设置为适用于接口类型(dual、oleautomation等)的通用默认p/s。但是,通用代理/存根似乎无法在自定义异步接口上与iCalFactory配合使用。我修改了注册例程,以便始终在32位和64位注册表项中设置自定义代理/存根信息。这可以确保以后的注册不会超过以前注册的信息

[更新]:最后,由于可用API中的几个弱点,我不得不编写自己的注册例程:

  • RegisterTypeLib和RegisterTypeLibForUser不写入AsynchronousInterface、SynchronousInterface和NumMethods注册表项。这是因为编译的类型库中没有显式链接同步和异步接口的信息。我自己的注册例程按名称匹配接口——它查找IXxx接口和相应的AsyncIXxx接口(仅按名称,没有方法比较),并根据需要设置这些注册表项
  • RegisterTypeLib和RegisterTypeLibForUser始终同时写入32位和64位注册表项,包括但不限于ProxyStubClsid32。这意味着通过这种方式注册类型库将覆盖以前通过其他方式编写的相反体系结构的任何ProxyStubClsid32。要解决这个问题,可以先注册两个类型库(32和64),然后注册代理/存根DLL。然而:
  • MIDL编译器生成的代理/存根代码似乎没有提供在每用户注册表中注册p/s的任何方法。如果要求每个用户注册,则生成的注册例程没有用处
  • 即使生成的代理/存根注册例程可以是每个用户,但如果代理/存根合并到com服务器dll中,则只有一个注册机会—单个dll中的单个DllRegisterServer。如果该例程只在注册表的一侧写入ProxyStubClsid32项(32位或64位,而不是两者),则随后为另一个体系结构注册dll将更改第一个体系结构的ProxyStubClsid32
  • 我还没有测试过像CoRegisterPSClsid这样的一些API。由于文档中没有提到每个用户的注册,我想它是不受支持的

尝试使用查看
注册表TypeLibForUser()
对注册表的实际操作。听起来注册是在某处修改共享密钥,而不是使用单独的32/64位密钥。找到它了。这与RegisterTypeLib/RegisterTypeLib使用wri的方式有关