Click here to Skip to main content
15,894,825 members
Articles / Programming Languages / C++

Understanding Custom Marshaling Part 1

Rate me:
Please Sign up or sign in to vote.
4.97/5 (53 votes)
18 Aug 2006CPOL31 min read 208.5K   1.4K   147  
Learn the fundamental principles of COM custom marshaling by code examples.
#ifndef UTILITIES_H
  #define UTILITIES_H
  
#include <windows.h>
#include <vector>
using namespace std;

typedef vector<HANDLE>		HANDLE_VECTOR;

DWORD ThreadMsgWaitForSingleObject (HANDLE hHandle, DWORD dwMilliseconds);

DWORD ThreadMsgWaitForMultipleObjects 
(
  DWORD dwCount, 
  LPHANDLE pHandles, 
  BOOL bWaitAll, 
  DWORD dwMilliseconds
);

template <class SmartPtrClass>
bool _CoCreateInstance(LPCTSTR lpszProgID, SmartPtrClass& spSmartPtrReceiver)
{
  HRESULT			hrRetTemp = S_OK;
  _bstr_t			bstProgID(lpszProgID);
  CLSID				clsid;
  bool				bRet = false;
  
  hrRetTemp = CLSIDFromProgID
  (
    (LPCOLESTR)bstProgID,  //Pointer to the ProgID
    (LPCLSID)&clsid         //Pointer to the CLSID
  );

  if (hrRetTemp == S_OK)
  {
    hrRetTemp = spSmartPtrReceiver.CoCreateInstance(clsid);

	if (SUCCEEDED(hrRetTemp))
	{
	  bRet = true;
	}
	else
	{
	  bRet = false;
	}
  }

  return bRet;
}





/* LowLevelInProcMarshalInterface() uses low-level APIs       */
/* CreateStreamOnHGlobal(), CoMarshalInterface(), and IStream */
/* methods to perform interface pointer marshalling across    */
/* apartments in a process.                                   */
/*                                                            */
template <typename T>
LPSTREAM LowLevelInProcMarshalInterface(T* pInterface, REFIID riid)
{
  IUnknown*		pIUnknown = NULL;
  IStream*		pIStreamRet = NULL;

  /* QI the original interface pointer for its IUnknown interface. */
  pInterface -> QueryInterface (IID_IUnknown, (void**)&pIUnknown);

  /* Once we get the IUnknown pointer, we serialize it into a stream of bytes. */
  if (pIUnknown)
  {
    /* Create a Stream Object which will reside in global memory.   */
    /* We set the first parameter to NULL, hence indicating that    */
    /* we want CreateStreamOnHGlobal() to internally allocate       */
    /* a new shared memory block of size zero.                      */
	/* The second parameter is set to TRUE so that when the returned*/
	/* stream object is Release()'d, the global memory will also be */
	/* freed.                                                       */
    ::CreateStreamOnHGlobal
    (
      0,
      TRUE,
      &pIStreamRet
    );

    if (pIStreamRet)
    {
	  LARGE_INTEGER li = { 0 };

      /* We use the new stream object to store the marshalling data */
      /* of spISimpleCOMObject2.                                    */
      /* The use of MSHCTX_INPROC indicates that the unmarshaling   */
      /* of the data in the stream will be done in another apartment*/
      /* in the same process.                                       */
      ::CoMarshalInterface
      (
        pIStreamRet,
        riid,
        (IUnknown*)pIUnknown,
        MSHCTX_INPROC,
        NULL,
        MSHLFLAGS_NORMAL
      );

      /* Always reset the stream to the beginning.*/
	  pIStreamRet -> Seek(li, STREAM_SEEK_SET, NULL);
    }

	pIUnknown -> Release();
	pIUnknown = NULL;
  }

  return pIStreamRet;
}





/* LowLevelInProcUnmarshalInterface() uses low-level APIs     */
/* CoUnmarshalInterface(), CoReleaseMarshalData(), and        */
/* IStream methods to perform interface pointer unmarshalling */
/* for an apartment in a process.                             */
/*                                                            */
template <typename T>
void LowLevelInProcUnmarshalInterface(LPSTREAM pIStream, REFIID riid, T** ppInterfaceReceiver)
{
  /* Deserialize the byte contents of the IStream object */
  /* into an actual interface pointer to be used only    */
  /* within this thread.                                 */
  /*                                                     */
  /* The interface pointer will not be a direct pointer. */
  /* It will be a proxy to the original pointer.         */
  if (pIStream)
  {
	LARGE_INTEGER li = { 0 };
    
    /* Make sure stream pointer is at the beginning of the stream. */
	pIStream -> Seek(li, STREAM_SEEK_SET, NULL);

    if
	(
	  ::CoUnmarshalInterface 
	  (
        pIStream,  //Pointer to the stream
        riid,     //Reference to the identifier of the interface
        (void **)ppInterfaceReceiver      //Address of output variable that receives the 
                   // interface pointer requested in riid
      ) != S_OK
	)
	{
	  /* Since unmarshalling has failed, we call   */
	  /* CoReleaseMarshalData() to destroys the    */
	  /* previously marshaled data packet contained*/
	  /* in pIStream.                              */
	  ::CoReleaseMarshalData(pIStream);
	}

    /* When pIStream is Release()'d the underlying global memory*/
	/* used to store the bytes of the stream is also freed.     */
	pIStream -> Release();
	pIStream = NULL;
  }
}

#endif

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Systems Engineer NEC
Singapore Singapore
Lim Bio Liong is a Specialist at a leading Software House in Singapore.

Bio has been in software development for over 10 years. He specialises in C/C++ programming and Windows software development.

Bio has also done device-driver development and enjoys low-level programming. Bio has recently picked up C# programming and has been researching in this area.

Comments and Discussions