天天看点

WebBroswer2 事件处理

 这两天写一个辅助工具,用到了WebBrowser2控件,需要对DIID_DWebBrowserEvents2事件、DIID_HTMLDocumentEvents2进行处理

ATL提供了IDispEventSimpleImpl模板来简化事件处理,但是这个模板只能绑定一个事件,google了半天也没有找到好的解决方案,索性参考IDispEventSimpleImpl DIY了一个EasyDispEventImpl模板代码如下:

    1. struct EVENT_DIID_ENTRY
    2. {   
    3.     const IID* piid;
    4. };
    5. #define BEGIN_EVENT_IID_MAP(_class)/
    6.     typedef _class _GetEventIIDMapFinder;/
    7.     static const EVENT_DIID_ENTRY * _GetEventIIDMap()/
    8.     {/
    9.         typedef _class _atl_event_classtype;/
    10.         static const EVENT_DIID_ENTRY __map[] = {
    11. #define EVENT_IID_ENTRY(iid) {&iid},
    12. #define END_EVENT_IID_MAP() /
    13.     {NULL} }; return __map;/
    14. }
    15. class CWebBrowser2EventsBase
    16. {
    17. protected:
    18.     static _ATL_FUNC_INFO StatusTextChangeStruct;
    19.     static _ATL_FUNC_INFO TitleChangeStruct;
    20.     static _ATL_FUNC_INFO PropertyChangeStruct;
    21.     static _ATL_FUNC_INFO OnQuitStruct;
    22.     static _ATL_FUNC_INFO OnToolBarStruct;
    23.     static _ATL_FUNC_INFO OnMenuBarStruct;
    24.     static _ATL_FUNC_INFO OnStatusBarStruct;
    25.     static _ATL_FUNC_INFO OnFullScreenStruct;
    26.     static _ATL_FUNC_INFO OnTheaterModeStruct;
    27.     static _ATL_FUNC_INFO DownloadBeginStruct;
    28.     static _ATL_FUNC_INFO DownloadCompleteStruct;
    29.     static _ATL_FUNC_INFO NewWindow2Struct; 
    30.     static _ATL_FUNC_INFO CommandStateChangeStruct;
    31.     static _ATL_FUNC_INFO BeforeNavigate2Struct;
    32.     static _ATL_FUNC_INFO ProgressChangeStruct;
    33.     static _ATL_FUNC_INFO NavigateComplete2Struct;
    34.     static _ATL_FUNC_INFO DocumentComplete2Struct;
    35.     static _ATL_FUNC_INFO OnVisibleStruct;
    36.     static _ATL_FUNC_INFO SetSecureLockIconStruct;
    37.     static _ATL_FUNC_INFO NavigateErrorStruct;
    38.     static _ATL_FUNC_INFO PrivacyImpactedStateChangeStruct;
    39.     //static _ATL_FUNC_INFO FileDownloadStruct;   // Unsafe to use
    40.     //static _ATL_FUNC_INFO WindowClosingStruct;
    41.     static _ATL_FUNC_INFO KeyUpEventStruct; 
    42.     static _ATL_FUNC_INFO MouseOverEventStruct; 
    43.     static _ATL_FUNC_INFO ClickEventStruct;     
    44.     static _ATL_FUNC_INFO DbClickEventStruct;       
    45.     static _ATL_FUNC_INFO MouseOutEventStruct;      
    46. };
    47. template <UINT nID, class T>
    48. class ATL_NO_VTABLE EasyDispEventImpl
    49. {
    50.     DWORD m_dwBrowserEventCookie;
    51.     DWORD m_dwDocumentEventCookie;
    52. public:
    53.     EasyDispEventImpl():m_dwBrowserEventCookie(0xFEFEFEFE),m_dwDocumentEventCookie(0xFEFEFEFE)
    54.     {}
    55.     STDMETHOD(_LocDEQueryInterface)(REFIID riid, void ** ppvObject)
    56.     {
    57.         ATLASSERT(ppvObject != NULL);
    58.         if (ppvObject == NULL)
    59.             return E_POINTER;
    60.         *ppvObject = NULL;
    61.         if (InlineIsEqualGUID(riid, IID_NULL))
    62.             return E_NOINTERFACE;
    63.         const EVENT_DIID_ENTRY * pMap = T::_GetEventIIDMap();
    64.         const EVENT_DIID_ENTRY * pFound = NULL;
    65.         while (pMap->piid != NULL)
    66.         {
    67.             if(InlineIsEqualGUID(riid,*pMap->piid))
    68.             {
    69.                 pFound = pMap;
    70.                 break;
    71.             }
    72.             pMap++;
    73.         }
    74.         if (pFound || InlineIsEqualUnknown(riid) || InlineIsEqualGUID(riid, __uuidof(IDispatch)))
    75.         {
    76.             *ppvObject = this;
    77.             AddRef();
    78. #ifdef _ATL_DEBUG_INTERFACES
    79.             _AtlDebugInterfacesModule.AddThunk((IUnknown**)ppvObject, _T("IDispEventImpl"), riid);
    80. #endif // _ATL_DEBUG_INTERFACES
    81.             return S_OK;
    82.         }
    83.         else
    84.             return E_NOINTERFACE;
    85.     }
    86.     // These are here only to support use in non-COM objects    
    87.     virtual ULONG STDMETHODCALLTYPE AddRef()
    88.     {
    89.         return 1;
    90.     }
    91.     virtual ULONG STDMETHODCALLTYPE Release()
    92.     {
    93.         return 1;
    94.     }
    95.     STDMETHOD(GetTypeInfoCount)(UINT* )
    96.     {ATLTRACENOTIMPL(_T("IDispEventSimpleImpl::GetTypeInfoCount"));}
    97.     STDMETHOD(GetTypeInfo)(UINT , LCID , ITypeInfo** )
    98.     {ATLTRACENOTIMPL(_T("IDispEventSimpleImpl::GetTypeInfo"));}
    99.     STDMETHOD(GetIDsOfNames)(REFIID , LPOLESTR* , UINT ,
    100.         LCID , DISPID* )
    101.     {ATLTRACENOTIMPL(_T("IDispEventSimpleImpl::GetIDsOfNames"));}
    102.     STDMETHOD(Invoke)(DISPID dispidMember, REFIID ,
    103.         LCID lcid, WORD , DISPPARAMS* pdispparams, VARIANT* pvarResult,
    104.         EXCEPINFO* , UINT* )
    105.     {
    106.         const _ATL_EVENT_ENTRY<T>* pMap = T::_GetSinkMap();
    107.         const _ATL_EVENT_ENTRY<T>* pFound = NULL;       
    108.         while (pMap->piid != NULL)
    109.         {
    110.             const EVENT_DIID_ENTRY * pEvts = T::_GetEventIIDMap();
    111.             const EVENT_DIID_ENTRY * pFoundEvt = NULL;
    112.             while (pEvts->piid != NULL)
    113.             {
    114.                 if(InlineIsEqualGUID(*(pMap->piid),*(pEvts->piid)))
    115.                 {
    116.                     pFoundEvt = pEvts;
    117.                     break;
    118.                 }
    119.                 pEvts++;
    120.             }
    121.             if ((pMap->nControlID == nID) && (pMap->dispid == dispidMember) && pFoundEvt )
    122.             {               
    123.                 pFound = pMap;
    124.                 break;
    125.             }
    126.             pMap++;
    127.         }
    128.         if (pFound == NULL)
    129.             return S_OK;
    130.         _ATL_FUNC_INFO info;
    131.         _ATL_FUNC_INFO* pInfo;
    132.         if (pFound->pInfo != NULL)
    133.             pInfo = pFound->pInfo;
    134.         else
    135.         {
    136.             pInfo = &info;
    137.             HRESULT hr = GetFuncInfoFromId(*(pFound->piid), dispidMember, lcid, info);
    138.             if (FAILED(hr))
    139.                 return S_OK;
    140.         }
    141.         return InvokeFromFuncInfo(pFound->pfn, *pInfo, pdispparams, pvarResult);
    142.     }
    143.     //Helper for invoking the event
    144.     HRESULT InvokeFromFuncInfo(void (__stdcall T::*pEvent)(), _ATL_FUNC_INFO& info, DISPPARAMS* pdispparams, VARIANT* pvarResult)
    145.     {
    146.         ATLASSERT(pdispparams->cArgs == (UINT)info.nParams);
    147.         T* pT = static_cast<T*>(this);
    148.         // If this assert occurs, then add 
    149.         // #define _ATL_MAX_VARTYPES nnnn
    150.         // before including atlcom.h
    151.         ATLASSERT(info.nParams <= _ATL_MAX_VARTYPES);
    152.         if (info.nParams > _ATL_MAX_VARTYPES)
    153.         {
    154.             return E_FAIL;
    155.         }
    156.         VARIANTARG* rgVarArgs[_ATL_MAX_VARTYPES];
    157.         VARIANTARG** pVarArgs = info.nParams ? rgVarArgs : 0;
    158.         UINT nIndex = 0;
    159. #ifndef _ATL_IGNORE_NAMED_ARGS
    160.         for (nIndex; nIndex < pdispparams->cNamedArgs; nIndex++)
    161.             pVarArgs[pdispparams->rgdispidNamedArgs[nIndex]] = &pdispparams->rgvarg[nIndex];
    162. #endif
    163.         for (; nIndex < pdispparams->cArgs; nIndex++)
    164.             pVarArgs[info.nParams-nIndex-1] = &pdispparams->rgvarg[nIndex];
    165.         CComStdCallThunk<T> thunk;
    166.         thunk.Init(pEvent, pT);
    167.         CComVariant tmpResult;
    168.         if (pvarResult == NULL)
    169.             pvarResult = &tmpResult;
    170.         HRESULT hr = DispCallFunc(
    171.             &thunk,
    172.             0,
    173.             info.cc,
    174.             info.vtReturn,
    175.             info.nParams,
    176.             info.pVarTypes,
    177.             pVarArgs,
    178.             pvarResult);
    179.         ATLASSERT(SUCCEEDED(hr));
    180.         return hr;
    181.     }
    182.     //Helper for finding the function index for a DISPID
    183.     virtual HRESULT GetFuncInfoFromId(const IID& , DISPID , LCID , _ATL_FUNC_INFO& )
    184.     {
    185.         ATLTRACE(_T("TODO: Classes using IDispEventSimpleImpl should override this method/n"));
    186.         ATLASSERT(0);
    187.         ATLTRACENOTIMPL(_T("IDispEventSimpleImpl::GetFuncInfoFromId"));
    188.     }
    189.     //Helpers for sinking events on random IUnknown*
    190.     HRESULT DispBrowserEventAdvise(IUnknown* pUnk)
    191.     {
    192.         ATLENSURE(m_dwBrowserEventCookie == 0xFEFEFEFE);        
    193.         return AtlAdvise(pUnk, (IUnknown*)this,DIID_DWebBrowserEvents2, &m_dwBrowserEventCookie);
    194.     }
    195.     HRESULT DispBrowserEventUnadvise(IUnknown* pUnk)
    196.     {
    197.         HRESULT hr = AtlUnadvise(pUnk,DIID_DWebBrowserEvents2, m_dwBrowserEventCookie);
    198.         m_dwBrowserEventCookie = 0xFEFEFEFE;
    199.         return hr;
    200.     }
    201.     HRESULT DispDocumentEventAdvise(IUnknown* pUnk)
    202.     {
    203.         ATLENSURE(m_dwDocumentEventCookie == 0xFEFEFEFE);       
    204.         return AtlAdvise(pUnk, (IUnknown*)this, DIID_HTMLDocumentEvents2, &m_dwDocumentEventCookie);
    205.     }
    206.     HRESULT DispDocumentEventUnadvise(IUnknown* pUnk)
    207.     {
    208.         HRESULT hr = AtlUnadvise(pUnk,DIID_HTMLDocumentEvents2, m_dwDocumentEventCookie);
    209.         m_dwDocumentEventCookie = 0xFEFEFEFE;
    210.         return hr;
    211.     }
    212.     HRESULT DispElementEventAdvise(IUnknown* pUnk, const IID* piid,DWORD * dwCookie)
    213.     {       
    214.         ///ATLASSERT(*dwCookie == 0xFEFEFEFE);
    215.         return AtlAdvise(pUnk, (IUnknown*)this, *piid,dwCookie);
    216.     }
    217.     HRESULT DispElementEventUnadvise(IUnknown* pUnk, const IID* piid,DWORD * dwCookie)
    218.     {
    219.         HRESULT hr = AtlUnadvise(pUnk, *piid,*dwCookie);
    220.         *dwCookie = 0xFEFEFEFE;
    221.         return hr;
    222.     }
    223. };
    224. #define EASY_SINK_ENTRY(id,iid, dispid,fn,info) {id, &iid,0, dispid, (void (__stdcall _atl_event_classtype::*)())fn, info},
    EASY_SINK_ENTRY 是SINK_ENTRY_INFO的替代物,因为我们自定了_ATL_EVENT_ENTRY结构的pInfo成员,因此nOffset可以为了0了。使用方法:
  1. _ATL_FUNC_INFO DocumentComplete2Struct={CC_STDCALL, VT_EMPTY, 2, {VT_DISPATCH, VT_BYREF|VT_VARIANT}};
  2. //....
  3. _ATL_FUNC_INFO ClickEventStruct = {CC_STDCALL, VT_EMPTY, 1, {VT_DISPATCH}};
  4. class CMyClass : public EasyDispEventImpl<1, CMyClass > 
  5. {
  6. public:
  7.     BEGIN_SINK_MAP(CMyClass)    
  8.         EASY_SINK_ENTRY(1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, __DocumentComplete, &DocumentComplete2Struct)
  9.         EASY_SINK_ENTRY(1, DIID_HTMLDocumentEvents2, DISPID_HTMLELEMENTEVENTS2_ONCLICK, __Click, &ClickEventStruct)
  10.     END_SINK_MAP()
  11. void __stdcall __DocumentComplete(IDispatch* pDisp, VARIANT* pvURL)
  12.     {
  13.         //TODO...
  14.     }
  15.   void __stdcall __Click(IDispatch* pDisp)
  16.     {
  17.         T* pT = static_cast<T*>(this);
  18.         CComQIPtr<IHTMLEventObj2> evt(pDisp);
  19.                 //TODO .... 
  20.     }
  21. };