一般分为两种:
1、直接调用
- HRESULT CFirePropNotifyEvent::FireOnRequestEdit(IUnknown* pUnk, DISPID dispID)
- {
- CComQIPtr<IConnectionPointContainer, &IID_IConnectionPointContainer> pCPC(pUnk);
- if (!pCPC)
- return S_OK;
- CComPtr<IConnectionPoint> pCP;
- pCPC->FindConnectionPoint(IID_IPropertyNotifySink, &pCP);
- if (!pCP)
- return S_OK;
- CComPtr<IEnumConnections> pEnum;
- if (FAILED(pCP->EnumConnections(&pEnum)))
- return S_OK;
- CONNECTDATA cd;
- while (pEnum->Next(1, &cd, NULL) == S_OK)
- {
- if (cd.pUnk)
- {
- HRESULT hr = S_OK;
- CComQIPtr<IPropertyNotifySink, &IID_IPropertyNotifySink> pSink(cd.pUnk);
- if (pSink)
- hr = pSink->OnRequestEdit(dispID);
- cd.pUnk->Release();
- if (hr == S_FALSE)
- return S_FALSE;
- }
- }
- return S_OK;
- }
获得连接容器接口,进而获得容器中接收器IID_IPropertyNotifySink类型的连接点,再遍历这个连接点中各个IID_IPropertyNotifySink接收器,进而调用相应某事件。
这里的关键是:在事件对象中继承IID_IPropertyNotifySink接收器接口,并实现OnRequestEdit等事件函数。
2、间接调用。
- template<typename host_t, const IID* pIID_ToHookEvent>
- class ComEventIntercepter : public IDispatch
- {
- typedef HRESULT (STDMETHODCALLTYPE host_t::*invok_t)(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
- DISPPARAMS FAR* pDispParams, VARIANT FAR* parResult,EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr);
- public:
- ComEventIntercepter(host_t* pHost = NULL, invok_t notifier = NULL) :
- m_pHost(pHost), m_notifier(notifier), m_dwCookie(0)
- {
- }
- HRESULT Intercept(IUnknown* pUnkCP)
- {
- if(pUnkCP == NULL)
- return E_INVALIDARG;
- CComPtr<IConnectionPointContainer> pCPC;
- CComPtr<IConnectionPoint> pCP;
- HRESULT hRes = pUnkCP->QueryInterface(__uuidof(IConnectionPointContainer), (void**)&pCPC);
- if (SUCCEEDED(hRes))
- hRes = pCPC->FindConnectionPoint(*pIID_ToHookEvent, &pCP);
- if (SUCCEEDED(hRes))
- hRes = pCP->Advise(this, &m_dwCookie);
- return hRes;
- }
- public:
- STDMETHODIMP QueryInterface(REFIID iid, void ** ppvObject)
- {
- if(ppvObject == NULL) return E_INVALIDARG;
- *ppvObject = NULL;
- if(iid == IID_IUnknown)
- *ppvObject = (IUnknown*)this;
- else if(iid == *pIID_ToHookEvent || iid == IID_IDispatch)
- *ppvObject = this;
- if(*ppvObject == NULL) return E_NOINTERFACE;
- return S_OK;
- }
- ULONG STDMETHODCALLTYPE AddRef()
- {
- return 0;
- }
- ULONG STDMETHODCALLTYPE Release()
- {
- return 0;
- }
- HRESULT STDMETHODCALLTYPE GetTypeInfoCount(unsigned int FAR* pctinfo)
- { return E_NOTIMPL; }
- HRESULT STDMETHODCALLTYPE GetTypeInfo(unsigned int iTInfo, LCID lcid,
- ITypeInfo FAR* FAR* ppTInfo)
- { return E_NOTIMPL; }
- HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid,
- OLECHAR FAR* FAR* rgszNames,
- unsigned int cNames,
- LCID lcid,
- DISPID FAR* rgDispId)
- { return E_NOTIMPL; }
- HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
- DISPPARAMS FAR* pDispParams, VARIANT FAR* parResult,
- EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr)
- {
- if(m_pHost && m_notifier)
- {
- return (m_pHost->*m_notifier)(dispIdMember, riid, lcid, wFlags, pDispParams, parResult, pExcepInfo, puArgErr);
- }
- return E_NOTIMPL;
- }
- protected:
- host_t* m_pHost;
- invok_t m_notifier;
- DWORD m_dwCookie;
- };
- HRESULT CWebBrowser::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
- DISPPARAMS FAR* pDispParams, VARIANT FAR* parResult,
- EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr)
- {
- switch (dispIdMember)
- {
- case DISPID_DOCUMENTCOMPLETE:
- //ATLTRACE("DISPID_DOCUMENTCOMPLETE/n");
- break;
- case DISPID_DOWNLOADBEGIN:
- // Enable the stop menu item and toolbar button
- //EnableMenuItem(m_hMenu, ID_VIEW_STOP, MF_BYCOMMAND|MF_ENABLED);
- //m_wndToolBar.SendMessage(TB_ENABLEBUTTON, ID_VIEW_STOP, MAKELONG(TRUE, 0));
- break;
- case DISPID_NAVIGATECOMPLETE:
- {
- // Set the text of the combobox to the current URL
- //CComBSTR bstrURL;
- //m_spWebBrowser->get_LocationURL(&bstrURL);
- //m_wndUrlCombo.SetWindowText(OLE2T(bstrURL));
- }
- break;
- case DISPID_NAVIGATECOMPLETE2:
- {
- // Set the text of the combobox to the current URL
- //CComBSTR bstrURL;
- //m_spWebBrowser->get_LocationURL(&bstrURL);
- //m_wndUrlCombo.SetWindowText(OLE2T(bstrURL));
- }
- break;
- case DISPID_DOWNLOADCOMPLETE:
- // Disable the stop menu item and toolbar button
- //EnableMenuItem(m_hMenu, ID_VIEW_STOP, MF_BYCOMMAND|MF_GRAYED);
- //m_wndToolBar.SendMessage(TB_ENABLEBUTTON, ID_VIEW_STOP, MAKELONG(FALSE, 0));
- break;
- //
- // The parameters for this DISPID:
- // [0]: New status bar text - VT_BSTR
- //
- case DISPID_STATUSTEXTCHANGE:
- //m_wndStatusBar.SetWindowText(OLE2T(pDispParams->rgvarg[0].bstrVal));
- break;
- //
- // The parameters for this DISPID:
- // [0]: Document title - VT_BSTR
- //
- case DISPID_TITLECHANGE:
- {
- //strstream strTitle;
- //if (pDispParams->cArgs > 0 && pDispParams->rgvarg[0].vt == VT_BSTR)
- //{
- // strTitle << OLE2T(pDispParams->rgvarg[0].bstrVal);
- // strTitle << " - AtlBrowser";
- //}
- //else
- //{
- // strTitle << "AtlBrowser";
- //}
- //strTitle << ends;
- //SetWindowText(strTitle.str());
- }
- break;
- //
- // DISPID for Download Control
- //
- case DISPID_AMBIENT_DLCONTROL:
- {
- //CComVariant vtResult(static_cast<long>(m_dwDLControl));
- //*pvarResult = vtResult;
- }
- break;
- default:
- return DISP_E_MEMBERNOTFOUND;
- }
- return S_OK;
- }
这里的关键是:在事件对象中定义IDispatch接口,通过在Invoke()函数中实现各事件分支语句,实现各事件具体功能。
而上一种需要为各个事件实现各自的函数,针对某个事件,会有相应的触发函数和响应函数。
而间接调用中,Invoke()把所有事件响应都集成在自己函数里,通过dispid的不同来进行分支处理。触发函数也只需一个,只需在输入参数中用dispid来区别。
间接调用的好处就是可以方便脚本语言中的实现,只是效率低很多而已。