即使找到接口,CoCreateInstance 也会返回 E_NOINTERFACE

2022-01-14 00:00:00 windows com visual-c++ c++ com-interop

我有一个 COM 类 CMyCOMServer 在一个应用程序中实现 IMyInterface,两者都具有正确的 GUID.如果请求 IUnknown 或 IMyInterface,CMyCOMServer::QueryInterface 将返回 S_OK(并将自身转换为正确的类型),否则返回 E_NOINTERFACE.

I have a COM class CMyCOMServer implementing IMyInterface in one application, both with correct GUIDs. CMyCOMServer::QueryInterface will return S_OK (and cast itself to the right type) if IUnknown or IMyInterface is requested, otherwise it returns E_NOINTERFACE.

在同一台 PC 上的另一个应用程序中,我调用:

In another app on the same PC, I call:

HRESULT hr = ::CoCreateInstance(__uuidof(CMyCOMServer), 0, CLSCTX_SERVER,
 __uuidof(IMyInterface ),(void **)&pInterface);

它返回 E_NOINTERFACE.所以我认为我做错了什么并在 CMyCOMServer::QueryInterface 上添加了一个断点.我发现当调用CoCreateInstance时,QueryInterface会针对不同的接口触发多次:

It returns E_NOINTERFACE. So I assumed I was doing something wrong and added a breakpoint on CMyCOMServer::QueryInterface. I found that when CoCreateInstance is called, QueryInterface is triggered several times for different interfaces:

  • 首先,请求 IUnknown - 没问题
  • 然后,请求了几个接口,如 IMarshall 等……不支持这些接口,因此返回 E_NOINTERFACE
  • 最后,请求 IMyInterface.我验证 QueryInterface 返回 S_OK 并将 (IMyInterface *)this 设置为接口指针,正如预期的那样
  • First, IUnknown is requested - no problem
  • Then, several interfaces like IMarshall etc are requested... these are not supported so E_NOINTERFACE is returned
  • Finally, IMyInterface is requested. I verify QueryInterface returns S_OK and sets (IMyInterface *)this as the interface pointer, as expected

所以我的困惑是为什么调用 CoCreateInstance 给我一个 NULL 指针并返回 E_NOINTERFACE 代码,而 COM 服务器应用程序显然返回了我要求的接口?

So my confusion is why the calling CoCreateInstance is leaving me a NULL pointer and return code of E_NOINTERFACE, when the COM server app is clearly returning the interface I ask for?

我的客户端应用程序在启动时调用 CoInitialize(NULL),这没有区别.

my client app calls CoInitialize(NULL) at startup, this makes no difference.

推荐答案

如果你的COM服务器运行在不同的进程中,或者同一个进程的不同单元,COM在制作的时候需要知道如何打包和传递参数调用您的界面.此过程称为编组".

If your COM server is running in a different process, or a different apartment in the same process, COM needs to know how to package and transmit parameters when you make calls to your interface. This process is called "marshaling".

如果您定义自定义接口,则需要使用以下方法之一为其实现编组.??

If you define a custom interface, you need to implement marshaling for it using one of the following approaches.

  • 标准编组:让 MIDL 编译器生成代理和存根,您必须在系统上注册.这可能是最好的选择,因为您已经定义了界面.
  • OLE 自动化编组:您定义一个自动化兼容自定义界面并使用marshaller 已经是COM 框架
  • 自定义编组:您实现 IMarshal 的方法
  • Standard marshaling: have the MIDL compiler to generate a proxy and stub which you must register on the system. This is probably the best option since you have already defined your interface.
  • OLE Automation marshaling: you define an automation compatible custom interface and use the marshaller which is already part of the COM framework
  • Custom marshaling: you implement the methods of IMarshal

当您调试 COM 服务器时,虽然您看到在对 QueryInterface 的调用中返回了您的自定义接口,但它并没有跨越进程边界,因为 COM 无法弄清楚如何编组该接口,因此客户端看到 E_NOINTERFACE.

When you are debugging your COM server, although you see that you are returning your custom interface in the call to QueryInterface, it does not make it across the process boundary because COM cannot figure out how to marshal that interface, hence the client sees E_NOINTERFACE.

更新(根据您的评论)

如果这是一个现有的 COM 服务器应用程序,那么您可能已经有一个代理/存根.您需要在客户端和服务器上注册它.会不会是你在一台新机器上测试它而你只是忘记注册了?要注册,您只需在代理/存根 dll 上执行 regsvr32.

If this is an existing COM server app then you probably already have a proxy/stub. You need to register this on both the client and server. Could it be that you were testing this on a new machine(s) and you simply forgot to register this? To register you simply do regsvr32 on the proxy/stub dll.

相关文章