COM连接点 - 一个COM接口实现多个连接点(3)

来源:互联网 发布:网络综合布线设计方案 编辑:程序博客网 时间:2024/06/06 06:42

之前讲到一个COM接口可以实现多个连接点。我们就来写个例子。

其实,我还真不知道怎么用ATL向导来实现多个连接点,我们这次就手工改吧。我觉得手工来修改还可以提高对COM的理解,多用用手工还是有好处的。

IDL中增加一个接口_IMyCarEvents2

打开IDL文件,增加以下代码(guid是用windows自带的生成器生成的)

        [uuid(5A745470-8950-4a9b-B624-5D76F1BB28C9)]dispinterface _IMyCarEvents2{properties:methods:            [id(1)] HRESULT NeedMoreGas();        };

现在就变成了

library MyComLib{importlib("stdole2.tlb");[uuid(2CF347A8-63ED-4CE0-8A6D-F98D60C98B8C)]dispinterface _IMyCarEvents{properties:methods:                        [id(1)] HRESULT OnStop([in] FLOAT Distance);    };    [uuid(5A745470-8950-4a9b-B624-5D76F1BB28C9)]dispinterface _IMyCarEvents2{properties:methods:            [id(1)] HRESULT NeedMoreGas();    };[uuid(DA6770F3-CBB6-4F34-A137-2B02A27AB219)]coclass MyCar{[default] interface IMyCar;[default, source] dispinterface _IMyCarEvents;};};

增加一个proxy类

template<class T>class CProxy_IMyCarEvents2 :    public ATL::IConnectionPointImpl < T, &__uuidof(_IMyCarEvents2) >{public:    HRESULT Fire_NeedMoreGas()    {        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();            IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);            if (pConnection)            {                                CComVariant varResult;                DISPPARAMS params = { NULL, NULL, 0, 0 };                hr = pConnection->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, &varResult, NULL, NULL);            }        }        return hr;    }};


修改对应COM类来支持新的连接点

主要就是:

1. 从新连接点的代理类继承

2. CONNECTION POINT MAP那里加上新的连接点。

class ATL_NO_VTABLE CMyCar :public CComObjectRootEx<CComSingleThreadModel>,public CComCoClass<CMyCar, &CLSID_MyCar>,public IConnectionPointContainerImpl<CMyCar>,public CProxy_IMyCarEvents<CMyCar>,    public CProxy_IMyCarEvents2<CMyCar>,  // 支持新的连接点public IDispatchImpl<IMyCar, &IID_IMyCar, &LIBID_MyComLib, /*wMajor =*/ 1, /*wMinor =*/ 0>{public:CMyCar(){}DECLARE_REGISTRY_RESOURCEID(IDR_MYCAR)BEGIN_COM_MAP(CMyCar)COM_INTERFACE_ENTRY(IMyCar)COM_INTERFACE_ENTRY(IDispatch)COM_INTERFACE_ENTRY(IConnectionPointContainer)END_COM_MAP()BEGIN_CONNECTION_POINT_MAP(CMyCar)CONNECTION_POINT_ENTRY(__uuidof(_IMyCarEvents))    CONNECTION_POINT_ENTRY(__uuidof(_IMyCarEvents2))  // 支持新的连接点END_CONNECTION_POINT_MAP()DECLARE_PROTECT_FINAL_CONSTRUCT()HRESULT FinalConstruct(){return S_OK;}void FinalRelease(){}public:    STDMETHOD(Run)();};

RUN函数触发新连接点的一个事件:

STDMETHODIMP CMyCar::Run(){    // TODO: Add your implementation code here    this->Fire_OnStop(1000);    this->Fire_NeedMoreGas();    return S_OK;}


客户端修改

增加一个新的sink类

class CSink2 :public CComObjectRoot,public _IMyCarEvents2{BEGIN_COM_MAP(CSink2)    COM_INTERFACE_ENTRY(IDispatch)    COM_INTERFACE_ENTRY(_IMyCarEvents2)END_COM_MAP()public:    virtual ~CSink2(){    }    STDMETHODIMP GetTypeInfoCount(UINT *pctinfo) { return E_NOTIMPL; }    STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)   { return E_NOTIMPL; }    STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)  { return E_NOTIMPL; }    STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)    {        printf("sink, id: %d", dispIdMember);        return S_OK;    }};

然后挂载

        CComObject<CSink2>* sinkptr2 = nullptr;        CComObject<CSink2>::CreateInstance(&sinkptr2);        AtlAdvise(spCar, sinkptr2, __uuidof(_IMyCarEvents2), &cookies);

跑一下,就会发现2个sink对象的Invoke都被调用了,成功。

注意:一个sink类不能处理2个连接点。我试了一下一个sink了继承2个连接点接口,编译都报错了。
错误如下:

1>d:\study\testcom\testcom\testcom.cpp(22): error C2594: 'static_cast' : ambiguous conversions from 'CSink::_ComMapClass *' to 'IDispatch *'
1>d:\study\testcom\testcom\testcom.cpp(81): error C2594: 'argument' : ambiguous conversions from 'ATL::CComObject<CSink> *' to 'IUnknown *'

不知道是我搞错了,还是确实不支持。不过,我觉得一个sink类处理一个连接点还是合理的。不然全放一起,也不好。



0 0