Previously, the original author's code was further encapsulated by using the template class to automatically implement the COM connection point receiver (Sink), and the principle used by the connection point was clarified. During the process of viewing the ATL code, it is found that ATL itself provides a mechanism such as AtlAdvise/AtlUnadvise to simplify the use of connection points. In CComPtrBase, Advise is also a member function, which further encapsulates AtlAdvise. Therefore, the ConnectionHelper code can be simplified. After the code is simplified, Connect () is only 10 lines. The GetConnectPoint function written by the original author cannot be used.
#if !defined( __sinkimpl_h_INCLUDED__ )#define __sinkimpl_h_INCLUDED__ #if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000template<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 );}};///////////////////////////////////////////////////////////////////////////////////////////////////////// ComDllLib::ITestComPtr pCom;// HRESULT hr = pCom.CreateInstance( L"Test.Com" );// ConnectionPointHelper<ComDllLib::ITestCom, 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; }CComObject<EventProcessor> * pTmp = NULL;hr = CComObject<EventProcessor>::CreateInstance( &pTmp );if ( FAILED( hr ) ){ break; }CComQIPtr<IUnknown, &IID_IUnknown> spSink( pTmp );hr = m_spInterface.Advise( spSink, __uuidof(EventInterface), &m_dwCookie );} while ( FALSE );}void Disconnect(){HRESULT hr = E_FAIL;do {if ( m_dwCookie == 0 ) { break; }AtlUnadvise( m_spInterface, __uuidof(EventInterface), m_dwCookie );m_dwCookie = 0;} while ( FALSE );}};#endif // !defined( __sinkimpl_h_INCLUDED__ )
All the above Code is reduced to less than 100 lines.
Usage:
{//. Call 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 );}}}
{// Call CComPtr <IDispatch> spDisp in IDispatch mode; HRESULT hr = spDisp. coCreateInstance (L "Test. com "); if (SUCCEEDED (hr) {CComQIPtr <IUnknown, & found> spUnknown (spDisp); ConnectionPointHelper <ComDllLib: _ Unknown, CSink3> cph (spUnknown ); _ variant_t ret; _ variant_t m = 2, n = 3; spDisp. invoke2 (LPCOLESTR) L "Add", & m, & n, & ret );}}