COM连接点 - Part III - 一个COM接口实现多个连接点

From: http://blog.csdn.net/zj510/article/details/39080353

 

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

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

IDL中增加一个接口_IMyCarEvents2

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

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

现在就变成了

  1. library MyComLib 
  2.     importlib("stdole2.tlb"); 
  3.     [ 
  4.         uuid(2CF347A8-63ED-4CE0-8A6D-F98D60C98B8C)       
  5.     ] 
  6.     dispinterface _IMyCarEvents 
  7.     { 
  8.         properties: 
  9.         methods: 
  10.              
  11.             [id(1)] HRESULT OnStop([in] FLOAT Distance); 
  12.     }; 
  13.     [ 
  14.         uuid(5A745470-8950-4a9b-B624-5D76F1BB28C9)       
  15.     ] 
  16.     dispinterface _IMyCarEvents2 
  17.     { 
  18.         properties: 
  19.         methods: 
  20.             [id(1)] HRESULT NeedMoreGas(); 
  21.     }; 
  22.     [ 
  23.         uuid(DA6770F3-CBB6-4F34-A137-2B02A27AB219)       
  24.     ] 
  25.     coclass MyCar 
  26.     { 
  27.         [default] interface IMyCar; 
  28.         [default, source] dispinterface _IMyCarEvents; 
  29.     }; 
  30. }; 
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类

  1. template<class T> 
  2. class CProxy_IMyCarEvents2 : 
  3.     public ATL::IConnectionPointImpl < T, &__uuidof(_IMyCarEvents2) > 
  4. public
  5.     HRESULT Fire_NeedMoreGas() 
  6.     { 
  7.         HRESULT hr = S_OK; 
  8.         T * pThis = static_cast<T *>(this); 
  9.         int cConnections = m_vec.GetSize(); 
  10.  
  11.         for (int iConnection = 0; iConnection < cConnections; iConnection++) 
  12.         { 
  13.             pThis->Lock(); 
  14.             CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection); 
  15.             pThis->Unlock(); 
  16.  
  17.             IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p); 
  18.  
  19.             if (pConnection) 
  20.             { 
  21.                  
  22.                 CComVariant varResult; 
  23.  
  24.                 DISPPARAMS params = { NULL, NULL, 0, 0 }; 
  25.                 hr = pConnection->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, &varResult, NULL, NULL); 
  26.             } 
  27.         } 
  28.         return hr; 
  29.     } 
  30. }; 
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那里加上新的连接点。

  1. class ATL_NO_VTABLE CMyCar : 
  2.     public CComObjectRootEx<CComSingleThreadModel>, 
  3.     public CComCoClass<CMyCar, &CLSID_MyCar>, 
  4.     public IConnectionPointContainerImpl<CMyCar>, 
  5.     public CProxy_IMyCarEvents<CMyCar>, 
  6.     public CProxy_IMyCarEvents2<CMyCar>,  // 支持新的连接点 
  7.     public IDispatchImpl<IMyCar, &IID_IMyCar, &LIBID_MyComLib, /*wMajor =*/ 1, /*wMinor =*/ 0> 
  8. public
  9.     CMyCar() 
  10.     { 
  11.     } 
  12.  
  13. DECLARE_REGISTRY_RESOURCEID(IDR_MYCAR) 
  14.  
  15.  
  16. BEGIN_COM_MAP(CMyCar) 
  17.     COM_INTERFACE_ENTRY(IMyCar) 
  18.     COM_INTERFACE_ENTRY(IDispatch) 
  19.     COM_INTERFACE_ENTRY(IConnectionPointContainer) 
  20. END_COM_MAP() 
  21.  
  22. BEGIN_CONNECTION_POINT_MAP(CMyCar) 
  23.     CONNECTION_POINT_ENTRY(__uuidof(_IMyCarEvents)) 
  24.     CONNECTION_POINT_ENTRY(__uuidof(_IMyCarEvents2))  // 支持新的连接点 
  25. END_CONNECTION_POINT_MAP() 
  26.  
  27.  
  28.     DECLARE_PROTECT_FINAL_CONSTRUCT() 
  29.  
  30.     HRESULT FinalConstruct() 
  31.     { 
  32.         return S_OK; 
  33.     } 
  34.  
  35.     void FinalRelease() 
  36.     { 
  37.     } 
  38.  
  39. public
  40.  
  41.  
  42.  
  43.     STDMETHOD(Run)(); 
  44. }; 
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函数触发新连接点的一个事件:

  1. STDMETHODIMP CMyCar::Run() 
  2.     // TODO: Add your implementation code here 
  3.  
  4.     this->Fire_OnStop(1000); 
  5.     this->Fire_NeedMoreGas(); 
  6.  
  7.     return S_OK; 
STDMETHODIMP CMyCar::Run()
{
    // TODO: Add your implementation code here

    this->Fire_OnStop(1000);
    this->Fire_NeedMoreGas();

    return S_OK;
}


客户端修改

增加一个新的sink类

  1. class CSink2 : 
  2. public CComObjectRoot, 
  3. public _IMyCarEvents2 
  4. BEGIN_COM_MAP(CSink2) 
  5.     COM_INTERFACE_ENTRY(IDispatch) 
  6.     COM_INTERFACE_ENTRY(_IMyCarEvents2) 
  7. END_COM_MAP() 
  8.  
  9. public
  10.     virtual ~CSink2(){ 
  11.     } 
  12.     STDMETHODIMP GetTypeInfoCount(UINT *pctinfo) { return E_NOTIMPL; } 
  13.     STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)   { return E_NOTIMPL; } 
  14.     STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)  { return E_NOTIMPL; } 
  15.  
  16.     STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) 
  17.     { 
  18.         printf("sink, id: %d", dispIdMember); 
  19.  
  20.         return S_OK; 
  21.     } 
  22. }; 
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;
    }
};

然后挂载

  1. CComObject<CSink2>* sinkptr2 = nullptr; 
  2. CComObject<CSink2>::CreateInstance(&sinkptr2); 
  3.  
  4. AtlAdvise(spCar, sinkptr2, __uuidof(_IMyCarEvents2), &cookies); 
        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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值