为什么在确实实现接口并且在Windows中具有内置marshaller时QueryInterface()会失败?

时间:2013-05-16 14:25:05

标签: c++ com marshalling atl com+

我有以下设置。 COM +中安装了一个COM服务器(在单独的进程中运行)并具有此接口定义:

[object, uuid("InterfaceIdHere"), nonextensible, oleautomation, hidden]
interface IMyInterface : IUnknown {
   HRESULT MyMethod( [in] IUnknown* param );
};

来电者称之为:

HRESULT callComObject(IStream* stream)
{
    return comObject->MyMethod(stream);
}

请注意,此处IStream*会隐式上传至IUnknown*。这样做是因为在IDL中声明类型为IStream*的参数会导致一些我现在无法回想起的问题。无论如何,它总是有效IStream*代替IUnknown*

COM服务器端具有MyMethod()的实现:

STDMETHODIMP CServer::MyMethod(IUnknown* param)
{
    if(param == 0) {
       return E_INVALIDARG;
    }   
    ATL::CComQIPtr<IStream> stream(param);
    if(stream == 0) {
       return E_INVALIDARG;// control passes HERE
    }
    // whatever
}

所以我在客户端传递了IStream* callComObject(),它被隐含地提升到IUnknown*,后者被传递给COM编组。已编组的IUnknown*在另一个进程中到达服务器并获得IUnknown*,然后QueryInterface()来自同一对象的IStream* QueryInterface()调用IStream*失败。

这看起来很疯狂,因为编组{{1}}应该始终有效 - 在Windows中预装了此接口的编组器。

为什么它可能无法工作,我如何找到原因?

3 个答案:

答案 0 :(得分:4)

与行为匹配的可能方案之一如下:

  • 你在来电者和被叫者之间没有任何争吵
  • 接口指针有效
  • 然而,实现IStream的对象没有相应的COM_INTERFACE_ENTRY映射条目并且不使接口可用,调用者可能已经通过非COM方式获得指针,例如,直接C ++演员

通过QueryInterface在呼叫之前调用呼叫方的流很容易检查。

此方案中的被调用方可以reinterpret_castIStream并且可以很好地工作。

答案 1 :(得分:2)

您可以将IDL导入objidl.idl,或者在您自己的IDL中手动定义IStream(和祖先)(只需确保使用标准IID值)。然后,您可以使用IStream而不是IUnknown作为参数类型,而不再担心QueryInterface()

答案 2 :(得分:1)

您可以将IDispatch替换为IUnknown作为方法的参数类型。在我看来,服务器实际上有一个存根而不是流本身,因为它在另一个进程中。

这只是猜测

我希望这会有所帮助

相关问题