2

我有以下设置。有一个 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*. 这样做是因为IStream*在 IDL 中声明类型参数会导致一些我现在无法回忆的问题。无论如何,它总是一个有效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 编组器。marshalledIUnknown*在另一个进程中到达服务器并IUnknown*获得,然后从同一个对象QueryInterface()调用 marshallIStream*并且QueryInterface()失败。

这看起来很疯狂,因为编组IStream*应该在任何时候都可以工作——Windows 中预装了一个用于该接口的编组器。

为什么它可能不起作用,我该如何找到原因?

4

3 回答 3

4

与行为匹配的可能场景之一如下:

  • 你在调用者和被调用者之间没有任何编组
  • 接口指针有效
  • 但是实现的对象IStream没有相应的COM_INTERFACE_ENTRY映射条目并且没有使接口可用,调用者可能已经通过非 COM 方式获得了指针,例如直接 C++ 强制转换

这很容易通过QueryInterface在调用之前在调用方的流中进行检查。

这种情况下的被调用者可以让它很好reinterpret_castIStream工作。

于 2013-05-16T14:33:22.593 回答
2

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

于 2013-05-16T15:37:52.583 回答
1

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

这只是一个猜测

我希望这有帮助

于 2013-05-16T14:39:00.227 回答