Click here to Skip to main content
15,886,608 members
Articles / Desktop Programming / MFC

The Ultimate TCP/IP Home Page

Rate me:
Please Sign up or sign in to vote.
4.98/5 (77 votes)
25 Aug 2007CPOL13 min read 2.6M   45.4K   267  
Ultimate TCP-IP is now Open Source
//=================================================================
//  class: CMarshalEvents
//  File:  MarshalEvents.h
//
//  Finger ActiveX control event sink marshalling
//
//=================================================================
// Ultimate TCP/IP v4.2
// This software along with its related components, documentation and files ("The Libraries")
// is � 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement").  Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office.  For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
//=================================================================

#if !defined(AFX_MARSHALEVENTS_H__B63A9000_ED4F_11D2_A443_0080C858F182__INCLUDED_)
#define AFX_MARSHALEVENTS_H__B63A9000_ED4F_11D2_A443_0080C858F182__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

// Event sinks Marshaled inteface list item
typedef struct MarshalInterfaceTag{
    IStream		*pStream;				// IStream inteface were IDispatch was marshaled
	IDispatch	*pDispatch;				// Original IDispatch interface
	IDispatch	*pMarshaledDispatch;	// UnMarshaled IDispatch interface

    MarshalInterfaceTag *pNext;			// Pointer to the next item
	} MarshalInterface;


/***************************************************
	Events are signaled by calling the Invoke method 
	of an IDispatch interface supplied by container.
	The interface lives in the appartment of its own 
	thread, which is also the one containing the control
	itself. To comply with the STA model, we can only 
	safely call this interface's methods from the thread 
	in which it was created. If the control wants to 
	signal an event from a different thread it must
	Marshal the IDispatch interface into the IStream
	first and then UnMarshal it.

	class T	- object class
	piid	- IDispatch interface of the object events

	bMultipleStreamUse	- TRUE if we are going to signal 
		events from more than one thread. In this case,
		we dont release the IStream interface after
		UnMarshaling becase we need to do that in each
		thread.

	The Fire_XXXX methods of the proxy (CProxy_XXXX<class T>)
	must be changed. ATTENTION! This changes may be overwritten
	by Connection Point Implementation wizard.

	*** Old code:

		pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
  
	*** New code:

		IDispatch* pMarshaledDispatch = pT->GetMarshaledInterface(pDispatch);
		if(pMarshaledDispatch)
			pMarshaledDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);

****************************************************/
template <class T, const IID* piid, BOOL bMultipleStreamUse>
class CMarshalEvents  
{
public:

	/***************************************************
	CMarshalEvents
		Constructor
	Params
		none
	Return
		none
	****************************************************/
	CMarshalEvents() : m_ptrInterfaces(NULL)	// Initialize interface list
	{ 
	}
	
	/***************************************************
	~CMarshalEvents
		Virtual destructor
	Params
		none
	Return
		none
	****************************************************/
	virtual ~CMarshalEvents() 
	{ 
		ClearInterfaceList();			// Clear interface list
	}

	/***************************************************
	MarshalInterfacesToStream
		Marshall all sink IDispatch into the stream interfaces
	Params
		pT	- pointer to the object class
	Return
		none
	****************************************************/
	void MarshalInterfacesToStream( T *pT ) 
	{
		if(pT) {
			HRESULT				hr;
			MarshalInterface	*ptrNextItem = NULL;
			IStream				*ptrStream;
			int					nConnectionIndex;
			int					nConnections = pT->IConnectionPointImpl<T, piid, CComDynamicUnkArray>::m_vec.GetSize();

			// Clear the list and release interfaces
			ClearInterfaceList();

			// Loop through all connected sinks
			for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++) {
				pT->Lock();
				CComPtr<IUnknown> sp = pT->IConnectionPointImpl<T, piid, CComDynamicUnkArray>::m_vec.GetAt(nConnectionIndex);
				pT->Unlock();
				IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);

				if (pDispatch != NULL) {

					// Marshal interface into the stream
					if(bMultipleStreamUse)
						hr = AtlMarshalPtrInProc(pDispatch, IID_IDispatch, &ptrStream);
					else
						hr = CoMarshalInterThreadInterfaceInStream(IID_IDispatch, pDispatch, &ptrStream);

					// Add new inteface list item
					if( hr == S_OK) {
						if(ptrNextItem == NULL) {
							m_ptrInterfaces = new MarshalInterface;
							ptrNextItem = m_ptrInterfaces;
							}
						else {
							ptrNextItem->pNext =  new MarshalInterface;
							ptrNextItem = ptrNextItem->pNext;
							}

						// Initialize new inteface list item
						ptrNextItem->pStream = ptrStream;
						ptrNextItem->pDispatch = pDispatch;
						ptrNextItem->pMarshaledDispatch = NULL;
						ptrNextItem->pNext = NULL;
						}
					}
				}
			}
		}

	/***************************************************
	GetMarshaledInterface
		Returns marshaled IDispatch interface. If bMultipleStreamUse
		is FALSE the IStream interface will be released.
	Params
		ptrIDispatch	- original IDispatch interface
	Return
		none
	****************************************************/
	IDispatch *GetMarshaledInterface(IDispatch *ptrIDispatch)
	{
		IDispatch	*ptrResult = NULL;
		HRESULT		hr;

		// Try to find original IDispatch in the Interfaces list
		MarshalInterface	*ptrNextItem = m_ptrInterfaces;
		while(ptrNextItem != NULL) {
			if(ptrNextItem->pDispatch == ptrIDispatch) {
				if((!m_ptrInterfaces->pMarshaledDispatch || bMultipleStreamUse) && m_ptrInterfaces->pStream) {

					// If we are going to use IStream more than once
					// don't release it
					if(bMultipleStreamUse) {
						if(m_ptrInterfaces->pMarshaledDispatch)
							m_ptrInterfaces->pMarshaledDispatch->Release();

						// Unmarshal IDispatch from IStream
						hr = AtlUnmarshalPtr( m_ptrInterfaces->pStream, IID_IDispatch, (IUnknown **) &m_ptrInterfaces->pMarshaledDispatch );
						}
					else {
						// Unmarshal IDispatch from IStream and release IStream 
						hr = CoGetInterfaceAndReleaseStream(m_ptrInterfaces->pStream, IID_IDispatch, (void **) &m_ptrInterfaces->pMarshaledDispatch);

						m_ptrInterfaces->pStream = NULL;
						}

					if(hr != S_OK)
						m_ptrInterfaces->pMarshaledDispatch = NULL;

					}

				ptrResult = m_ptrInterfaces->pMarshaledDispatch;
				}
			
			ptrNextItem = ptrNextItem->pNext;
			}

		return ptrResult;
	}

private:

	/***************************************************
	ClearInterfaceList
		Clear list and release Interfaces
	Params
		none
	Return
		none
	****************************************************/
	void ClearInterfaceList()
	{
		MarshalInterface	*ptrNextItem;

		while(m_ptrInterfaces != NULL){
			ptrNextItem = m_ptrInterfaces->pNext;
			try {
				if(m_ptrInterfaces->pStream)
					m_ptrInterfaces->pStream->Release();
				if(m_ptrInterfaces->pMarshaledDispatch)
					m_ptrInterfaces->pMarshaledDispatch->Release();
				delete m_ptrInterfaces;
				}
			catch(...) {}
			m_ptrInterfaces = ptrNextItem;
			}
   	}


private:

	MarshalInterface	*m_ptrInterfaces;	// Marshaled interface list

};

#endif // !defined(AFX_MARSHALEVENTS_H__B63A9000_ED4F_11D2_A443_0080C858F182__INCLUDED_)


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
Web Developer
Canada Canada
In January 2005, David Cunningham and Chris Maunder created TheUltimateToolbox.com, a new group dedicated to the continued development, support and growth of Dundas Software’s award winning line of MFC, C++ and ActiveX control products.

Ultimate Grid for MFC, Ultimate Toolbox for MFC, and Ultimate TCP/IP have been stalwarts of C++/MFC development for a decade. Thousands of developers have used these products to speed their time to market, improve the quality of their finished products, and enhance the reliability and flexibility of their software.
This is a Organisation

476 members

Comments and Discussions