none
How to detect tab-change in IE7?

    Question

  • Hi I'm wondering if anyone knows how to detect when a tab changes in IE? My toolbar has to detect when

    a) A tab changes site (This I already do by Navigate and DocumentComplete)
    b) When you change between tabs (this I have no idea how to do).

    I know there is a DWebBrowserEvents2::WindowStateChanged I maybe could use but I have no idea how to use it? The only thing I've been able to even think about up until now is to create a thread that runs every second and checks what tab is visible, if it's not the one that was visible last check then fetch the document URL location from that, not that I've even gotten that to work very well...

    So I was hoping someone might be able to help me out, maybe show me some code on how to achieve knowing when the user changes between tabs and getting the URL from the open tab.


    Sincerely
    Tom
    Thursday, January 04, 2007 7:50 PM

Answers

  • We have added a new event you can catch...

    DISPID_WINDOWSTATECHANGED

    It will tell you that the user is switching tabs.

     

    -Reza

    Monday, January 08, 2007 6:03 PM

All replies

  • I still haven't found a solution to this, and seemingly none others here have either? I heard from someone that he had done it with .NET and an OnDocumentChange event but I can't for the life of me find the equivalent in C++/ATL nor even that one in .NET.

    So any takers on a solution?
    Saturday, January 06, 2007 4:45 AM
  • Hi,

    I may be wrong (just been working with IE6 and live toolbar with tabbed browsing and a BHO), but there should be an instance of your toolbar for each tab that is created, so if you are hooking into the loaded document when your toolar is loaded then you should have to do nothing. Use the spyXX utility that comes with .net to inspect the window and tab heiracy of an IE7 window. You will see that for each open tab there is an instance of an IEFrame class and under each of these there will be an instance of your toolbar.

    Otherwise you can create a satelite bho for you toolbar that will keep a list of tabs and their document locations (either as registry entries ... as the live toolbar does... or as a shared memory variable.)

    Regards.

    Saturday, January 06, 2007 11:44 AM
  • It is not so in IE7, there is one instance for each instance of IE7, each tab isn't it's own instance of IE7 but a window in IE7, so that's not possible.

    The only thing I need to find out is what kind of Message/Api is sent to IE/Toolbars when a user switches from one tab to another, doesn't seem to be any (Atleast not that I could find with Spy++, OllyDbg or ApiSpy)
    Saturday, January 06, 2007 3:06 PM
  • Yea I can iterate all the tabs and see which one is open, that still won't tell me exactly when the user switches tab. There must be some event or API call that's called for this? Or I'll have to setup a 1 second timer that checks which tab is open and run my code if the hwnd != lasthwnd
    Monday, January 08, 2007 12:05 AM
  • We have added a new event you can catch...

    DISPID_WINDOWSTATECHANGED

    It will tell you that the user is switching tabs.

     

    -Reza

    Monday, January 08, 2007 6:03 PM
  • Why thank you =) Currently I solved it by grabbing the appropriate HWND from SetSite then setting up a WindowsHook for SW_SHOWWINDOW and check when it fires if it's one of the HWND's grabbed in SetSite, if so and ShowWindow is TRUE then that's the tab to be shown.

    Now I just need to figure out how to get the IWebBrowser2 from a HWND :P
    Monday, January 08, 2007 6:13 PM
  • Hi RyomaEchizen,

    I'm currently developing an IE7 extension/BHO and I'm facing some trouble detecting when the user change the active tab.
    I'm new to Win32 programming, so I'm facing trouble with that too...
    I would really appreciate if you could post the code you used to solve the problem.

    I know it's an old post, but I really need some help.

    Thanks!
    Tuesday, April 08, 2008 5:00 AM
  • Don't create a hook to get window messages.  That's a terrible idea.  WindowsHooks pollute the enviornment for everyone and should only be used as an absolute last resort. 

     

    You just need to have your BHO handle DWebBrowserEvents2::WindowStateChanged.  Do something like this in your IDispatch::Invoke() method:

     

    Code Snippet

    case DISPID_WINDOWSTATECHANGED:

    {

    DWORD dwMask = pDispParams->rgvarg[0].lVal;

    DWORD dwFlags = pDispParams->rgvarg[1].lVal;

     

    if (dwMask & OLECMDIDF_WINDOWSTATE_USERVISIBLE)

    {

    _pYourBHO->HandleWindowStateChanged(!!(dwFlags & OLECMDIDF_WINDOWSTATE_USERVISIBLE));

    }

    break;

    }

     

     

    Since IE will create an instance of your BHO for each tab, you now know when your tab becomes visible.  It's fairly trivial to implement a system where they can talk to each other.

     

    I found it's helpful to give each BHO a unique ID as well.  Something like:

     

    Code Snippet

    LONG g_nNextId = 0;

     

    CYourBHO::CYourBHO()

    {

        _nBhoId = InterlockedIncrement(&g_nNextId);

    }

     

     

    Tuesday, April 08, 2008 5:53 PM
  • That was so easy! Thanks for the reply and the tips!
    Wednesday, April 09, 2008 5:11 AM
  • Hi gonzaling,

            I am facing difficulties in detecting active tab. I went through your post.
    As jeffdev suggested i am able to assign id to the bho using InterlockedIncrement() function.
    But I am not able to understand how to use that ids in DWebBrowserEvents2::WindowStateChanged and how to implement
    IDispath::Invoke() method.
           Since i am  new to Extension development environment finding defficulty in comunicating with the interface and its
    implementaion.I know IDispatch::Invoke() mehtod provides access to propetry and method exposed by an object,but dont know
    how to use this interface in my implementation.
           It would be helpfull for me if you could tell how did you resolved your problem.    

    Thanks in advance,
    Jyoti J.V



    Saturday, August 09, 2008 8:54 AM
  • Hi jyotijv,
    My BHO is developed in C#, so I think it might be better for you to take a look at this thread (http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2859646&SiteID=1). It contains a link to a BHO example in C++ which handles the WindowStateChanged event to set the current visible BHO. You need to take a look in the ButtonDemoBHO.cpp.

    Hope it helps!
    Tuesday, August 12, 2008 1:00 PM
  • Hi gonzaling,

       Thanks for the reply. Even I have developed BHO in C#. I went through the link you suggested, but couldn't understand much of it since it is implemented in ATL. I have some queries.

       1. Could you kindly tell what approach you followed.
       2. How can I use interfaces like IDispatch::Invoke and IconnectionPoint in the C# BHO application?
       3. How can I detect active tab? Please suggest me any links or any sample C# code snippets which I can look into.

    Thank you,
    Jyoti J.V

    Wednesday, August 13, 2008 12:37 PM
  • Hi, sure.
    You need to handle DWebBrowserEvents2::WindowStateChanged event.
    I assign an event handler for this event on the call to SetSite of my BHO, this way:

    Code Snippet
    Explorer.WindowStateChanged += new DWebBrowserEvents2_WindowStateChangedEventHandler(Explorer_WindowStateChanged);

     

     

    The handler methos is as follows

    Code Snippet

    public const int OLECMDIDF_WINDOWSTATE_USERVISIBLE = 3;

    void Explorer_WindowStateChanged(uint dwWindowStateFlags, uint dwValidFlagsMask)
            {
                try
                {
                    if (dwWindowStateFlags == OLECMDIDF_WINDOWSTATE_USERVISIBLE)
                    {                   
                        Log.LogData("New tab active --> " + Explorer.LocationURL);

    BHOManager.SetActiveBHO(this);

                    }
                }
                catch (Exception ex)
                {
                    Log.LogData("Exception --> " + ex.Message);
                }

            }

     

     

    BHOManager only contains static members. A collection of all the BHOs and the current active BHO/tab.

     

    This answers question 1 and 3. Reg. 3: You don't need to detect the active tab, you always have the active tab stored somewhere in an object that manages the BHOs. Remember that there's a one-to-one relation between BHOs and opened tabs. You need to store a reference to the InternetExplorer or IWebBrowser2 object that was passed to the SetSite method when your BHO got instantiated.

     

    Reg. question 2: I suggest you take a look at this article in CodeProject. it's really good.


    Wednesday, August 13, 2008 1:15 PM
  •  Hi gonzaling,

    Thanks for the links and code snippet. I went through the link and found it very useful. I tried the way you suggested by assigning an event handler on the call to SetSite. The event is getting fired only when the visibility state of tabs are changed but is not getting fired when browser window visibility state changes or when the window is minimized.

    I went through the documentation for WindowStateChanged at MSDN (http://msdn.microsoft.com/en-us/library/aa768307(VS.85).aspx and it says that the event should be raised for the following actions.

     1.It fires when the visibility state of a content window, such as the browser window or a tab, changes.
     2.The browser window is minimized or restored.
     3.An active tab becomes inactive.
     4.An inactive tab becomes active.
     5.The browser window is enabled or disabled due to a modal dialog box.

    Except for actions  1 and 2 all others are working great with the approach you suggested.

    And I also could not get why we need to assign const number 3 to OLECMDIDF_WINDOWSTATE_USERVISIBLE

    I googled but could not get much information regarding this Sad

    How can I capture action 1 and 2(as listed above) raised by WindowStateChanged event and why we need to use a const number 3?

    Thanks again.
    Jyoti J.V


     

    Saturday, August 16, 2008 7:52 AM
  •  

    For "Minmized" event:

     

    if(YourBrowser.Left == -32000)

      //it's minmized

    Monday, August 18, 2008 3:41 AM
  • Hi cablehead,
     
        Thanks for your help.I tried the way you suggested and now I am able capture minimize window event.
        The link I referred to know about window minimized state  is
    http://blogs.msdn.com/oldnewthing/archive/2004/10/28/249044.aspx
        But I would like to know more about window state and its coordinates,If you could suggest me any  other links It would be
    helpful for me.
     
    Thanks again,
    Jyoti J.V
         
    Thursday, August 21, 2008 8:37 AM
  • Hi Jyoti,
    OLECMDIDF_WINDOWSTATE_USERVISIBLE is a Win32 constant which has the value 3... and most important, is one of the posible values that the event get as a parameter if you're programming in C++, but that's not the case, so we just create the same constant for clarity purposes in C#. You could just compare the event parameter against 3, but that's a little bit obscure if you ask me.

    Regarding window coordinates, I would suggest you take a look at the GetWindowInfo function (http://msdn.microsoft.com/en-us/library/ms633516(VS.85).aspx).
    I think that's what you are looking for.
    Here's the declaration of the function in C#, along with the structures you need - http://pinvoke.net/default.aspx/user32/GetWindowInfo.html

    Good luck!
    Thursday, August 21, 2008 1:06 PM
  • Hi gonzaling,

              Thank you for the links and for explaining why we need use const number 3.It cleared my doubt but even though I am able to capture visibility state of tabs,still struggling with capturing the event triggered by WindowStateChanged when visibility state of the browser window is changed.
    Please kindly suggest me how can I achieve this.

    Thanks in advance,
    Jyoti J.V
    Friday, August 22, 2008 9:58 AM