ICallFactory 并排提供 32 位和 64 位类型库
ICallFactory with 32-bit and 64-bit type libraries side by side
我有一个进程内 COM 服务器,我想为其构建 32 位和 64 位版本。我可以毫无问题地做到这一点。但是,我在注册两个版本时遇到了一些问题。
我没有使用 ATL。在我的 DllRegisterServer 函数中,我将 RegisterTypeLibForUser. I am acquiring the ITypeLib instance for the RegisterTypeLibForUser call by calling LoadTypeLibEx 与我的 DLL 路径一起使用,并且我正在使用 REGKIND_NONE 标志。我正在使用 .idl 和 MIDL 编译器创建我的类型库。我将类型库作为资源嵌入到我的 .dll 中。鉴于下面的前两个项目符号(一切都按预期工作),我这样做的方式似乎没有任何问题。
- 如果我仅注册 32 位,则在 32 位客户端中一切正常,但在 64 位客户端中出现预期故障(class 未注册)。
- 如果我只注册 64 位,则在 64 位客户端中一切正常,但在 32 位客户端中出现预期的故障(class 未注册)。
- 如果我先注册 64 位,然后再注册 32 位,则在 32 位客户端中一切正常,但在 64 位客户端中会出现故障。如果我随后取消注册 32 位服务器,64 位客户端将继续失败。如果我重新注册 64 位服务器(有或没有取消注册),64 位客户端可以正常工作。
- 如果我先注册 32 位,然后再注册 64 位,则在 64 位客户端中一切正常,但在 32 位客户端中会出现故障。如果我随后注销 64 位服务器,32 位客户端将继续失败。如果我重新注册 32 位服务器(有或没有取消注册),32 位客户端工作。
看来,当我注册两个服务器时,后者 RegisterTypeLibForUser call does something that screws up the registry settings for the previous RegisterTypeLibForUser 调用。
至于我遇到的错误:
- CoCreateInstance always works as long as the correct server is registered. In a 32-bit client, CoCreateInstance 只要注册了 32 位服务器就可以工作(即使 64 位服务器也注册了)。 64 位客户端与 64 位服务器同上。
- 在 CoCreateInstance 有效的任何情况下,我都可以调用对象的方法。我可以在单元之间编组我的接口(我正在使用全局接口 table),并且我可以在编组的接口上调用方法。
- 我收到的错误与我的异步接口的 IID ICallFactory in an apartment to which the interfaces have been marshaled. I can query for ICallFactory on the marshaled interface without any problem. But when I call CreateCall 具体相关,我收到错误 E_NOINTERFACE。
- 正如前面列表中提到的,只要最后注册的服务器是与客户端具有相同目标平台的服务器,我就不会收到此错误。
我现在正在尝试深入了解我的注册表,并弄清楚在进行注册时究竟发生了什么变化,但是由于注册表重定向器的存在,这并不是那么简单。我会在发现注册表信息时更新此 post。
想通了。
RegisterTypeLib 和 RegisterTypeLibForUser 在 运行 在 64 位 OS 上时总是写入 32 位和 64 位条目(即使进程是 32 位)。这在大多数情况下是完全可以接受的,因为它只是被写入的接口和类型库元数据。写入接口密钥时,RegisterTypeLib/RegisterTypeLibForUser 将 ProxyStubClsid32 设置为通用的默认值 p/s,这适用于接口类型(双重、oleautomation 等)。但是,通用 proxy/stubs 似乎不适用于自定义异步接口上的 ICallFactory。我修改了我的注册例程,以始终在 32 位和 64 位注册表项中设置我的自定义 proxy/stub 信息。这样可以确保以后的注册不会取代以前注册的信息。
[更新]:最后,由于可用 APIS 中的几个弱点,我不得不编写自己的注册程序:
- RegisterTypeLib 和 RegisterTypeLibForUser 不写入 AsynchronousInterface、SynchronousInterface 和 NumMethods 注册表项。这是因为编译类型库中没有显式链接同步和异步接口的信息。我自己的注册例程按名称匹配接口——它找到具有相应 AsyncIXxx 接口的 IXxx 接口(仅按名称,没有方法比较)并适当地设置这些注册表项。
- RegisterTypeLib 和 RegisterTypeLibForUser 始终写入 32 位和 64 位注册表项,包括但不限于 ProxyStubClsid32。这意味着通过这种方式注册类型库将覆盖以前通过其他方式编写的相反体系结构的任何 ProxyStubClsid32。要解决这个问题,可以先注册两个类型库(32 和 64),然后再注册 proxy/stub dll。然而:
- MIDL 编译器生成的 proxy/stub 代码似乎没有提供任何在每个用户注册表中注册 p/s 的方法。如果需要按用户注册,则生成的注册例程没有用。
- 即使生成的 proxy/stub 注册例程可以是每个用户,如果 proxy/stub 合并到 com 服务器 dll 中,也只有一个注册机会 -- 中的单个 DllRegisterServer单个dll。如果该例程仅在注册表的一侧写入 ProxyStubClsid32 条目(32 位或 64 位,而不是两者),则随后为另一个体系结构注册的 dll 将更改第一个体系结构的 ProxyStubClsid32。
- 我还没有测试过 CoRegisterPSClsid 等一些 API。由于文档没有说明每用户注册,我想它不受支持。
我有一个进程内 COM 服务器,我想为其构建 32 位和 64 位版本。我可以毫无问题地做到这一点。但是,我在注册两个版本时遇到了一些问题。
我没有使用 ATL。在我的 DllRegisterServer 函数中,我将 RegisterTypeLibForUser. I am acquiring the ITypeLib instance for the RegisterTypeLibForUser call by calling LoadTypeLibEx 与我的 DLL 路径一起使用,并且我正在使用 REGKIND_NONE 标志。我正在使用 .idl 和 MIDL 编译器创建我的类型库。我将类型库作为资源嵌入到我的 .dll 中。鉴于下面的前两个项目符号(一切都按预期工作),我这样做的方式似乎没有任何问题。
- 如果我仅注册 32 位,则在 32 位客户端中一切正常,但在 64 位客户端中出现预期故障(class 未注册)。
- 如果我只注册 64 位,则在 64 位客户端中一切正常,但在 32 位客户端中出现预期的故障(class 未注册)。
- 如果我先注册 64 位,然后再注册 32 位,则在 32 位客户端中一切正常,但在 64 位客户端中会出现故障。如果我随后取消注册 32 位服务器,64 位客户端将继续失败。如果我重新注册 64 位服务器(有或没有取消注册),64 位客户端可以正常工作。
- 如果我先注册 32 位,然后再注册 64 位,则在 64 位客户端中一切正常,但在 32 位客户端中会出现故障。如果我随后注销 64 位服务器,32 位客户端将继续失败。如果我重新注册 32 位服务器(有或没有取消注册),32 位客户端工作。
看来,当我注册两个服务器时,后者 RegisterTypeLibForUser call does something that screws up the registry settings for the previous RegisterTypeLibForUser 调用。
至于我遇到的错误:
- CoCreateInstance always works as long as the correct server is registered. In a 32-bit client, CoCreateInstance 只要注册了 32 位服务器就可以工作(即使 64 位服务器也注册了)。 64 位客户端与 64 位服务器同上。
- 在 CoCreateInstance 有效的任何情况下,我都可以调用对象的方法。我可以在单元之间编组我的接口(我正在使用全局接口 table),并且我可以在编组的接口上调用方法。
- 我收到的错误与我的异步接口的 IID ICallFactory in an apartment to which the interfaces have been marshaled. I can query for ICallFactory on the marshaled interface without any problem. But when I call CreateCall 具体相关,我收到错误 E_NOINTERFACE。
- 正如前面列表中提到的,只要最后注册的服务器是与客户端具有相同目标平台的服务器,我就不会收到此错误。
我现在正在尝试深入了解我的注册表,并弄清楚在进行注册时究竟发生了什么变化,但是由于注册表重定向器的存在,这并不是那么简单。我会在发现注册表信息时更新此 post。
想通了。
RegisterTypeLib 和 RegisterTypeLibForUser 在 运行 在 64 位 OS 上时总是写入 32 位和 64 位条目(即使进程是 32 位)。这在大多数情况下是完全可以接受的,因为它只是被写入的接口和类型库元数据。写入接口密钥时,RegisterTypeLib/RegisterTypeLibForUser 将 ProxyStubClsid32 设置为通用的默认值 p/s,这适用于接口类型(双重、oleautomation 等)。但是,通用 proxy/stubs 似乎不适用于自定义异步接口上的 ICallFactory。我修改了我的注册例程,以始终在 32 位和 64 位注册表项中设置我的自定义 proxy/stub 信息。这样可以确保以后的注册不会取代以前注册的信息。
[更新]:最后,由于可用 APIS 中的几个弱点,我不得不编写自己的注册程序:
- RegisterTypeLib 和 RegisterTypeLibForUser 不写入 AsynchronousInterface、SynchronousInterface 和 NumMethods 注册表项。这是因为编译类型库中没有显式链接同步和异步接口的信息。我自己的注册例程按名称匹配接口——它找到具有相应 AsyncIXxx 接口的 IXxx 接口(仅按名称,没有方法比较)并适当地设置这些注册表项。
- RegisterTypeLib 和 RegisterTypeLibForUser 始终写入 32 位和 64 位注册表项,包括但不限于 ProxyStubClsid32。这意味着通过这种方式注册类型库将覆盖以前通过其他方式编写的相反体系结构的任何 ProxyStubClsid32。要解决这个问题,可以先注册两个类型库(32 和 64),然后再注册 proxy/stub dll。然而:
- MIDL 编译器生成的 proxy/stub 代码似乎没有提供任何在每个用户注册表中注册 p/s 的方法。如果需要按用户注册,则生成的注册例程没有用。
- 即使生成的 proxy/stub 注册例程可以是每个用户,如果 proxy/stub 合并到 com 服务器 dll 中,也只有一个注册机会 -- 中的单个 DllRegisterServer单个dll。如果该例程仅在注册表的一侧写入 ProxyStubClsid32 条目(32 位或 64 位,而不是两者),则随后为另一个体系结构注册的 dll 将更改第一个体系结构的 ProxyStubClsid32。
- 我还没有测试过 CoRegisterPSClsid 等一些 API。由于文档没有说明每用户注册,我想它不受支持。