一.使用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, ¶ms,NULL,NULL,NULL);
跟反射的概念完全是一样的
二.IDispatchImpl
ATL中,IDispatchImpl实现了IDispatch
class CRandom : public IDispatchImpl,{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, public IConnectionPointImpl
2.在客户端调用方实现IRandomEvent接口(接收器)
class CDriver : public IDispatchImpl, 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* pDriver;CComObject ::CreateInstance(&pDriver);pDriver->m_nID = m_nAdviseCnt;HRESULT hRes = AtlAdvise(pRandom, pDriver->GetUnknown(), IID_IRandomEvent, &m_arrAdvise[m_nAdviseCnt++]);
4.服务器端进行回调
IConnectionPointImpl* 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自动生成代码,如果事件很多(而且客户端可以多次监听),写这些重复的代码是没有必要的
templateclass CProxyIRandomEvent : public ATL::IConnectionPointImpl {public: HRESULT Fire_Fire(long nID) { HRESULT hr = S_OK; T * pThis = static_cast (this); int cConnections = m_vec.GetSize(); for (int iConnection = 0; iConnection < cConnections; iConnection++) { pThis->Lock(); CComPtr punkConnection = m_vec.GetAt(iConnection); pThis->Unlock(); IRandomEvent * pConnection = static_cast (punkConnection.p); if (pConnection) { hr = pConnection->Fire(nID); } } return hr; }};
class CRandom : public IDispatchImpl, public IConnectionPointContainerImpl , public CProxyIRandomEvent {public: CRandom() { } ~CRandom();// Connection Point1 BEGIN_CONNECTION_POINT_MAP(CRandom) CONNECTION_POINT_ENTRY(__uuidof(IRandomEvent)) END_CONNECTION_POINT_MAP()
让CRandom 继承自CProxyIRandomEvent,去掉之前的IConnectionPointImpl