这两天写一个辅助工具,用到了WebBrowser2控件,需要对DIID_DWebBrowserEvents2事件、DIID_HTMLDocumentEvents2进行处理
ATL提供了IDispEventSimpleImpl模板来简化事件处理,但是这个模板只能绑定一个事件,google了半天也没有找到好的解决方案,索性参考IDispEventSimpleImpl DIY了一个EasyDispEventImpl模板代码如下:
-
- struct EVENT_DIID_ENTRY
- {
- const IID* piid;
- };
- #define BEGIN_EVENT_IID_MAP(_class)/
- typedef _class _GetEventIIDMapFinder;/
- static const EVENT_DIID_ENTRY * _GetEventIIDMap()/
- {/
- typedef _class _atl_event_classtype;/
- static const EVENT_DIID_ENTRY __map[] = {
- #define EVENT_IID_ENTRY(iid) {&iid},
- #define END_EVENT_IID_MAP() /
- {NULL} }; return __map;/
- }
- class CWebBrowser2EventsBase
- {
- protected:
- static _ATL_FUNC_INFO StatusTextChangeStruct;
- static _ATL_FUNC_INFO TitleChangeStruct;
- static _ATL_FUNC_INFO PropertyChangeStruct;
- static _ATL_FUNC_INFO OnQuitStruct;
- static _ATL_FUNC_INFO OnToolBarStruct;
- static _ATL_FUNC_INFO OnMenuBarStruct;
- static _ATL_FUNC_INFO OnStatusBarStruct;
- static _ATL_FUNC_INFO OnFullScreenStruct;
- static _ATL_FUNC_INFO OnTheaterModeStruct;
- static _ATL_FUNC_INFO DownloadBeginStruct;
- static _ATL_FUNC_INFO DownloadCompleteStruct;
- static _ATL_FUNC_INFO NewWindow2Struct;
- static _ATL_FUNC_INFO CommandStateChangeStruct;
- static _ATL_FUNC_INFO BeforeNavigate2Struct;
- static _ATL_FUNC_INFO ProgressChangeStruct;
- static _ATL_FUNC_INFO NavigateComplete2Struct;
- static _ATL_FUNC_INFO DocumentComplete2Struct;
- static _ATL_FUNC_INFO OnVisibleStruct;
- static _ATL_FUNC_INFO SetSecureLockIconStruct;
- static _ATL_FUNC_INFO NavigateErrorStruct;
- static _ATL_FUNC_INFO PrivacyImpactedStateChangeStruct;
- //static _ATL_FUNC_INFO FileDownloadStruct; // Unsafe to use
- //static _ATL_FUNC_INFO WindowClosingStruct;
- static _ATL_FUNC_INFO KeyUpEventStruct;
- static _ATL_FUNC_INFO MouseOverEventStruct;
- static _ATL_FUNC_INFO ClickEventStruct;
- static _ATL_FUNC_INFO DbClickEventStruct;
- static _ATL_FUNC_INFO MouseOutEventStruct;
- };
- template <UINT nID, class T>
- class ATL_NO_VTABLE EasyDispEventImpl
- {
- DWORD m_dwBrowserEventCookie;
- DWORD m_dwDocumentEventCookie;
- public:
- EasyDispEventImpl():m_dwBrowserEventCookie(0xFEFEFEFE),m_dwDocumentEventCookie(0xFEFEFEFE)
- {}
- STDMETHOD(_LocDEQueryInterface)(REFIID riid, void ** ppvObject)
- {
- ATLASSERT(ppvObject != NULL);
- if (ppvObject == NULL)
- return E_POINTER;
- *ppvObject = NULL;
- if (InlineIsEqualGUID(riid, IID_NULL))
- return E_NOINTERFACE;
- const EVENT_DIID_ENTRY * pMap = T::_GetEventIIDMap();
- const EVENT_DIID_ENTRY * pFound = NULL;
- while (pMap->piid != NULL)
- {
- if(InlineIsEqualGUID(riid,*pMap->piid))
- {
- pFound = pMap;
- break;
- }
- pMap++;
- }
- if (pFound || InlineIsEqualUnknown(riid) || InlineIsEqualGUID(riid, __uuidof(IDispatch)))
- {
- *ppvObject = this;
- AddRef();
- #ifdef _ATL_DEBUG_INTERFACES
- _AtlDebugInterfacesModule.AddThunk((IUnknown**)ppvObject, _T("IDispEventImpl"), riid);
- #endif // _ATL_DEBUG_INTERFACES
- return S_OK;
- }
- else
- return E_NOINTERFACE;
- }
- // These are here only to support use in non-COM objects
- virtual ULONG STDMETHODCALLTYPE AddRef()
- {
- return 1;
- }
- virtual ULONG STDMETHODCALLTYPE Release()
- {
- return 1;
- }
- STDMETHOD(GetTypeInfoCount)(UINT* )
- {ATLTRACENOTIMPL(_T("IDispEventSimpleImpl::GetTypeInfoCount"));}
- STDMETHOD(GetTypeInfo)(UINT , LCID , ITypeInfo** )
- {ATLTRACENOTIMPL(_T("IDispEventSimpleImpl::GetTypeInfo"));}
- STDMETHOD(GetIDsOfNames)(REFIID , LPOLESTR* , UINT ,
- LCID , DISPID* )
- {ATLTRACENOTIMPL(_T("IDispEventSimpleImpl::GetIDsOfNames"));}
- STDMETHOD(Invoke)(DISPID dispidMember, REFIID ,
- LCID lcid, WORD , DISPPARAMS* pdispparams, VARIANT* pvarResult,
- EXCEPINFO* , UINT* )
- {
- const _ATL_EVENT_ENTRY<T>* pMap = T::_GetSinkMap();
- const _ATL_EVENT_ENTRY<T>* pFound = NULL;
- while (pMap->piid != NULL)
- {
- const EVENT_DIID_ENTRY * pEvts = T::_GetEventIIDMap();
- const EVENT_DIID_ENTRY * pFoundEvt = NULL;
- while (pEvts->piid != NULL)
- {
- if(InlineIsEqualGUID(*(pMap->piid),*(pEvts->piid)))
- {
- pFoundEvt = pEvts;
- break;
- }
- pEvts++;
- }
- if ((pMap->nControlID == nID) && (pMap->dispid == dispidMember) && pFoundEvt )
- {
- pFound = pMap;
- break;
- }
- pMap++;
- }
- if (pFound == NULL)
- return S_OK;
- _ATL_FUNC_INFO info;
- _ATL_FUNC_INFO* pInfo;
- if (pFound->pInfo != NULL)
- pInfo = pFound->pInfo;
- else
- {
- pInfo = &info;
- HRESULT hr = GetFuncInfoFromId(*(pFound->piid), dispidMember, lcid, info);
- if (FAILED(hr))
- return S_OK;
- }
- return InvokeFromFuncInfo(pFound->pfn, *pInfo, pdispparams, pvarResult);
- }
- //Helper for invoking the event
- HRESULT InvokeFromFuncInfo(void (__stdcall T::*pEvent)(), _ATL_FUNC_INFO& info, DISPPARAMS* pdispparams, VARIANT* pvarResult)
- {
- ATLASSERT(pdispparams->cArgs == (UINT)info.nParams);
- T* pT = static_cast<T*>(this);
- // If this assert occurs, then add
- // #define _ATL_MAX_VARTYPES nnnn
- // before including atlcom.h
- ATLASSERT(info.nParams <= _ATL_MAX_VARTYPES);
- if (info.nParams > _ATL_MAX_VARTYPES)
- {
- return E_FAIL;
- }
- VARIANTARG* rgVarArgs[_ATL_MAX_VARTYPES];
- VARIANTARG** pVarArgs = info.nParams ? rgVarArgs : 0;
- UINT nIndex = 0;
- #ifndef _ATL_IGNORE_NAMED_ARGS
- for (nIndex; nIndex < pdispparams->cNamedArgs; nIndex++)
- pVarArgs[pdispparams->rgdispidNamedArgs[nIndex]] = &pdispparams->rgvarg[nIndex];
- #endif
- for (; nIndex < pdispparams->cArgs; nIndex++)
- pVarArgs[info.nParams-nIndex-1] = &pdispparams->rgvarg[nIndex];
- CComStdCallThunk<T> thunk;
- thunk.Init(pEvent, pT);
- CComVariant tmpResult;
- if (pvarResult == NULL)
- pvarResult = &tmpResult;
- HRESULT hr = DispCallFunc(
- &thunk,
- 0,
- info.cc,
- info.vtReturn,
- info.nParams,
- info.pVarTypes,
- pVarArgs,
- pvarResult);
- ATLASSERT(SUCCEEDED(hr));
- return hr;
- }
- //Helper for finding the function index for a DISPID
- virtual HRESULT GetFuncInfoFromId(const IID& , DISPID , LCID , _ATL_FUNC_INFO& )
- {
- ATLTRACE(_T("TODO: Classes using IDispEventSimpleImpl should override this method/n"));
- ATLASSERT(0);
- ATLTRACENOTIMPL(_T("IDispEventSimpleImpl::GetFuncInfoFromId"));
- }
- //Helpers for sinking events on random IUnknown*
- HRESULT DispBrowserEventAdvise(IUnknown* pUnk)
- {
- ATLENSURE(m_dwBrowserEventCookie == 0xFEFEFEFE);
- return AtlAdvise(pUnk, (IUnknown*)this,DIID_DWebBrowserEvents2, &m_dwBrowserEventCookie);
- }
- HRESULT DispBrowserEventUnadvise(IUnknown* pUnk)
- {
- HRESULT hr = AtlUnadvise(pUnk,DIID_DWebBrowserEvents2, m_dwBrowserEventCookie);
- m_dwBrowserEventCookie = 0xFEFEFEFE;
- return hr;
- }
- HRESULT DispDocumentEventAdvise(IUnknown* pUnk)
- {
- ATLENSURE(m_dwDocumentEventCookie == 0xFEFEFEFE);
- return AtlAdvise(pUnk, (IUnknown*)this, DIID_HTMLDocumentEvents2, &m_dwDocumentEventCookie);
- }
- HRESULT DispDocumentEventUnadvise(IUnknown* pUnk)
- {
- HRESULT hr = AtlUnadvise(pUnk,DIID_HTMLDocumentEvents2, m_dwDocumentEventCookie);
- m_dwDocumentEventCookie = 0xFEFEFEFE;
- return hr;
- }
- HRESULT DispElementEventAdvise(IUnknown* pUnk, const IID* piid,DWORD * dwCookie)
- {
- ///ATLASSERT(*dwCookie == 0xFEFEFEFE);
- return AtlAdvise(pUnk, (IUnknown*)this, *piid,dwCookie);
- }
- HRESULT DispElementEventUnadvise(IUnknown* pUnk, const IID* piid,DWORD * dwCookie)
- {
- HRESULT hr = AtlUnadvise(pUnk, *piid,*dwCookie);
- *dwCookie = 0xFEFEFEFE;
- return hr;
- }
- };
- #define EASY_SINK_ENTRY(id,iid, dispid,fn,info) {id, &iid,0, dispid, (void (__stdcall _atl_event_classtype::*)())fn, info},
- _ATL_FUNC_INFO DocumentComplete2Struct={CC_STDCALL, VT_EMPTY, 2, {VT_DISPATCH, VT_BYREF|VT_VARIANT}};
- //....
- _ATL_FUNC_INFO ClickEventStruct = {CC_STDCALL, VT_EMPTY, 1, {VT_DISPATCH}};
- class CMyClass : public EasyDispEventImpl<1, CMyClass >
- {
- public:
- BEGIN_SINK_MAP(CMyClass)
- EASY_SINK_ENTRY(1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, __DocumentComplete, &DocumentComplete2Struct)
- EASY_SINK_ENTRY(1, DIID_HTMLDocumentEvents2, DISPID_HTMLELEMENTEVENTS2_ONCLICK, __Click, &ClickEventStruct)
- END_SINK_MAP()
- void __stdcall __DocumentComplete(IDispatch* pDisp, VARIANT* pvURL)
- {
- //TODO...
- }
- void __stdcall __Click(IDispatch* pDisp)
- {
- T* pT = static_cast<T*>(this);
- CComQIPtr<IHTMLEventObj2> evt(pDisp);
- //TODO ....
- }
- };