即使找到接口,CoCreateInstance也会返回E_NOINTERFACE
我有一个 COM 类 CMyCOMServer
在一个应用程序中实现 IMyInterface
,两者都具有正确的 GUID。如果请求 IUnknown 或 IMyInterface,CMyCOMServer::QueryInterface
将返回 S_OK(并将自身转换为正确的类型),否则返回 E_NOINTERFACE。
在同一台 PC 上的另一个应用程序中,我调用:
HRESULT hr = ::CoCreateInstance(__uuidof(CMyCOMServer), 0, CLSCTX_SERVER,
__uuidof(IMyInterface ),(void **)&pInterface);
它返回 E_NOINTERFACE。所以我假设我做错了什么,并在 CMyCOMServer::QueryInterface
上添加了一个断点。我发现,当调用 CoCreateInstance
时,QueryInterface
会针对不同的接口多次触发:
- 首先,请求 IUnknown - 没问题
- 然后,请求 IMarshall 等多个接口。不支持这些,因此返回 E_NOINTERFACE
- 最后,请求 IMyInterface。我验证 QueryInterface 返回 S_OK 并将
(IMyInterface *)this
设置为接口指针,如预期
所以我的困惑是为什么调用 CoCreateInstance 给我留下一个 NULL 指针并返回 E_NOINTERFACE 代码,当 COM 服务器应用程序显然返回了我要求的界面?
编辑:我的客户端应用程序在启动时调用 CoInitialize(NULL) ,这没有什么区别。
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.
In another app on the same PC, I call:
HRESULT hr = ::CoCreateInstance(__uuidof(CMyCOMServer), 0, CLSCTX_SERVER,
__uuidof(IMyInterface ),(void **)&pInterface);
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:
- 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
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?
EDIT: my client app calls CoInitialize(NULL) at startup, this makes no difference.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果您的 COM 服务器运行在不同的进程中,或者同一进程中的不同单元中,则当您调用接口时,COM 需要知道如何打包和传输参数。这个过程称为“编组”。
如果定义自定义接口,则需要使用以下方法之一为其实现封送。
以及您必须在系统上注册的存根。这可能是最好的选择,因为您已经定义了接口。
自定义界面并使用
marshaller 已经是的一部分
COM 框架
当您调试 COM 服务器时,尽管您看到在对 QueryInterface 的调用中返回了自定义接口,但它并没有使其跨越整个 COM 框架。进程边界,因为 COM 无法弄清楚如何封送该接口,因此客户端会看到 E_NOINTERFACE。
更新(根据您的评论)
如果这是一个现有的 COM 服务器应用程序,那么您可能已经有一个代理/存根。您需要在客户端和服务器上注册它。是否可能是您在新机器上测试此功能而只是忘记注册此功能?要注册,您只需在 proxy/stub dll 上执行 regsvr32 即可。
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.
and stub which you must register on the system. This is probably the best option since you have already defined your interface.
custom interface and use the
marshaller which is already part of
the COM framework
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.
UPDATE (based on your comment)
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.
发生这种情况是因为 COM 子系统尝试封送您的自定义接口 (IMyInterface),但根本不知道如何执行此操作。发生这种情况的原因要么是服务器在进程外,要么是因为服务器在进程内,并且调用 CoCreateInstance() 的消费者应用程序的线程错误地调用了 CoInitialize()/ CoInitializeEx(),因此如上所述请求“多线程单元”在文章用户托马斯在另一个答案中提到。
如果您只需要一个进程内服务器,则可以通过确保调用 CoCreateInstance() 的线程使用 COINIT_APARTMENTTHREADED 调用 CoInitialize() 或 CoInitializeEx() 来强制执行“单线程单元”来抑制编组。
如果您需要进程外服务器,则无法绕过编组。在后一种情况下,您可以执行以下操作之一:
This happens because COM subsystem tries to marshal your custom interface (IMyInterface) and simply has no idea how to do that. That happens either because the server is out-proc or because the server is in-proc and the thread of the consumer application that calls CoCreateInstance() has called CoInitialize()/ CoInitializeEx() incorrectly so that "multithreaded apartment" is requested as mentioned in the article user Thomas refers to in the other answer.
If you only need an in-proc server you could suppress marshalling by ensuring that the thread calling CoCreateInstance() either calls CoInitialize() or CoInitializeEx() with COINIT_APARTMENTTHREADED to enforce "single-threaded apartment".
If you need an out-proc server you can't get around marshalling. In the latter case you could do one of the following:
这可能是 Raymond Chen 写的线程模型问题?
编辑回复评论:
实际上,它更多的是关于线程模型而不是编组。
Could this be the threading model problem that Raymond Chen wrote about?
Edit in reply to the comment:
It's more about threading models than about marshalling, really.
之前关于
E_NOINTERFACE
因为缺少编组接口而返回的评论非常有帮助,然而,
对于我们来说,答案/修复是强制主应用程序(调用 CoCreateInstance 的应用程序)成为 STA(单线程单元),这是通过设置高级链接器来完成的选项,即:
或在链接命令行上执行以下操作:
这可以防止 MTA 和 STA 混合,从而导致跨线程调用。
希望其他人觉得这有帮助。
The previous comments about
E_NOINTERFACE
returned because marshalling interface is missing was very helpful,however,
for us the answer/fix was to force the main application (the one calling
CoCreateInstance
) to beSTA
(single threaded apartment), and this was done by setting an advanced linker option, i.e.:or on the link command line you do:
This prevents a mix of MTA and STA, which causes a call across threads.
Hope someone else finds this helpful.