COM 进程运行起来但只有 IUnknown 是可查询的

COM process runs up but only IUnknown is queryable

我的处境有点奇怪。我创建了一个 COM 服务器(.exe 模块)并注册了它;我可以在我的注册表中看到条目。

此服务器注册了一个 class id,当进程启动时,它会根据该 id 注册一个支持自定义接口的对象 ISomething:

//rough pseudo code
MyClass : public ISomething { ... };

main(){
 ::CoInitialize(NULL);
 MyClass obj;
 CoRegisterClassObject(ClassId, (ISomething *)&obj, ...);
 ...
}

当我尝试从测试应用程序中使用 IUnknown 共同创建 clsid 时,COM 进程运行起来并且我得到一个非 NULL IUnknown 指针。

但是如果我尝试使用 ISomething 进行共同创建,我会得到 E_NOINTERFACE

请注意此代码设置已经过许多模块的尝试和测试,它基本上是复制粘贴的。所以我认为问题是 registry/configuration 一个。

我在 "clean" 开发 PC 上,所以我唯一注册的是链接到 ClassId.

的 COM.exe

我还需要 ISomething 注册的问题吗? Roman R 在他的回答中提到了代理存根(在我编辑我的问题之前),我想知道这是否是问题所在...是否需要注册每个接口以及组件的 class ID?

您的 .EXE 托管的 COM 服务器是进程外服务器。使用它的接口,您可以从另一个进程访问服务器:您不直接与服务器对话,而是与为您创建的 COM 子系统的代理对话。

客户端进程:你的客户端代码 -> Proxy -> (Magic)

服务器进程:(魔法)-> 存根 -> 您的服务器代码

好吧,proxy/stub 也是魔法的一部分,但我将它们分开是为了帮助理解客户端代码是与有形但还不是真实服务器的接口。

代理、存根和其他魔法创建一个模仿您的客户端代码请求的 COM 接口,然后将调用转发到真实服务器,然后取回数据。他们只能做 "marshalable" 的接口,其中存在编组代码,其中 proxy/stub 对创建是可能的。

不是每个接口都可以编组的,最后就出现了服务端实现了一个接口,你肯定知道,客户端还是获取不到的情况。

如何完成封送处理有几个选项,使用 ATL 完成任务的最简单方法是确保:

  • 接口派生自IDispatch,在类型库中被标记为oleautomation
  • 该接口位于 IDL 代码的库部分,或者以其他方式包含在 TLB 文件中,并且在使用 OleView 检查时在您的 EXE 中可见
  • COM 服务器 (EXE) 注册良好并且您的 COM 对象正确实现接口(COM_MAP 条目等)

在这种情况下,您正在利用 OLE 自动化接口的标准封送拆收器(也称为 PSOAInterface),并且无需任何额外的努力就可以为您创建 proxy/stub 对。

您可能想在此处查看一些代码片段:http://diranieh.com/ATLCOM/IDL.htm

尝试在调用 QueryInterface() 之前调用 OleRun()。如果该对象不在进程中,则您只是在与处理程序对象对话。 EXE 可能甚至不是 运行。调用 OleRun 将导致它加载。那么查询接口的可能性更大。