IE9 fails to fire onscroll event on HTMLWindow2 in BHO
-
2. března 2012 19:56
I encountered a problem when developing a IE9 plugin BHO.
IE can fire onscroll event when using Document Mode: IE7 or IE8, but fail to fire onscroll event when using Document Mode: IE9. I also register the onscroll event on documentElement, it reacts the same way.
The BHO class uses:
public IDispEventImpl<3, CHelloWorldBHO, &DIID_HTMLWindowEvents2, &LIBID_MSHTML, 4, 0>.And sink the event:
BEGIN_SINK_MAP(CHelloWorldBHO)
SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_NAVIGATECOMPLETE2, OnNavigateComplete2)
SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_WINDOWSTATECHANGED, OnWindowStateChanged)
SINK_ENTRY_EX(3, DIID_HTMLWindowEvents2, DISPID_HTMLWINDOWEVENTS2_ONSCROLL, OnScroll)
END_SINK_MAP()Then Advise it to the window object in Document Complete:
CComQIPtr<IHTMLDocument2> spHTMLDoc = spDispDoc;
CComQIPtr<IHTMLWindow2> spTempWindow2;
spHTMLDoc->get_parentWindow(&spTempWindow2);
IDispEventImpl<3, CHelloWorldBHO, &DIID_HTMLWindowEvents2, &LIBID_MSHTML, 4, 0>::DispEventAdvise(spTempWindow2);I have been working on this problem for quite a while. Any ideas? Thanks so much!
- Upravený Hugo Liu 2. března 2012 19:59 Incomplete information
Všechny reakce
-
5. března 2012 3:25
As far as I know. There is no answer for this question.
You can only get the position value of scroll but the event.
NEU_ShieldEdge
-
6. března 2012 17:35
Hi, I'm also having problem with IE9 and document mode: IE9
I managed to obtain the scroll event, by deriving a class from IDispatch, and attaching the event with the new addEventListener...
hr = _spDocument->get_parentWindow(reinterpret_cast<IHTMLWindow2 **>(&_spWindow)); if (SUCCEEDED(hr) && _spWindow) { CComPtr<IEventTarget> spIEventTarget; hr = _spWindow->QueryInterface(IID_IEventTarget, reinterpret_cast<void **>(&spIEventTarget)); if (SUCCEEDED(hr) && spIEventTarget) { _pIEUIEventListener = new CIEUIEventListener(); // This class derives from IDispatch hr = spIEventTarget->addEventListener(_bstr_t("scroll"), _pIEUIEventListener, VARIANT_TRUE); if (SUCCEEDED(hr)) { ... } } }
and then on the invoke...HRESULT STDMETHODCALLTYPE CIEUIEventListener::Invoke( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) { if(dispIdMember == 0) { ... } return S_OK; }Now the problem is that according to msdn I should receive in the arguments two parameters the target, and the event, but the count of dispparams is always 0 :(
For the scroll event, that isn't a problem but I'm trying to capture MutationEvents and I really need to know for example what node was inserted, and I don't want to keep a "hash" of the nodes before and do a full dom search to check for changes...
- Upravený jaugusto.pt 6. března 2012 17:35
- Označen jako odpověď Hugo Liu 14. března 2012 5:03
-
11. března 2012 8:33
Hi Augusto,
I also read your post on stack overflow, it gave me a basic sense about the problem.
But I'm not quite sure about how to achieve it in practice. Would you please give me more codes or instructions on how to construct the class <CIEUIEventListener>, derive from IDispatchEx and implement those abstract methods?
I worked in VS2010 and used ATL simple object, but I'm not sure whether this is right or not. Sorry I'm kind of new to this area. Many many thanks to your kind help.
Regards
Hugo
-
12. března 2012 9:52
Hi,
This is my base sink for the IE9 Events
.h
class CIE9EventListener : public IDispatchEx { public: CIE9EventListener(void); virtual ~CIE9EventListener(void); virtual bool AddEventListener(CComPtr<IEventTarget> spIEventTarget) = 0; virtual bool RemoveEventListener() = 0; // IUnknown HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject); ULONG STDMETHODCALLTYPE AddRef(void); ULONG STDMETHODCALLTYPE Release(void); // IDispatch HRESULT STDMETHODCALLTYPE GetTypeInfoCount(__RPC__out UINT *pctinfo); HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, __RPC__deref_out_opt ITypeInfo **ppTInfo); HRESULT STDMETHODCALLTYPE GetIDsOfNames( __RPC__in REFIID riid, __RPC__in_ecount_full(cNames) LPOLESTR *rgszNames, __RPC__in_range(0,16384) UINT cNames, LCID lcid, __RPC__out_ecount_full(cNames) DISPID *rgDispId); HRESULT STDMETHODCALLTYPE Invoke( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr); // IDispatchEx HRESULT STDMETHODCALLTYPE GetDispID(__RPC__in BSTR, DWORD, __RPC__out DISPID*); HRESULT STDMETHODCALLTYPE DeleteMemberByName(__RPC__in BSTR, DWORD); HRESULT STDMETHODCALLTYPE DeleteMemberByDispID(DISPID); HRESULT STDMETHODCALLTYPE GetMemberProperties(DISPID, DWORD, __RPC__out DWORD*); HRESULT STDMETHODCALLTYPE GetMemberName(DISPID, __RPC__deref_out_opt BSTR*); HRESULT STDMETHODCALLTYPE GetNextDispID(DWORD, DISPID, __RPC__out DISPID*); HRESULT STDMETHODCALLTYPE GetNameSpaceParent(__RPC__deref_out_opt IUnknown **); virtual HRESULT STDMETHODCALLTYPE InvokeEx( __in DISPID, __in LCID, __in WORD, __in DISPPARAMS*, __out_opt VARIANT*, __out_opt EXCEPINFO*, __in_opt IServiceProvider*) = 0; protected: long _lRef; bool _bIsAdvised; CComPtr<IEventTarget> _spIEventTarget; };.cpp
CIE9EventListener::CIE9EventListener(void) { _lRef = 0; _bIsAdvised = false; } CIE9EventListener::~CIE9EventListener(void) { } ////////////////////////////////////////////////////////////////////// // QueryInterface ////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE CIE9EventListener::QueryInterface(REFIID riid, __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject) { *ppvObject = NULL; if(IsEqualGUID(riid, IID_IUnknown)) *ppvObject = reinterpret_cast<void**>(this); if(IsEqualGUID(riid, IID_IDispatch)) *ppvObject = reinterpret_cast<void**>(this); if(IsEqualGUID(riid, IID_IDispatchEx)) *ppvObject = reinterpret_cast<void**>(this); if(*ppvObject) { ((IUnknown*)*ppvObject)->AddRef(); return S_OK; } return E_NOINTERFACE; } ////////////////////////////////////////////////////////////////////// // AddRef ////////////////////////////////////////////////////////////////////// ULONG STDMETHODCALLTYPE CIE9EventListener::AddRef() { return InterlockedIncrement(&_lRef); } ////////////////////////////////////////////////////////////////////// // Release ////////////////////////////////////////////////////////////////////// ULONG STDMETHODCALLTYPE CIE9EventListener::Release() { if (InterlockedDecrement(&_lRef) == 0) { delete this; return 0; } return _lRef; } ////////////////////////////////////////////////////////////////////// // GetTypeInfoCount ////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE CIE9EventListener::GetTypeInfoCount(__RPC__out UINT *pctinfo) { return E_NOTIMPL; } ////////////////////////////////////////////////////////////////////// // GetTypeInfo ////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE CIE9EventListener::GetTypeInfo(UINT iTInfo, LCID lcid, __RPC__deref_out_opt ITypeInfo **ppTInfo) { return E_NOTIMPL; } ////////////////////////////////////////////////////////////////////// // GetIDsOfNames ////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE CIE9EventListener::GetIDsOfNames(__RPC__in REFIID riid, __RPC__in_ecount_full(cNames) LPOLESTR *rgszNames, __RPC__in_range(0,16384) UINT cNames, LCID lcid, __RPC__out_ecount_full(cNames) DISPID *rgDispId) { return S_OK; } ////////////////////////////////////////////////////////////////////// // Invoke ////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE CIE9EventListener::Invoke( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) { return S_OK; } ////////////////////////////////////////////////////////////////////// // GetDispID ////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE CIE9EventListener::GetDispID(__RPC__in BSTR bstrName, DWORD grfdex, __RPC__out DISPID *pid) { return E_NOTIMPL; } ////////////////////////////////////////////////////////////////////// // DeleteMemberByName ////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE CIE9EventListener::DeleteMemberByName(__RPC__in BSTR bstrName, DWORD grfdex) { return E_NOTIMPL; } ////////////////////////////////////////////////////////////////////// // DeleteMemberByDispID ////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE CIE9EventListener::DeleteMemberByDispID(DISPID id) { return E_NOTIMPL; } ////////////////////////////////////////////////////////////////////// // GetMemberProperties ////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE CIE9EventListener::GetMemberProperties(DISPID id, DWORD grfdexFetch, __RPC__out DWORD *pgrfdex) { return E_NOTIMPL; } ////////////////////////////////////////////////////////////////////// // GetMemberName ////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE CIE9EventListener::GetMemberName(DISPID id, __RPC__deref_out_opt BSTR *pbstrName) { return E_NOTIMPL; } ////////////////////////////////////////////////////////////////////// // GetNextDispID ////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE CIE9EventListener::GetNextDispID(DWORD grfdex, DISPID id, __RPC__out DISPID *pid) { return E_NOTIMPL; } ////////////////////////////////////////////////////////////////////// // GetNameSpaceParent ////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE CIE9EventListener::GetNameSpaceParent(__RPC__deref_out_opt IUnknown **ppunk) { return E_NOTIMPL; }Then just create classes from this one, for example I created one to deal with the UIEvents (I removed some code, but left the one for scroll)
.h
class CIE9UIEvent : public CIE9EventListener { public: enum enumUIEvent { UIEventScroll = 1 }; public: CIE9UIEvent(CIEPage* pObjPage, enumUIEvent eType); ~CIE9UIEvent(void); bool AddEventListener(CComPtr<IEventTarget> spIEventTarget); bool RemoveEventListener(); // IDispatchEx HRESULT STDMETHODCALLTYPE InvokeEx( __in DISPID, __in LCID, __in WORD, __in DISPPARAMS*, __out_opt VARIANT*, __out_opt EXCEPINFO*, __in_opt IServiceProvider*); private: enumUIEvent _eType; CIEPage* _pObjPage; };.cpp
CIE9UIEvent::CIE9UIEvent(CIEPage* pObjPage, enumUIEvent eType) { _eType = eType; _pObjPage = pObjPage; } CIE9UIEvent::~CIE9UIEvent(void) { } ////////////////////////////////////////////////////////////////////// // AddEventListener ////////////////////////////////////////////////////////////////////// bool CIE9UIEvent::AddEventListener(CComPtr<IEventTarget> spIEventTarget) { _spIEventTarget = spIEventTarget; CComPtr<IDispatch> spIDispatch; HRESULT hr = this->QueryInterface(IID_IDispatch, reinterpret_cast<void **>(&spIDispatch)); if (SUCCEEDED(hr) && spIDispatch) { BSTR bstrType = _bstr_t(""); switch(_eType) { case UIEventScroll: bstrType = _bstr_t("scroll"); break; } hr = _spIEventTarget->addEventListener(bstrType, spIDispatch, VARIANT_TRUE); if (SUCCEEDED(hr)) { _bIsAdvised = true; return true; } } return false; } ////////////////////////////////////////////////////////////////////// // RemoveEventListener ////////////////////////////////////////////////////////////////////// bool CIE9UIEvent::RemoveEventListener() { if(_spIEventTarget) { CComPtr<IDispatch> spIDispatch; HRESULT hr = this->QueryInterface(IID_IDispatch, reinterpret_cast<void **>(&spIDispatch)); if (SUCCEEDED(hr) && spIDispatch) { BSTR bstrType = _bstr_t(""); switch(_eType) { case UIEventScroll: bstrType = _bstr_t("scroll"); break; } hr = _spIEventTarget->removeEventListener(bstrType, spIDispatch, VARIANT_TRUE); if (SUCCEEDED(hr)) { _bIsAdvised = false; return true; } } } return false; } ////////////////////////////////////////////////////////////////////// // InvokeEx ////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE CIE9UIEvent::InvokeEx( __in DISPID dispIdMember, __in LCID lcid, __in WORD wFlags, __in DISPPARAMS* pDispParams, __out_opt VARIANT *pvarRes, __out_opt EXCEPINFO *pei, __in_opt IServiceProvider *pspCaller) { if(dispIdMember == 0 && pDispParams->cArgs == 2) { if(pDispParams->rgvarg[1].vt == VT_DISPATCH && pDispParams->rgvarg[1].pdispVal) { CComPtr<IDOMEvent> spIDOMEvent; HRESULT hr = pDispParams->rgvarg[1].pdispVal->QueryInterface(IID_IDOMEvent, reinterpret_cast<void **>(&spIDOMEvent)); if(SUCCEEDED(hr) && spIDOMEvent) _pObjPage->OnScroll(NULL); } } return S_OK; }
- Označen jako odpověď Hugo Liu 14. března 2012 5:03
-
14. března 2012 5:13
Hi João,
I managed to solve this problem successfully by your priceless codes! You are really awesome! I have no further comments for this problem, as your answer and code are more than enough for solving it.
This approach is much more complicated than the conventional one. Anyway, I marked your reply as answers. I'm sorry that currently I might not be able to mark your answer at stackoverflow.com, coz I lost that account. I tried my every email account but failed to get it back. I'll mark it if I find it someday.
Thank you so so much!
Best regards,
Hugo