Search code examples
c++comrpcinproc

Unwillingly calling QueryInterface via RPC


In my application, I create an object A, that creates an object B, both via CreateInstance. Both objects should live in the same process.

Now I see that object B, when asked for a certain interface, is returning E_NOINTERFACE, although I defined it in the COM_MAP:

class B:
{
    // ....
BEGIN_COM_MAP(B)
    COM_INTERFACE_ENTRY(IB)
    COM_INTERFACE_ENTRY(IDispatch)
    COM_INTERFACE_ENTRY(IXXX) // the interface I'm interested in
END_COM_MAP()
    // .....
};

And the A code:

#define FORWARD_ERROR( expr ) { hr=expr; if( !SUCCEEDED( hr ) ) return hr;}
IBPtr b;
FORWARD_ERROR( b.CreateInstance( __uuidof( B ), 0, CLSCTX_INPROC_SERVER ) );

IXXXPtr x;
HRESULT hrIf = b.QueryInterface( __uuidof( IXXX ), x );
// ===> now x is NULL, and hrIf contains E_NOINTERFACE

When I debug this, and put a breakpoint in the COM_MAP, I don't see my source code in the lowest frame, but some ole32.dll's CRpcThread::WorkerLoop.

I have no clue how I indicated that the QueryInterface should be called via OLE and RPC. Any ideas?


Solution

  • From you description it was definitely marshalling kicking in. Marshalling is done by tunnelling calls through RPC so it looks rather weird, but that's how it is done on Windows.

    The consumer thread likely called CoInitializeEx() with COINIT_APARTMENTTHREADED. Since the object to create was marked as Free it couldn't have been created in the caller's apartment (see this very good explanation on apartments). Instead COM tried to turn marshalling on and you likely haven't anything to facilitate marshalling and in such cases CoCreateInstance() return E_NOINTERFACE because COM inner workings request a bunch of interfaces it would use for marshalling and once all those requests fail it ends up with E_NOINTERFACE and returns it which is of course not convenient for you at all.

    Then you changed from Free to Both which means "Apartment of Free as COM sees fit" COM is officially allowed to put the object into the same apartment as the caller and no marshalling is required and so you don't see that weird looking error code anymore.