ICallFactory与32位和64位类型库并排

时间:2015-06-11 00:23:23

标签: windows winapi com registry typelib

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

我没有使用ATL。在我的DllRegisterServer函数中,我使用的是RegisterTypeLibForUser。我通过使用我的DLL路径调用ITypeLib来获取RegisterTypeLibForUser调用的LoadTypeLibEx实例,并且我正在使用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位客户端可以正常工作。

看来,当我注册这两个服务器时,后一个RegisterTypeLibForUser调用会阻止上一次RegisterTypeLibForUser调用的注册表设置。

至于我得到的错误:

    只要注册了正确的服务器,
  • CoCreateInstance始终有效。在32位客户端中,只要注册了32位服务器,CoCreateInstance就会工作(即使64位服务器也已注册)。同样适用于64位客户端和64位服务器。
  • CoCreateInstance有效的任何情况下,我都可以在对象上调用方法。我可以整理公寓之间的接口(我正在使用全局接口表),我可以在编组接口上调用方法。
  • 我得到的错误与接口已被封送的公寓中的ICallFactory特别相关。我可以在编组接口上查询ICallFactory而没有任何问题。但是当我使用异步接口的IID调用CreateCall时,我收到错误E_NOINTERFACE。
  • 如上一个清单所述,只要上次注册的服务器是与客户端具有相同目标平台的服务器,我就不会收到此错误。

我正在尝试挖掘我的注册表,并确定在注册发生时究竟发生了什么变化,但由于注册表重定向器,这并不是那么简单。当我发现注册表信息时,我将更新这篇文章。

1 个答案:

答案 0 :(得分:4)

想出来。

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

[更新]:最后,由于可用的APIS存在一些缺点,我不得不编写自己的注册程序:

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