首页 > 代码库 > 借助模板类自动实现COM连接点接收器(Sink)更新

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

之前在借助模板类自动实现COM连接点接收器(Sink)中对原作者的代码进一步封装,弄清了连接点使用的原理,在看ATL代码的过程中,发现ATL本身就提供了AtlAdvise/AtlUnadvise这样的机制来简化连接点的使用,CComPtrBase中也有Advise这个成员函数,它是对AtlAdvise,进一步封装,因此,对ConnectionHelper的代码可以再简化,简化后Connect()只有十来行了。原作者写的GetConnectPoint函数也用不上了。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#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 );
    }
};
 
 
///////////////////////////////////////////////////////////////////////////////////////////////////////
// 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__ )

  以上就是全部代码,减少到不到100行。

 

使用方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{ // .tlh中的接口方式调用
    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 );
        }
    }
}

  

?
1
2
3
4
5
6
7
8
9
10
11
12
{ // IDispatch方式调用
    CComPtr<IDispatch> spDisp;
    HRESULT hr = spDisp.CoCreateInstance( L"Test.Com" );
    if ( SUCCEEDED( hr ) )
    {
        CComQIPtr<IUnknown, &IID_IUnknown> spUnknown( spDisp );
        ConnectionPointHelper<ComDllLib::_ITestComEvent, CSink3> cph( spUnknown );
        _variant_t ret;
        _variant_t m = 2, n = 3;
        spDisp.Invoke2( (LPCOLESTR) L"Add", &m, &n, &ret );
    }
}