zoukankan      html  css  js  c++  java
  • 借助模板类自动实现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 );
    	}
    };
    

      

  • 相关阅读:
    Android 节日短信送祝福(UI篇:3-选择短信与发送短信的Activity的实现)
    Android 节日短信送祝福(功能篇:2-短信历史记录Fragment的编写)
    Android 节日短信送祝福(功能篇:1-数据库操作类与自定义ContentProvider)
    Android AIDL 小结
    Android 异步更新UI-线程池-Future-Handler实例分析
    Android 利用线程运行栈StackTraceElement设计Android日志模块
    Android OkHttp网络连接封装工具类
    Android OKHttp源码解析
    Android开发人员不得不收集的代码(持续更新中)
    Android 为开发者准备的最佳 Android 函数库(2016 年版)
  • 原文地址:https://www.cnblogs.com/honker/p/3773048.html
Copyright © 2011-2022 走看看