views:

472

answers:

1

I have an Internet Explorer BHO (in c# .net) and want to identify either when a user initiates a navigation, or when a user-initiated navigation has completed. By user-initiated i mean clicking on a link or similar action. In particular if there are multiple frames in the document being loaded I want to treat them as a single 'navigation', but I can't think of any easy way to do this. I know the BeforeNavigate2 and DocumentComplete events, but can't see any way to differentiate between BeforeNavigate/DocumentComplete firing when a user has clicked on a link and it firing because a frame is loading.

One possible solution I'm thinking is that the BeforeNavigate2 for the top frame always gets fired before that of the inner frames (obviously), and then the DocumentComplete of the child frames get called before the DocumentComplete of the top, which is always called last. So for instance I could increment a counter in BeforeNavigates and decrement it in DocumentComplete, and only when it's 0 is it a user-initiated navigation.

But I'm not sure if I can rely on this or if there's a better way to do it. e.g. What happens if the user presses ESC after one of the frames but not all have finished loading: does the DocumentComplete of the top frame ever get called?

Any suggestions?

A: 

You can test whether BeforeNavigate/NavigateComplete/DocumentComplete event came from ineere frame or the topmost one simple by testing pDispParams agruments against pointer to browser object you have stored in SetSite method of your BHO.

Here's C++ code to do this, I hope you can convert it easily to C#:

STDMETHODIMP MyBHO::Invoke(DISPID dispidMember,
  REFIID riid, 
  LCID lcid,
  WORD wFlags,
  DISPPARAMS* pDispParams,
  VARIANT* pvarResult,
  EXCEPINFO* pExcepInfo,
  UINT* puArgErr)
{
  if( dispidMember != DISPID_BEFORENAVIGATE2 &&
      dispidMember != DISPID_NAVIGATECOMPLETE2 &&
      dispidMember != DISPID_DOCUMENTCOMPLETE )
 return S_OK;

  CComQIPtr<IWebBrowser2, &IID_IWebBrowser2> frame =
    pDispParams->rgvarg[ 1 ].pdispVal;

  if( webBrowser2 != frame )
    return S_OK;
}

webBrowser2 is pointer to browser object that you got in SetSite method,

Mladen Jankovic
true, but unfortunately that doesn't do what I need, as users could perform a navigation in the top-level frame OR could just navigate within an inner frame. Either way i want to regard that as a single navigation, but ignore any sub-frame navigations.
Rory