Click here to Skip to main content
15,886,072 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 206.8K   1.4K   147  
Learn the fundamental principles of COM custom marshaling by code examples.
// ImmutableImpl.h : Declaration of the CImmutableImpl

#pragma once
#include "resource.h"       // main symbols

#include "BasicSample01InterfacesImpl.h"


// CImmutableImpl

class ATL_NO_VTABLE CImmutableImpl : 
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<CImmutableImpl, &CLSID_ImmutableImpl>,
	public IDispatchImpl<IImmutableImpl, &IID_IImmutableImpl, &LIBID_BasicSample01InterfacesImplLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
	public IDispatchImpl<IImmutable, &__uuidof(IImmutable), &LIBID_BasicSample01InterfacesLib, /* wMajor = */ 1, /* wMinor = */ 0>,
	public IMarshal
{
public:
	CImmutableImpl() :
	  m_lLongValue(0)
	{
	}
	
	~CImmutableImpl()
	{
	}	

	DECLARE_REGISTRY_RESOURCEID(IDR_IMMUTABLEIMPL)


	BEGIN_COM_MAP(CImmutableImpl)
	    COM_INTERFACE_ENTRY(IMarshal)
		COM_INTERFACE_ENTRY(IImmutableImpl)
		COM_INTERFACE_ENTRY2(IDispatch, IImmutable)
		COM_INTERFACE_ENTRY(IImmutable)
	END_COM_MAP()


	DECLARE_PROTECT_FINAL_CONSTRUCT()

	HRESULT FinalConstruct()
	{
		return S_OK;
	}

	void FinalRelease() 
	{
	}

public:


	// IImmutable Methods
public:
	STDMETHOD(get_LongValue)(long * pVal)
	{
	    *pVal = m_lLongValue;
	    
		return S_OK;
	}
	
	// IMarshal Methods.
	/*! IMarshal implementation.
	The CoMarshalInterface() API will call GetUnmarshalClass()
	Here, we will indicate to CoMarshalInterface() the CLSID
	of the object that will take charge of unmarshaling
	the interface pointers of this current object.
	*/
	STDMETHOD(GetUnmarshalClass) (REFIID riid, void * pv, DWORD dwDestContext, void * pvDestContext, DWORD mshlFlags, CLSID* pCid )
	{
	    // The class that will perform the unmarshaling will be
	    // this class itslf.
	    *pCid = GetObjectCLSID();

		return S_OK;
	}
	
	/*!
	The CoMarshalInterface() API will call GetMarshalSizeMax().
	Here, we will indicate to CoMarshalInterface() the total 
	size of the marshaled object reference.\n
	
	The marshaled object reference will end up being serialized
	and marshaled across to a target apartment.\n
	
	It should contain information that will help the proxy 
	to uniquely identify and establish connection with this object
	in order to invoke its properties and methods.\n
	
	*/
	STDMETHOD(GetMarshalSizeMax) (REFIID riid, void * pv, DWORD dwDestContext, void * pvDestContext, DWORD mshlFlags, ULONG* pSize )
	{
		HRESULT hr = S_OK;

		*pSize = sizeof(CImmutableMarshaledObjectReferenceStruct);

		return hr;
	}

	STDMETHOD(MarshalInterface)  (IStream* pStm, REFIID riid, void *pv, DWORD dwDestContext, void * pvDestContext, DWORD mshlFlags)
	{		    
	    if (dwDestContext != MSHCTX_INPROC)
	    {
	      return E_FAIL;
	    }
	    
	    CImmutableMarshaledObjectReferenceStruct ImmutableMarshaledObjectReferenceStruct;
	    
	    ImmutableMarshaledObjectReferenceStruct.lLongValue = m_lLongValue;
	    
	    *pStm << ImmutableMarshaledObjectReferenceStruct;
	    
	    return S_OK;
	}

	// It is the Proxy which will perform the UnmarshalInterface().
	// The object itself is the proxy and so during UnmarshalInterface(),
	// it is re-constructed from the input marshaling object reference
	// contained inside pStm.
	STDMETHOD(UnmarshalInterface)(IStream* pStm, REFIID riid, void ** ppv )
	{
	    CImmutableMarshaledObjectReferenceStruct	ImmutableMarshaledObjectReferenceStruct;
		
		*pStm >> (CImmutableMarshaledObjectReferenceStruct&)ImmutableMarshaledObjectReferenceStruct;

		m_lLongValue = ImmutableMarshaledObjectReferenceStruct.lLongValue;
		
		return QueryInterface(riid, ppv);
	}

    // This method is COM's way of indicating to an object (which has been marshaled) 
    // that a marshaled object packet is being destroyed. 
    // A marshaled object reference can be considered an additional reference
    // to an object. Hence, a call to ReleaseMarshalData() should signal 
    // an object to perform reference count state management.
    //
    // However it is not significant in our basic example, as will be the case for most 
    // "Marshal-by-value" proxies. This is because a "Marshal-by-value" proxy is independent
    // of its original object.
	STDMETHOD (ReleaseMarshalData)(IStream *pStm)
	{
		return S_OK;
	}
    
    // The usual case in which this method is called occurs when an end user 
    // forcibly closes a COM server (usually an EXE server) that has one or 
    // more running objects that implement IMarshal. 
    //
    // Under normal circumstances too, prior to shutting down, the server 
    // needs to call the CoDisconnectObject() helper function to release 
    // external connections to all its running objects. 
    // For each object that implements IMarshal, however, this function calls 
    // IMarshal::DisconnectObject() so that each object that manages its own 
    // marshaling can take steps to notify its proxy that it is about to 
    // shut down.
    //
    // The outcome of any implementation of this method should be to enable 
    // a proxy to respond to all subsequent calls from its client by returning 
    // RPC_E_DISCONNECTED or CO_E_OBJECTNOTCONNECTED rather than attempting 
    // to forward the calls on to the original object. Note that it is up to 
    // the client to destroy the proxy.
    //
    // Because CImmutableImpl is an immutable object, its implementation doesn't 
    // need to do anything because its instances will be copied whole into the 
    // client's address space. Therefore, they have neither a proxy nor a connection 
    // to the original object.
    // 
    STDMETHOD (DisconnectObject)(DWORD dwReserved)
	{
		return S_OK;
	}			

protected :
	long			m_lLongValue;

// Non-COM public methods.
public :
	void			SetLongValue(long lLongValue)
	{
	  m_lLongValue = lLongValue;
	}	
};

OBJECT_ENTRY_AUTO(__uuidof(ImmutableImpl), CImmutableImpl)

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