Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Understanding Custom Marshaling Part 1

, 18 Aug 2006 CPOL
Learn the fundamental principles of COM custom marshaling by code examples.
custommarshaling01_src.zip
utilities
BasicSample01
Interfaces
Implementations
Clients
BasicSample01Interfaces
BasicSample01Interfaces.aps
BasicSample01Interfaces.def
BasicSample01Interfaces.ncb
BasicSample01Interfaces.rgs
BasicSample01Interfacesps.def
Immutable.rgs
ImmutableObjectFactory.rgs
BasicSample01Interfaces.vcproj.vspscc
BasicSample01InterfacesPS.vcproj.vspscc
BasicSample01InterfacesImpl
BasicSample01InterfacesImpl.aps
BasicSample01InterfacesImpl.def
BasicSample01InterfacesImpl.rgs
BasicSample01InterfacesImplps.def
ImmutableImpl.rgs
ImmutableObjectFactoryImpl.rgs
BasicSample01InterfacesImpl.ncb
BasicSample01InterfacesImpl.vcproj.vspscc
BasicSample01InterfacesImplPS.vcproj.vspscc
VCConsoleClient01
VCConsoleClient03
VCConsoleClient02
VCConsoleClient01.ncb
VCConsoleClient03.ncb
VCConsoleClient02.ncb
// 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)

Share

About the Author

Lim Bio Liong
Web Developer
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.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141223.1 | Last Updated 18 Aug 2006
Article Copyright 2006 by Lim Bio Liong
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid