• COM Tip(2)


    一.使用IDispatch

    interface IRandom : IDispatch
    {
        import "oaidl.idl";
        [id(0)]
        HRESULT Start([out]long* pnID);
        [id(1)]
        HRESULT Stop([in]long nID);
        [id(2)]
        HRESULT StopAll();
    };
    

    使用GetIDsOfNames获取DISP

    OLECHAR *fn=L"Stop";
    DISPID id;
    pRandom->GetIDsOfNames(IID_NULL,&fn,1,GetUserDefaultLCID(),&id);
    

    使用Invoke动态调用函数

    VARIANT var;
    ::VariantInit(&var);
    var.lVal=2;
    
    DISPPARAMS params;
    params.cArgs=1;
    params.rgvarg=&var;
    pRandom->Invoke(id,IID_NULL,GetUserDefaultLCID(),DISPATCH_METHOD,
        &params,NULL,NULL,NULL);
    

    跟反射的概念完全是一样的

    二.IDispatchImpl

    ATL中,IDispatchImpl实现了IDispatch

    class CRandom :
        public IDispatchImpl<IRandom, &IID_IRandom, &LIBID_CONNECTLib>,
    {
    public:
        CRandom()
        {
        }
        ~CRandom();
    
    BEGIN_COM_MAP(CRandom)
        COM_INTERFACE_ENTRY2(IDispatch, IRandom)
        COM_INTERFACE_ENTRY(IRandom)
    END_COM_MAP()
    }

    三.实现连接点

    1.实现IConnectionPointContainerImpl和IConnectionPointImpl

    class CRandom :
        public IConnectionPointContainerImpl<CRandom>,
        public IConnectionPointImpl<CRandom, &IID_IRandomEvent, {
    public:
        CRandom()
        {
        }
        ~CRandom();
    
    BEGIN_COM_MAP(CRandom)
        COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)
    END_COM_MAP()
    
    // Connection Point
        BEGIN_CONNECTION_POINT_MAP(CRandom)
            CONNECTION_POINT_ENTRY(IID_IRandomEvent)
        END_CONNECTION_POINT_MAP()
    }

    2.在客户端调用方实现IRandomEvent接口(接收器)

    class CDriver :
        public IDispatchImpl<IRandomEvent, &IID_IRandomEvent, &LIBID_CONNECTLib>,
        public CComObjectRoot
    {
    public:
        CDriver() {}
    BEGIN_COM_MAP(CDriver)
        COM_INTERFACE_ENTRY(IDispatch)
        COM_INTERFACE_ENTRY(IRandomEvent)
    END_COM_MAP()
    
    // IRandomEvent
        STDMETHOD(Fire)(long l);
    public:
    };
    

    3.客户端创建连接点进行监听

    CComObject<CDriver>* pDriver;
    CComObject<CDriver>::CreateInstance(&pDriver);
    pDriver->m_nID = m_nAdviseCnt;
    HRESULT hRes = AtlAdvise(pRandom, pDriver->GetUnknown(), IID_IRandomEvent, &m_arrAdvise[m_nAdviseCnt++]);
    

    4.服务器端进行回调

    IConnectionPointImpl<CRandom, &IID_IRandomEvent, CComDynamicUnkArray>* p = this;
    Lock();
    HRESULT hr = S_OK;
    IUnknown** pp = p->m_vec.begin();
    while (pp < p->m_vec.end() && hr == S_OK)
    {
        if (*pp != NULL)
        {
            IRandomEvent* pIRandomEvent = (IRandomEvent*)*pp;
            hr = pIRandomEvent->Fire(nID);
        }
        pp++;
    }
    

    5.自动生成连接点代理

    第4步可以用vs自动生成代码,如果事件很多(而且客户端可以多次监听),写这些重复的代码是没有必要的

    template<class T>
    class CProxyIRandomEvent :
        public ATL::IConnectionPointImpl<T, &__uuidof(IRandomEvent)>
    {
    public:
        HRESULT Fire_Fire(long nID)
        {
            HRESULT hr = S_OK;
            T * pThis = static_cast<T *>(this);
            int cConnections = m_vec.GetSize();
    
            for (int iConnection = 0; iConnection < cConnections; iConnection++)
            {
                pThis->Lock();
                CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
                pThis->Unlock();
    
                IRandomEvent * pConnection = static_cast<IRandomEvent *>(punkConnection.p);
    
                if (pConnection)
                {
                    hr = pConnection->Fire(nID);
                }
            }
            return hr;
        }
    };
    
    class CRandom :
        public IDispatchImpl<IRandom, &IID_IRandom, &LIBID_CONNECTLib>,
        public IConnectionPointContainerImpl<CRandom>,
        public CProxyIRandomEvent<CRandom>
    {
    public:
        CRandom()
        {
        }
        ~CRandom();
    
    // Connection Point1
        BEGIN_CONNECTION_POINT_MAP(CRandom)
            CONNECTION_POINT_ENTRY(__uuidof(IRandomEvent))
        END_CONNECTION_POINT_MAP()
    

    让CRandom 继承自CProxyIRandomEvent,去掉之前的IConnectionPointImpl

  • 相关阅读:
    rails采用MongoDB感觉相当不错!
    LWC: 将VF页面显示在LWC中
    Salesforce: System.TypeException: Invalid integer: 2185340704
    Salesforce: Report没有权限访问
    Maven Archetype 多 Module 自定义代码脚手架
    2021年度总结
    [转摘]Lucene学习总结之一:全文检索的基本原理
    DataTable.Rows.Remove(row) 与 DataTable.Rows[i].Delete()区别
    Lucene.net根据Sort走到了不同的类处理
    调用腾讯QQ天气预报的JS代码
  • 原文地址:https://www.cnblogs.com/Clingingboy/p/2078846.html
Copyright © 2020-2023  润新知