Click here to Skip to main content
15,887,683 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 207.2K   1.4K   147  
Learn the fundamental principles of COM custom marshaling by code examples.
// VCConsoleClient03.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

// Global event object handle that will be signalled when 
// an interface of a custom marshaled object has been
// marshaled into a stream. This will signal a receiving 
// thread that unmarshaling can now be performed.
HANDLE g_hInterfaceMarshaled = NULL;

DWORD WINAPI ThreadFunc_CustomMarshaledObject(LPVOID lpvParameter)
{
  MSG						msg;
  long						lLong = 0;
  IGlobalInterfaceTable*	pIGlobalInterfaceTable = NULL;
  DWORD						dwGITCookie = 0;
  DWORD*					pdwGITCookieReceiver = (DWORD*)lpvParameter;

  // This thread will be thread of an STA.
  ::CoInitialize(NULL);
  
  // There is a single instance of the global interface 
  // table per process.                                 
  // Hence all calls in a process to create it will     
  // return the same instance.                          
  CoCreateInstance
  (
    CLSID_StdGlobalInterfaceTable,
    NULL,
    CLSCTX_INPROC_SERVER,
    IID_IGlobalInterfaceTable,
    (void **)&pIGlobalInterfaceTable
  );
  
  if (pIGlobalInterfaceTable)
  {
    IImmutableObjectFactoryPtr	spIImmutableObjectFactory = NULL;
    IImmutablePtr				spIImmutable = NULL;
    IUnknown*					pIUnknown = NULL;
    
    // Create an instance of the COM object which has ProgID 
    // "BasicSample01InterfacesImpl.ImmutableObjectFactoryImpl" and manage it
    // via its IImmutableObjectFactory interface.
    // Now, because the resultant object (spIImmutableObjectFactory) is an STA object,
    // and this thread is an STA thread, spIImmutableObjectFactory will live in the 
    // same STA as this thread.
    _CoCreateInstance("BasicSample01InterfacesImpl.ImmutableObjectFactoryImpl", spIImmutableObjectFactory);
    
    // Get the IImmutable object from spIImmutableObjectFactory.
    // Now because spIImmutable is also an STA object, it will live in the
    // same STA as this thread.
    spIImmutableObjectFactory -> CreateObject(101, (IImmutable**)&spIImmutable);

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

    if (pIUnknown)
    {
	  // Register this interface pointer in the GIT.    
	  // 
	  // No need to call pIUnknown -> AddRef().     
	  // Another thread can retrieve the pIUnknown  
	  // using the cookie.                          
	  //
	  // When RegisterInterfaceInGlobal() is called on 
	  // the IImmutable interface, COM will attempt to 
	  // get a marshal data packet from the underlying object
	  // and then store it into the GIT. An associated 
	  // cookie will be returned.
	  //
	  // The following sequence of function calls will take place :
	  // 
	  // CImmutableImpl::GetUnmarshalClass()
	  // CImmutableImpl::GetUnmarshalClass()
	  // CImmutableImpl::GetMarshalSizeMax()
	  // CImmutableImpl::MarshalInterface()
	  // 
      pIGlobalInterfaceTable -> RegisterInterfaceInGlobal
	  (
        pIUnknown,
        __uuidof(IImmutablePtr),
        &dwGITCookie
      );
      
      *pdwGITCookieReceiver = dwGITCookie;

	  pIUnknown -> Release();
	  pIUnknown = NULL;

      if (g_hInterfaceMarshaled)
      {
        SetEvent(g_hInterfaceMarshaled);
      }
    }

    // Dispatch all windows messages in queue.
    while (GetMessage(&msg, NULL, 0, 0))
    {
      TranslateMessage (&msg);
      DispatchMessage(&msg);
    }
    
    pIGlobalInterfaceTable -> RevokeInterfaceFromGlobal(dwGITCookie);

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

  ::CoUninitialize();
  
  return 0;
}





void Demonstrate_Cross_Apartment_Call_Via_GIT()
{
  HANDLE					hThread = NULL;
  DWORD						dwThreadId = 0;
  DWORD						dwGITCookie = 0;
  long						lLongValue = 0;
  IGlobalInterfaceTable*	pIGlobalInterfaceTable = NULL;

  // There is a single instance of the global interface 
  // table per process.                                 
  // Hence all calls in a process to create it will     
  // return the same instance.                          
  CoCreateInstance
  (
    CLSID_StdGlobalInterfaceTable,
    NULL,
    CLSCTX_INPROC_SERVER,
    IID_IGlobalInterfaceTable,
    (void **)&pIGlobalInterfaceTable
  );
  
  if (pIGlobalInterfaceTable)
  {
    IImmutablePtr spIImmutable = NULL;
    
    hThread = CreateThread
    (
      (LPSECURITY_ATTRIBUTES)NULL,
      (SIZE_T)0,
      (LPTHREAD_START_ROUTINE)ThreadFunc_CustomMarshaledObject,
      (LPVOID)(&dwGITCookie),
      (DWORD)0,
      (LPDWORD)&dwThreadId
    );

    ThreadMsgWaitForSingleObject(g_hInterfaceMarshaled, INFINITE);

    ResetEvent(g_hInterfaceMarshaled);

    // Retrieve the interface pointer from the GIT.					 
	// What is returned is actually a proxy to the					 
	// original interface pointer created in the					 
	// ThreadFunc_CustomMarshaledObject() function.												 
	//
	// The Marshal Data Packet is already in the GIT.				 
	// All COM needs is a new Proxy object to which it passes		 
	// the Marshal Data Packet (in the UnmarshalInterface()			 
	// method call).												 
    //	
	// When GetInterfaceFromGlobal() is called on dwGITCookie,       
	// COM will attempt to create a proxy for the IImmutable
	// object, get its marshal data packet from the GIT
	// and then pass the packet to the proxy in order 
	// for the proxy to initialize itself.
	//
	// These actions have the collective effect of importing
	// the IImmutable interface pointer from the STA,
	// in which ThreadFunc_CustomMarshaledObject() runs,
	// to the current STA.
	//
	// The following sequence of function calls will take place :    
	//															     
	// CImmutableImpl()	(part of proxy construction)			     
	// CImmutableImpl::FinalConstruct() (part of proxy construction) 
	// CImmutableImpl::UnmarshalInterface()							 
	//																 
	pIGlobalInterfaceTable -> GetInterfaceFromGlobal
	(
      dwGITCookie,
      __uuidof(IImmutablePtr),
	  (void**)&spIImmutable
    );

    if (spIImmutable)
    {   
      spIImmutable -> get_LongValue(&lLongValue);        
    }
  }

  PostThreadMessage(dwThreadId, WM_QUIT, 0, 0);

  ThreadMsgWaitForSingleObject(hThread, INFINITE);

  CloseHandle (hThread);

  hThread = NULL;
}

int _tmain(int argc, _TCHAR* argv[])
{
    ::CoInitialize(NULL);
    
    g_hInterfaceMarshaled = CreateEvent(NULL, TRUE, FALSE, NULL);
    
    Demonstrate_Cross_Apartment_Call_Via_GIT();
    
    if (g_hInterfaceMarshaled)
    {
      CloseHandle(g_hInterfaceMarshaled);
	  g_hInterfaceMarshaled = NULL;
    }

    ::CoUninitialize();
    
	return 0;
}

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