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

Understanding Custom Marshaling Part 1

, 18 Aug 2006
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
// VCConsoleClient02.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;
  LPSTREAM*		plpStreamReceiver = (LPSTREAM*)lpvParameter;

  // This thread will be thread of an STA.
  ::CoInitialize(NULL);
  
  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)
  {
	// When CoMarshalInterThreadInterfaceInStream() is called on spIImmutable,
	// COM will attempt to get a proxy to spIImmutable and to get the 
	// marshaled data packet from the original object.
	// The following sequence of function calls will take place :
	// 
	// CImmutableImpl::GetUnmarshalClass()
	// CImmutableImpl::GetMarshalSizeMax()
	// CImmutableImpl::MarshalInterface()
	// 
    CoMarshalInterThreadInterfaceInStream
    (
      __uuidof(IImmutablePtr),
      pIUnknown,
      plpStreamReceiver
    );
      
	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);
  }
    
  ::CoUninitialize();
  
  return 0;
}





void ExamineStream(LPSTREAM& lpStream)
{
  LPBYTE  lpbyStreamData = NULL;
  STATSTG statstg;
    
  memset (&statstg, 0, sizeof(statstg));

  lpStream -> Stat
  (
    (STATSTG*)&statstg,
    STATFLAG_DEFAULT
  );
    
  lpbyStreamData = new BYTE[(size_t)(statstg.cbSize.LowPart)];
  memset (lpbyStreamData, 0, (size_t)(statstg.cbSize.LowPart));
  if (lpbyStreamData)
  {
    MarshalDataPacket marshal_data_packet;
    
    memset (&marshal_data_packet, 0, sizeof(marshal_data_packet));
    
    lpStream -> Read
    (
      (void*)lpbyStreamData,
      statstg.cbSize.LowPart,
      NULL
    );
    
    memcpy((void*)&marshal_data_packet, (void*)lpbyStreamData, sizeof(marshal_data_packet));
      
    delete [] lpbyStreamData;
    lpbyStreamData = NULL;
  }
    
  LARGE_INTEGER li;
    
  memset (&li, 0, sizeof(li));
  lpStream -> Seek
  (
    li,
    STREAM_SEEK_SET ,
    NULL
  );
}





void Demonstrate_Cross_Apartment_Call_Via_Stream()
{
  HANDLE		hThread = NULL;
  DWORD			dwThreadId = 0;
  long			lLongValue = 0;
  LPSTREAM		lpStream = NULL;
  IImmutablePtr spIImmutable = NULL;
    
  hThread = CreateThread
  (
    (LPSECURITY_ATTRIBUTES)NULL,
    (SIZE_T)0,
    (LPTHREAD_START_ROUTINE)ThreadFunc_CustomMarshaledObject,
    (LPVOID)(&lpStream),
    (DWORD)0,
    (LPDWORD)&dwThreadId
  );

  ThreadMsgWaitForSingleObject(g_hInterfaceMarshaled, INFINITE);

  ResetEvent(g_hInterfaceMarshaled);
  
  ExamineStream(lpStream);

  // Construct a proxy to the IImmutable interface from the stream.  
  //																 
  // When CoGetInterfaceAndReleaseStream() is called on a marshaled  
  // data packet stream, COM will attempt to get the IImmutable		 
  // interface from spIImmutable and import it into the current      
  // apartment.	                                                     
  // The following sequence of function calls will take place :      
  //															     
  // CImmutableImpl()	(part of proxy construction)			     
  // CImmutableImpl::FinalConstruct() (part of proxy construction)   
  // CImmutableImpl::UnmarshalInterface()							 
  //																 
  // The Marshal Data Packet is contained inside the stream.	     
  // All COM needs is a new Proxy object to which it passes		     
  // the Marshal Data Packet (in the UnmarshalInterface()			 
  // method call).												     
  CoGetInterfaceAndReleaseStream
  (
    lpStream,
    __uuidof(IImmutablePtr),
    (LPVOID*)&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_Stream();
    
    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 | Mobile
Web03 | 2.8.140916.1 | Last Updated 18 Aug 2006
Article Copyright 2006 by Lim Bio Liong
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid