摘自:http://blog.****.net/cometnet/article/details/5261192
一般情况下,当ReadyState属性变成READYSTATE_COMPLETE时,Webbrowser控件会通过触发DocumentCompleted事件来指示网页加载完毕。但当加载的网页包含frame时,可能会多次触发该事件,所以不能简单地通过它来判断网页加载完毕。
从微软的官方网站上了解到,并非每个frame都对应了一个DocumentCompleted事件,只有触发了DownloadBegin事件的frame才会有相应的DocumentCompleted事件。另外,最外层的frame总是最后触发DocumentCompleted事件。DocumentCompleted事件具有一个IDispatch *类型的参数,它指示了是在哪个frame上触发的该事件。所以,要判断文档是否加载完毕,只需要判断IDispatch *参数是否是Webbrowser控件的IDispatch。
微软support网站上关于这个问题的说明:
http://support.microsoft.com/?scid=kb%3Ben-us%3B180366&x=9&y=14
原文及译文如下:(我用Google翻译的,不一定正确,大家见谅)
The Internet Explorer WebBrowser control fires the DocumentComplete event when it is finished downloading a Web page. You can create a event handler function in your application for this event. This article describes the steps to take in determining if a the WebBrowser control is finished downloading a Web page.
在Internet Explorer WebBrowser控件激发DocumentComplete事件完成时下载网页。您可以在应用程序中创建的这一事件的事件处理函数。本文介绍的步骤可以参与决定,如果WebBrowser控件下载完成一个网页。
The WebBrowser control fires the DocumentComplete event when its ReadyState property is changed to READYSTATE_COMPLETE. This indicates that the WebBrowser control has completed downloading the Web page. Here are some important points regarding this event:
- In the case of a page with no frames, DocumentComplete is fired once after everything is done.
- In case of multiple frames, DocumentComplete gets fired multiple times. Not every frame fires this event, but each frame that fires a DownloadBegin event fires a corresponding DocumentComplete event.
- The DocumentComplete event has a IDispatch* parameter, which is the IDispatch of the frame (shdocvw) for which DocumentComplete is fired.
- The top-level frame fires the DocumentComplete in the end. So, to check if a page is done downloading, you need to check if the IDispatch* parameter is same as the IDispatch of the WebBrowser control.
WebBrowser控件激发DocumentComplete事件时,它的readyState属性更改为READYSTATE_COMPLETE。这表明,WebBrowser控件已完成下载的网页。以下是一些对这起事件的要点: 在网页的情况下,没有框架,一旦被激发的DocumentComplete一切完成之后。 在多个帧的情况,得到的DocumentComplete多次发射。不是每帧触发这一事件,但每个帧触发一个DownloadBegin事件触发相应的DocumentComplete事件。 DocumentComplete事件的IDispatch *有一个参数,它是框架(shdocvw),这些被激发的DocumentComplete的IDispatch。 在*框架火灾最终的DocumentComplete。因此,要检查一个页面完成下载,您需要检查的IDispatch *参数作为WebBrowser控件的IDispatch相同。
For Visual Basic, here is code that performs this check:
- Private Sub WebBrowser1_DocumentComplete(ByVal pDisp As Object,URL As Variant)
- If (pDisp Is WebBrowser1.Object) Then
- Debug.Print "Web document is finished downloading"
- End If
- End Sub
Private Sub WebBrowser1_DocumentComplete(ByVal pDisp As Object,URL As Variant)
If (pDisp Is WebBrowser1.Object) Then
Debug.Print "Web document is finished downloading"
End If
End Sub
To handle the DocumentComplete event in Visual C++ and determine if the download of the Web page is complete, follow these steps.
Note that the steps you follow depend on the way you use the WebBrowser control.
- If you are creating the WebBrowser control in a CWnd/CView object, you must follow steps 1 to 4.
- If you are creating the WebBrowser control in a CDialog/CFormView object, only need to follow step 4.
- If you are using the CHtmlView class provided with Visual C++ 6.0, override CHtmlView::DocumentComplete() and follow step 4, using the m_pBrowserApp member of the CHtmlView class to access the WebBrowser control.
为了处理在Visual C + + DocumentComplete事件,并确定如果网页下载完成后,按照下列步骤。
请注意,您按照步骤取决于你如何使用WebBrowser控件。 如果你在创建一个CWnd / CView对象WebBrowser控件,则必须按照步骤1至4。 如果您要创建一个CDialog在WebBrowser控件/ CFormView对象,只需要按照步骤4。 如果您使用的是CHtmlView类提供与Visual C + + 6.0,重写CHtmlView::的DocumentComplete()和后续步骤4,使用该CHtmlView类m_pBrowserApp成员访问WebBrowser控件。
1.Define the OnDocumentComplete method in the header file for your CWnd/CView-derived class:
- afx_msg void OnDocumentComplete(LPDISPATCH lpDisp,VARIANT FAR* URL);
afx_msg void OnDocumentComplete(LPDISPATCH lpDisp,VARIANT FAR* URL);
2.Declare the event sink in the same header file:
- DECLARE_EVENTSINK_MAP()
DECLARE_EVENTSINK_MAP()
3.In the implementation file (.cpp) for your CWnd/CView-derived class, implement the event sink map:
- BEGIN_EVENTSINK_MAP(CYourView, CView)
- ON_EVENT(CWBTstView, ID_WEB_BROWSE, 259 /* DocumentComplete */,
- OnDocumentComplete, VTS_DISPATCH VTS_PVARIANT)
- END_EVENTSINK_MAP()
BEGIN_EVENTSINK_MAP(CYourView, CView)
ON_EVENT(CWBTstView, ID_WEB_BROWSE, 259 /* DocumentComplete */,
OnDocumentComplete, VTS_DISPATCH VTS_PVARIANT)
END_EVENTSINK_MAP()
4.Implement the OnDocumentComplete method:
- void CWBTstView::OnDocumentComplete(LPDISPATCH lpDisp,
- VARIANT FAR* URL)
- {
- IUnknown* pUnk;
- LPDISPATCH lpWBDisp;
- HRESULT hr;
- pUnk = m_webBrowser.GetControlUnknown();
- ASSERT(pUnk);
- hr = pUnk->QueryInterface(IID_IDispatch, (void**)&lpWBDisp);
- ASSERT(SUCCEEDED(hr));
- if (lpDisp == lpWBDisp )
- {
- // Top-level Window object, so document has been loaded
- TRACE("Web document is finished downloading/n");
- }
- lpWBDisp->Release();
- }
void CWBTstView::OnDocumentComplete(LPDISPATCH lpDisp,
VARIANT FAR* URL)
{
IUnknown* pUnk;
LPDISPATCH lpWBDisp;
HRESULT hr;
pUnk = m_webBrowser.GetControlUnknown();
ASSERT(pUnk);
hr = pUnk->QueryInterface(IID_IDispatch, (void**)&lpWBDisp);
ASSERT(SUCCEEDED(hr));
if (lpDisp == lpWBDisp )
{
// Top-level Window object, so document has been loaded
TRACE("Web document is finished downloading/n");
}
lpWBDisp->Release();
}
This approach works when the WebBrowser control navigates to a page that changes the top-level frame. Say if the navigation occurs within a frame itself, then the final DocumentComplete that is fired is that of the frame and not the top-level frame. For example, consider the following scenario.
The WebBrowser control is hosting a frameset. Within one frame of the frameset, the user clicks on a link that opens a new page in the frame itself and keeps the rest of the frameset intact. The new page could contain multiple frames again. So, there will be multiple DocumentComplete notifications (one for each new frame). But, since the top-level frame has not changed, the final DocumentComplete would be that of the frame that has changed.
If you are interested in checking for the final document complete in this scenario, you could do the following:
WebBrowser控件主持一个框架。在一个框架集框架,在用户点击链接打开在框架本身就是一种新的一页,保持完整的框架休息。新的页面可能包含多个帧了。因此,将有多个(每个新的框架之一)的DocumentComplete通知。但是,由于*框架没有改变,最后的DocumentComplete将是该改变了框架。
如果您是在为最后文件在这种情况下完成检查感兴趣,你可以做以下操作: 检查的一个DocumentComplete的IDispatch参数是相同的第一NavigateComplete2事件的IDispatch参数。自第一NavigateComplete2是*帧和最后一个DocumentComplete也是*框架,做了这样的方式比较,判断该页面进行下载。
- LPDISPATCH glpDisp = NULL; // global LPDISPATCH, can also
- // be of class scope
- // NavigateComplete2 event
- void CWebbrDlg::OnNavigateComplete2Explorer1(LPDISPATCH pDisp,
- VARIANT FAR* URL)
- {
- // Check if glpDisp is NULL. If NULL, that means it is
- // the top level NavigateComplete2. Save the LPDISPATCH
- if (!glpDisp)
- glpDisp = pDisp;
- }
- void CWebbrDlg::OnDocumentCompleteExplorer1(LPDISPATCH pDisp,
- VARIANT FAR* URL)
- {
- if (glpDisp && glpDisp == pDisp)
- {
- // if the LPDISPATCH are same, that means
- // it is the final DocumentComplete. Reset glpDisp
- TRACE("Document is done downloading");
- glpDisp = NULL;
- }
- }
LPDISPATCH glpDisp = NULL; // global LPDISPATCH, can also
// be of class scope
// NavigateComplete2 event
void CWebbrDlg::OnNavigateComplete2Explorer1(LPDISPATCH pDisp,
VARIANT FAR* URL)
{
// Check if glpDisp is NULL. If NULL, that means it is
// the top level NavigateComplete2. Save the LPDISPATCH
if (!glpDisp)
glpDisp = pDisp;
}
void CWebbrDlg::OnDocumentCompleteExplorer1(LPDISPATCH pDisp,
VARIANT FAR* URL)
{
if (glpDisp && glpDisp == pDisp)
{
// if the LPDISPATCH are same, that means
// it is the final DocumentComplete. Reset glpDisp
TRACE("Document is done downloading");
glpDisp = NULL;
}
}