Detecting the IE Refresh button using IWebBrowser2 and DWebBrowserEvents2 events.






4.61/5 (16 votes)
Feb 6, 2003
2 min read

277481

5958
An article explaining how to capture a click on Internet Exporer's Refresh button, using DWebBrowserEvents2.
Introduction
If you have ever tried to capture an event from the Internet Explorer web browser when a user clicks the Refresh button, you will know it is not easy. Capturing Internet Explorer events is generally not easy using MFC or COM. I have created a class that I use to capture DWebBrowserEvents2
events and the logic needed to detect a page refresh. There are no events specifically sent for a page refresh and the normal events you check for do not work. So you have to use a work around. My class is called CIEComCtrlSink
. It is derived from CCmdTarget
and is used to capture DWebBrowserEvents2
events. You can also use the logic to solve this problem in JavaScript etc.
Background
I did some searching on the Internet for a solution to this Microsoft bug/issue and only found some talk of a workout in Google newsgroups. So after I got it working, I thought I better throw the solution up on CodeProject.
Using the code
In the sample application, I just used an MFC Wizard to create a new Dialog project. In the file IERefreshSampleDlg.cpp I respond to a button click and create a new web browser object and advise it we want events from it.
// create the browser and event sink BOOL CIERefreshSampleDlg::CreateMyIEBrowser() { if(m_pMyIESink != NULL) { AfxMessageBox("Sorry just one browser in this sample :)"); return false; } m_pMyIESink = new CIEComCtrlSink(); m_pMyIESink->m_pParent = this; BOOL bOK = m_pMyIESink->MyAdviseSink(); return bOK; }
The CIEComCtrlSink
class does all the work. It is derived from CCmdTarget
so we can get events from DWebBrowserEvents2
object.
// start capture of DWebBrowserEvents2 events BOOL CIEComCtrlSink::MyAdviseSink() { // create the web browser using IWebBrowser2 HRESULT hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, (void**)&m_pWebBrowser2); if(!SUCCEEDED(hr)) { CString strMsg; strMsg.Format("Failed to create object error = %d",(int)hr); AfxMessageBox(strMsg); return false; } // get an interface to IWebBrowserApp so we can set the toolbars we want hr = m_pWebBrowser2->QueryInterface(IID_IWebBrowserApp, (void**)&m_pIEApp); hr = m_pIEApp->put_StatusBar(true); hr = m_pIEApp->put_ToolBar(true); hr = m_pIEApp->put_MenuBar(true); long hIE; // get a window handle so we can resize and show the browser window. hr = m_pWebBrowser2->get_HWND(&hIE); if(!SUCCEEDED(hr)) { CString strMsg; strMsg.Format("Failed to create object error = %d",(int)hr); AfxMessageBox(strMsg); return FALSE; } // use CWnd to make showing the window etc easy m_wndWebBrowser.Attach((HWND)hIE); m_wndWebBrowser.EnableScrollBar(SB_BOTH, ESB_DISABLE_BOTH); m_wndWebBrowser.ShowWindow(SW_NORMAL); // navigate to a URL Navigate2("http://www.stevefoxover.com"); // advise the browser to send events here LPUNKNOWN pUnkSink = GetIDispatch(FALSE); AfxConnectionAdvise((LPUNKNOWN)m_pWebBrowser2, DIID_DWebBrowserEvents2,pUnkSink,FALSE,&m_dwCookie); return TRUE; }
Points of interest
The tricky part is actually working out if the refresh button was hit. The logic goes as follows:
- Each time
BeforeNavigate2()
is called we add 1 to a page counterm_nPageCounter ++;
- Each call to
DocumentComplete()
, we take 1 from the page counterm_nPageCounter --;
- Each call to
DownloadBegin()
, we check ifm_nPageCounter == 0
. If so we know it's a refresh page call. - We also add to an object counter here
m_nObjCounter ++;
- Also we set a member variable to
true
to note it's a refresh call,m_bIsRefresh = true;
- On
DownloadEnd()
we decrease the counter fromDownloadBegin
.m_nObjCounter --;
- If
m_nObjCounter
is zero and we are in refresh mode we know that the refreshed page has loaded.if(m_bIsRefresh && m_nObjCounter == 0)
Clear as mud? Just compile the sample application and put break points in:
CIEComCtrlSink::BeforeNavigate2()
CIEComCtrlSink::DocumentComplete()
CIEComCtrlSink::DownloadBegin()
CIEComCtrlSink::DownloadEnd()
You will then see what is called and when from Internet Explorer. IE never calls BeforeNavigate2()
or DocumentComplete()
on a page refresh. (Bad IE...)
History
My first release...