Sinking Events of DWebBrowserEvent2 supports navigation

I have a problem similar to JimEvans in Event Drop DWebBrowserEvents2 seems to hurt software navigation , but I can't figure out anwser, can someone tell me more about this?

I am manipulating IE Explorer using plaint C ++. Some codes are copied from Codeproject. But my IE hung up when I process events, and I can't get the DISPID_NAVIGETCOMPLETE event until my main function completes.

My code is below:

#include <afxwin.h> #include <afxdisp.h> #include <iostream> #include <MsHTML.h> #include <Exdisp.h> #include <ExDispid.h> class IE_Events_Sinker : public DWebBrowserEvents2 { public: // No constructor or destructor is needed // IUnknown methods STDMETHODIMP QueryInterface(REFIID riid,void **ppvObject); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release(); // IDispatch methods STDMETHODIMP GetTypeInfoCount(UINT *pctinfo); STDMETHODIMP GetTypeInfo(UINT iTInfo,LCID lcid,ITypeInfo **ppTInfo); STDMETHODIMP GetIDsOfNames(REFIID riid,LPOLESTR *rgszNames,UINT cNames,LCID lcid,DISPID *rgDispId); STDMETHODIMP Invoke(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags, DISPPARAMS *pDispParams,VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT *puArgErr); }; IE_Events_Sinker IESinker; STDMETHODIMP IE_Events_Sinker::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr ) { switch(dispIdMember) { case DISPID_NAVIGATEERROR: { //Extract the status code from the DISPPARAMS structure VARIANT * vt_statuscode = pDispParams->rgvarg[1].pvarVal; DWORD dwStatusCode = vt_statuscode->lVal; //Extract the event IDispatch pointer IDispatch *pdispFiredEvent = pDispParams->rgvarg[4].pdispVal; printf("Status Code: %d\n", dwStatusCode); break; } case DISPID_NAVIGATECOMPLETE2: printf("Navigate Complete!\n"); break; case DISPID_BEFORENAVIGATE2: printf("Before Navigate is fired!\n"); break; default: //MessageBox(NULL, L"A Message", NULL, NULL); printf("A Message !\n the dispIdMemberis %d\n", dispIdMember); break; } return S_OK; } STDMETHODIMP IE_Events_Sinker::QueryInterface(REFIID riid,void **ppvObject) { // Check if ppvObject is a valid pointer if(IsBadWritePtr(ppvObject,sizeof(void*))) return E_POINTER; // Set *ppvObject to NULL (*ppvObject)=NULL; // See if the requested IID matches one that we support // If it doesn't return E_NOINTERFACE if(!IsEqualIID(riid,IID_IUnknown) && !IsEqualIID(riid,IID_IDispatch) && !IsEqualIID(riid,DIID_DWebBrowserEvents2)) return E_NOINTERFACE; // If it a matching IID, set *ppvObject to point to the global EventSink object (*ppvObject)=(void*)&IESinker; return S_OK; } STDMETHODIMP_(ULONG) IE_Events_Sinker::AddRef() { return 1; // We always have just one static object } STDMETHODIMP_(ULONG) IE_Events_Sinker::Release() { return 1; // Ditto } // We don't need to implement the next three methods because we are just a pure event sink // We only care about Invoke() which is what IE calls to notify us of events STDMETHODIMP IE_Events_Sinker::GetTypeInfoCount(UINT *pctinfo) { UNREFERENCED_PARAMETER(pctinfo); return E_NOTIMPL; } STDMETHODIMP IE_Events_Sinker::GetTypeInfo(UINT iTInfo,LCID lcid,ITypeInfo **ppTInfo) { UNREFERENCED_PARAMETER(iTInfo); UNREFERENCED_PARAMETER(lcid); UNREFERENCED_PARAMETER(ppTInfo); return E_NOTIMPL; } STDMETHODIMP IE_Events_Sinker::GetIDsOfNames(REFIID riid,LPOLESTR *rgszNames,UINT cNames,LCID lcid,DISPID *rgDispId) { UNREFERENCED_PARAMETER(riid); UNREFERENCED_PARAMETER(rgszNames); UNREFERENCED_PARAMETER(cNames); UNREFERENCED_PARAMETER(lcid); UNREFERENCED_PARAMETER(rgDispId); return E_NOTIMPL; } int main() { HRESULT hr; IWebBrowser2* IWbr; IConnectionPointContainer* pCPContainer; IConnectionPoint* m_pConnectionPoint; CoInitialize(NULL); //hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, (void**)&IWbr); hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, (void**)&IWbr); IWbr->put_Visible(TRUE); hr = IWbr->QueryInterface(IID_IConnectionPointContainer, (void**)&pCPContainer); hr = pCPContainer->FindConnectionPoint(DIID_DWebBrowserEvents2, &m_pConnectionPoint); //Important Point! DWORD m_dwCookie; m_pConnectionPoint->Advise(&IESinker, &m_dwCookie); COleVariant vtEmpty; BSTR url2 = SysAllocString(L"http://www.qq.com/"); IWbr->Navigate(url2, &vtEmpty, &vtEmpty, &vtEmpty, &vtEmpty); Sleep(20000); //hr = IWbr->Quit(); //while(FAILED(hr)) //{ //a++; //hr = IWbr->Quit(); //} //printf("shut down %d times\n", a); m_pConnectionPoint->Unadvise(m_dwCookie); m_pConnectionPoint->Release(); IWbr->Release(); pCPContainer->Release(); CoUninitialize(); } 
+1
source share
1 answer

The problem and the answer to this question that you are talking about concern the processing of window messages in a stream with your activity, the so-called "message pump". You do:

 Sleep(20000); 

And that is the cause of the problem. Instead, you should wait. And you should process window messages while waiting. Instead, it should be a loop with these dispatch messages:

 MSG Message; while(PeekMessage(&Message, NULL, WM_NULL, WM_NULL, PM_REMOVE)) { TranslateMessage(&Message); DispatchMessage(&Message); } 

In this way, messages in a window that IE or COM could send as part of processing your request have reached the target windows and will be processed. Instead, you block the thread, giving it the ability to not do what it should do. However, the loop above only sends messages once, so if you need a timeout, you can do it like an endless loop waking up with some sign of success or processing failure, or a loop based on an event that wakes up the message and goes back to sleep. without losing processor cycles.

That is, your Sleep was still processing window messages for 20 seconds, it may have been like this (the fragment should be good for copy / paste to replace):

 const ULONG nTimeoutTime = GetTickCount() + 20 * 1000; // In 20 seconds const HANDLE hFakeEvent = CreateEvent(NULL, TRUE, FALSE, NULL); for(; ; ) { const LONG nWaitTime = nTimeoutTime - GetTickCount(); if(nWaitTime <= 0) break; // Timeout const DWORD nWaitResult = MsgWaitForMultipleObjects(1, &hFakeEvent, FALSE, nWaitTime, QS_ALLINPUT | QS_ALLPOSTMESSAGE); //ATLTRACE(_T("nWaitResult 0x%x\n"), nWaitResult); //ATLASSERT(nWaitResult == WAIT_OBJECT_0 + 1 || nWaitResult == WAIT_TIMEOUT); if(nWaitResult == WAIT_TIMEOUT) break; // Timeout MSG Message; while(PeekMessage(&Message, NULL, WM_NULL, WM_NULL, PM_REMOVE)) { //ATLTRACE(_T("Message.hwnd 0x%p, Message.message 0x%04x\n"), Message.hwnd, Message.message); TranslateMessage(&Message); DispatchMessage(&Message); } } CloseHandle(hFakeEvent); 
+3
source

Source: https://habr.com/ru/post/1441370/


All Articles