我有一个进程内COM服务器,我想build立32位和64位版本。 我可以做到这一点没有问题。 但是,当两个版本都注册时,我遇到了一些问题。
我没有使用ATL。 在我的DllRegisterServer函数中,我使用了RegisterTypeLibForUser 。 我通过调用LoadTypeLibEx与我的DLL的path获取RegisterTypeLibForUser调用的ITypeLib实例,并使用REGKIND_NONE标志。 我使用.idl和MIDL编译器创build我的types库。 我正在将我的.dll中的types库作为资源embedded。 鉴于下面的头两个项目符号(一切按预期工作),似乎没有任何问题,我正在这样做。
- 如果我只注册32位,一切都在32位客户端正常工作,我预计在64位客户端(类未注册)失败。
- 如果我只注册64位,一切都在64位客户端正常工作,并得到预期的32位客户端(类未注册)失败。
- 如果我注册64位,其次是32位,一切都在32位客户端正常工作,但我在64位客户端失败。 如果我然后取消注册32位服务器,64位客户端继续失败。 如果我重新注册64位服务器(有或没有注销),64位客户端的工作。
- 如果我注册32位,然后64位,一切正常,在64位客户端,但我在32位客户端失败。 如果我然后取消注册64位服务器,32位客户端继续失败。 如果我重新注册32位服务器(有或没有注销),32位客户端工作。
看来,当我注册这两个服务器时,后面的RegisterTypeLibForUser调用做了一些事情,搞砸了以前的RegisterTypeLibForUser调用的registry设置。
至于我得到的错误:
- 只要正确的服务器注册, CoCreateInstance就会始终工作。 在32位客户端中,只要注册了32位服务器(即使64位服务器也已注册), CoCreateInstance也会运行。 同上64位客户端与64位服务器。
- 在CoCreateInstance工作的任何情况下,我都可以调用对象上的方法。 我可以编组公寓之间的接口(我使用全局接口表),我可以在编组接口上调用方法。
- 我得到的错误与接口已被封送的公寓中的ICallFactory特别相关。 我可以在封送的接口上查询ICallFactory ,没有任何问题。 但是当我用我的asynchronous接口的IID调用CreateCall时,收到错误E_NOINTERFACE。
- 正如前面的列表中所提到的,只要上次注册的服务器是与客户端具有相同目标平台的服务器,我就不会收到此错误。
我试图通过我的registry现在,并确切地说正在发生的注册正在发生什么变化,但由于registryredirect器,这不是那么简单。 我会更新这个职位,因为我发现了registry信息。
弄清楚了。
当在64位操作系统上运行时(即使进程是32位),RegisterTypeLib和RegisterTypeLibForUser总是写入32位和64位条目。 在大多数情况下,这是完全可以接受的,因为它只是写入的接口和类型库元数据。 当写入接口密钥时,RegisterTypeLib / RegisterTypeLibForUser将ProxyStubClsid32设置为适用于接口类型(dual,oleautomation等)的通用默认p / s。 但是,通用代理/存根似乎无法在自定义异步接口上使用ICallFactory。 我修改了我的注册例程,以便始终在32位和64位注册表项中设置我的自定义代理/存根信息。 这确保了以后的注册不会超过以前的注册信息。
[更新]:最后,由于可用的APIS存在几个弱点,我不得不编写自己的注册程序:
- 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这样的apis。 由于文档没有提及每个用户的注册,我会想象它不被支持。