Why is the Webbrowser control DocumentComplete eve

2019-05-11 11:57发布

问题:

Based on this article on MSDN: How To Determine When a Page Is Done Loading in WebBrowser Control, and from past discussions on StackOverflow, I would assume that in case of a document with multiple frames, the DocumentComplete event would fire multiple times, and the last time would be for the top level frame.

However, using the exact sample code from the above-mentioned MSDN link, I find that if there are multiple DocumentComplete events when doing a Navigate to a URL, the condition is satisfied in the following code the first time, not the last time as the article seems to indicate. Subsequent invokes of DocumentComplete seem to be for lower level frames, since the condition fails.

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();

I am not sure why the behaviour I observe is exactly opposite of what it is supposed to be as per the documentation. Any pointers on this would be appreciated.

Background: I am using this code in a dialog-based VC++ / MFC application, and in the DocumentComplete event I want to get certain statistics when the document is fully loaded. So I was trying to use the above code to detect that a particular instance of DocumentComplete firing is when the page has fully loaded.

回答1:

IMO, the most reliable way to get notified when the page has been fully loaded is to attach to window.onload DOM event for the top window object (IWebBrowser2::get_Document, IHTMLDocument2::get_parentWindow), when DocumentComplete is fired for the first time for a particular navigation. Then, onload event for the top web page will be fired when all inner frames have been loaded. This answer illustrates how it can be done in C# and this answer may help to get it done in C++.



回答2:

The MSDN doc seems right to me: the last DISPID_DOCUMENTCOMPLETE is the one fired for the main frame.

I can't reproduce your problem for http://www.microsoft.com/ as that link gives me the final http://www.microsoft.com/fr-fr/default.aspx which is a single frame.

I don't like the way the sample code is testing for the Main Browser (equality of 2 IDispatch pointers). What I do is this:

  1. QueryInterface the IDispatch for an IWebBrowser2
  2. Make a true COM equality test, that is "comparing the IUnknown" from the 2 IWebBrower2 (I do it with the IsEqualObject method from the CComPtr template.