借助模板类自动实现COM连接点接收器(Sink)

本文的更新:借助模板类自动实现COM连接点接收器(Sink)更新 (2014-06-09 17:09)

 

最初的代码源自free2000fly一个标准的 COM 连接点接收器(Sink)的实现, 使用相当简单!!!作者封装了不少工作,但调用时的代码还可以再封装一下,最后只要拷贝并修改Sink实现类的Invoke就好了。

 

以下是这个代码的头文件 "sinkimpl.h",比free2000fly的"sinkimpl.h"多了一个模板类ConnectionPointerHelper<>

#if !defined( __sinkimpl_h_INCLUDED__ )

#define __sinkimpl_h_INCLUDED__ 



#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000





template<typename T, typename EventInterface, const GUID * evtLibID = NULL >

class ATL_NO_VTABLE CSinkImpT

	: public CComObjectRootEx<CComSingleThreadModel>

	, public CComCoClass<CSinkImpT<T, EventInterface, evtLibID>, &__uuidof(T)>

	, public IDispatchImpl < EventInterface, &__uuidof(EventInterface), evtLibID >

{

public:

	CSinkImpT() {}

	virtual ~CSinkImpT() {}



	typedef IDispatchImpl<EventInterface, &__uuidof(EventInterface), evtLibID> _parentClass;

	typedef CSinkImpT<T, EventInterface, evtLibID> _thisClass;



	STDMETHOD( Invoke )(DISPID dispidMember, REFIID riid,

						 LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,

						 EXCEPINFO* pexcepinfo, UINT* puArgErr)

	{

		T * pThis = static_cast<T *>(this);

		return pThis->DoInvoke( dispidMember, riid,

								lcid, wFlags, pdispparams, pvarResult,

								pexcepinfo, puArgErr );

	}



	DECLARE_NO_REGISTRY()



	DECLARE_PROTECT_FINAL_CONSTRUCT()



	BEGIN_COM_MAP( _thisClass )

		COM_INTERFACE_ENTRY( IDispatch )

		COM_INTERFACE_ENTRY( EventInterface )

	END_COM_MAP();



	STDMETHOD( DoInvoke )(DISPID dispidMember, REFIID riid,

						   LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,

						   EXCEPINFO* pexcepinfo, UINT* puArgErr)

	{

		return _parentClass::Invoke( dispidMember, riid,

									 lcid, wFlags, pdispparams, pvarResult,

									 pexcepinfo, puArgErr );

	}

};



inline HRESULT WINAPI GetConnectPoint( IUnknown * pItf, const IID & rSinkIID, IConnectionPoint ** ppCP )

{

	HRESULT hr = E_FAIL;

	do

	{

		if ( pItf == NULL || ppCP == NULL ) { break; }



		CComQIPtr<IConnectionPointContainer> spContainer;

		hr = pItf->QueryInterface( &spContainer );

		if ( FAILED( hr ) ) { break; }



		hr = spContainer->FindConnectionPoint( rSinkIID, ppCP );

	} while ( FALSE );

	return hr;

}



///////////////////////////////////////////////////////////////////////////////////////////////////////

// 使用方法:

// ComDllLib::ITestComPtr pCom;

// HRESULT hr = pCom.CreateInstance( L"Test.Com" );

// ConnectionPointHelper<ComDllLib::_ITestComEvent, CSink3> cph( pCom );

//

template<typename EventInterface, typename EventProcessor>

class ConnectionPointHelper

{

	CComPtr<IUnknown> m_spInterface;

	DWORD m_dwCookie;

public:

	ConnectionPointHelper( IUnknown* pInterface ) : m_spInterface( pInterface ), m_dwCookie( 0 ) { Connect(); }

	~ConnectionPointHelper() { Disconnect(); }

protected:

	void Connect()

	{

		HRESULT hr = E_FAIL;

		do

		{

			if ( m_spInterface == NULL || m_dwCookie != 0 ) { break; }



			CComQIPtr<IConnectionPoint> spCP;

			hr = GetConnectPoint( m_spInterface, __uuidof(EventInterface), &spCP );

			if ( FAILED( hr ) ){ break; }



			CComQIPtr<IDispatch> spSink;

			{

				CComObject<EventProcessor> * pTmp = NULL;

				hr = CComObject<EventProcessor>::CreateInstance( &pTmp );

				if ( FAILED( hr ) ){ break; }



				pTmp->AddRef();

				hr = pTmp->QueryInterface( &spSink );

				pTmp->Release();



				if ( FAILED( hr ) ){ break; }

			}



			spCP->Advise( spSink, &m_dwCookie );



		} while ( FALSE );

	}



	void Disconnect()

	{

		HRESULT hr = E_FAIL;

		do {

			if ( m_dwCookie == 0 ) { break; }



			CComQIPtr<IConnectionPoint> spCP;



			hr = GetConnectPoint( m_spInterface, __uuidof(EventInterface), &spCP );

			if ( FAILED( hr ) ){ break; }



			hr = spCP->Unadvise( m_dwCookie );

			m_dwCookie = 0;

		} while ( FALSE );

	}



};

#endif // !defined( __sinkimpl_h_INCLUDED__ )

  

使用方法:
		UIAddChildWindowContainer( m_hWnd );

		ComDllLib::ITestComPtr pCom;

		CComPtr<IUnknown> pUnknown;

		HRESULT hr = pCom.CreateInstance( L"Test.Com" );

		if (SUCCEEDED(hr))

		{

			hr = pCom->QueryInterface( IID_IUnknown, reinterpret_cast<void**>(&pUnknown) );

			if ( SUCCEEDED( hr ) )

			{

				ConnectionPointHelper<ComDllLib::_ITestComEvent, CSink3> cph( pUnknown );

				LONG c = pCom->Add( 1, 5 );

			}

		}

  CSink3的实现(与free2000fly写的一样):

// 要响应连接点事件,只需要重写此类

// 

class DECLSPEC_UUID( "492194D9-7BEE-422D-AE7C-C43A809F20EC" ) CSink3;

class ATL_NO_VTABLE CSink3

	: public CSinkImpT < CSink3, ComDllLib::_ITestComEvent >

{

public:

	CSink3( void ) {  }

	virtual ~CSink3( void ) {}



	typedef CSinkImpT<CSink3, ComDllLib::_ITestComEvent> _parentClass;



	STDMETHOD( DoInvoke )(DISPID dispidMember, REFIID riid,

						   LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,

						   EXCEPINFO* pexcepinfo, UINT* puArgErr)

	{

		// 3. the dispidMember must referenced from .thl file, and you can have a look using oleview.exe

		switch ( dispidMember )

		{

		case 1:

		{

			CComVariant result( *pvarResult );

			if ( SUCCEEDED( result.ChangeType( VT_BSTR ) ) )

				::MessageBoxW( ::GetActiveWindow(), result.bstrVal, L"Sink Message", MB_OK );

			return S_OK;

		}

		default:

			break;

		}

		return _parentClass::DoInvoke( dispidMember, riid,

									   lcid, wFlags, pdispparams, pvarResult,

									   pexcepinfo, puArgErr );

	}

};

  

你可能感兴趣的:(com)