Background:
~~~~~~~~~~
COM exposes two sets of API functions to serialize an interface pointer into an apartment neutral representation.
1. CoMarshalInterThreadInterfaceInStream (and its counterpart for unmarshalling)
2. CoMarshalInterface (and its counterpart for unmarshalling)
The former is simply a wrapper around the latter.~~~~~~~~~~
COM exposes two sets of API functions to serialize an interface pointer into an apartment neutral representation.
1. CoMarshalInterThreadInterfaceInStream (and its counterpart for unmarshalling)
2. CoMarshalInterface (and its counterpart for unmarshalling)
CoMarshalInterface is the more primitive form and provides for optimizations to the serialized state based on the distance of the importing apartment (different apartment same process, different process same host, remote host)
A stream (into which the interface state is written) is just a blob of memory that's wrapped around by a COM object that implements the IStream interface to work with the stream. CoMarhalInterface expects it to be provided with such a stream, Though it is smart enough to allocate the buffer if the stream contains no memory.
Rewind the stream before unmarshalling an interface pointer:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
So I did a simple exercise to serialize an interface pointer into a stream and then deserializing it back into the same apartment (so i get a raw pointer back). The code is pretty straight forward. I was however having trouble unmarshalling the stream and was hitting errors that showed no indication of the real nature of the problem.
Here's the code: (Error checks ignored for brevity)
IStream *pStream = NULL;
HGLOBAL hGlobal = NULL; // CASE 1
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE,1000); // CASE 2
HRESULT hr = CreateStreamOnHGlobal(hGlobal,TRUE,&pStream);
ISafeObject *pSafeObject = static_cast
ISafeObject *pUnmarshaledSafeObject = NULL;
hr = CoUnmarshalInterface(pStream,__uuidof(ISafeObject), (void **)&pUnmarshaledSafeObject);
Case 1: I pass NULL as the HGLOBAL handle to CreateStreamOnHGlobal (assuming CoMarshalInterface should autoalloc)
Result : 0x8003001e A disk error occurred during a read operation.
Case 2: I allocate memory.
Result : 0x8001011d The marshaled interface data packet (OBJREF) has an invalid or unknown format.
It turned out that i had to unwind the stream to which CoMarshalInterface wrote to, before i could call CoUnmarshalInterface.
Sticking the following two lines of code fixed the problem.
// Before calling CoUnmarshalInterface
LARGE_INTEGER disp = {0};
pStream->Seek(disp,STREAM_SEEK_SET,NULL); // REWIND
Lesson learnt:
~~~~~~~~~~~~~
The next time (in the rare case) you ever need to use the CoMarshalInterface API for serializing interface pointers, remember to rewind the stream pointer before you rehydrate your serialized interface.