Active tab ignored by InternetExplorer COM object

2019-02-17 19:58发布

问题:

This is web single sign on code that runs on a .net 3.5 winform. The code runs fine for ie6 or ie8 as long as ie8 only has one tab open. The problem is that if the user opens a new tab (tab 2,3,etc.) and navigates to a web site (web form internal in the organization) the below code will be executed but the ie COM automation object will return the HTMLDocument for the first tab (Tab 1) even though tab 2 is the active tab. I can't find any IE tab references in the InternetExplorer or HTMLDocument classes anywhere. Actually, there's very little IE tab related documentation anywherer in the IE COM automation docs.

AutoResetEvent ie2_NavigateCompleteAutoReset;

    /// <summary>
    /// Given the handle of an Internet Explorer instance, this method performs single sign on to
    /// several known web login forms.
    /// </summary>
    /// <param name="iEFramHandle"></param>
    private void WebFormSignOn(int iEFramHandle)
    {
        foreach (SHDocVw.InternetExplorer ie2 in new SHDocVw.ShellWindows())
        {
            if (ie2.HWND == iEFramHandle)
            {
                while (true)
                {
                    Thread.Sleep(100);
                    if (ie2.ReadyState == SHDocVw.tagREADYSTATE.READYSTATE_COMPLETE)
                    {
                        try
                        {
                            mshtml.HTMLDocument doc = (mshtml.HTMLDocument)ie2.Document;
                            ie2.NavigateComplete2 += new SHDocVw.DWebBrowserEvents2_NavigateComplete2EventHandler(ie2_NavigateComplete2);
                            ie2_NavigateCompleteAutoReset = new AutoResetEvent(false);

                            /*Find the username element and enter the user's username*/
                            mshtml.HTMLInputElement userID = (mshtml.HTMLInputElement)doc.all.item("username", 0);
                            userID.value = Globals.Username;

                            /*Find the password element and enter the user's password*/
                            mshtml.HTMLInputElement pwd = (mshtml.HTMLInputElement)doc.all.item("password", 0);
                            pwd.value = Globals.GetAppName();

                            /*Find the submit element/button and click it*/
                            mshtml.HTMLInputElement btnsubmit = (mshtml.HTMLInputElement)doc.all.item("submit", 0);
                            btnsubmit.click();

                            /*Wait up to 5 seconds for the form submit to complete.
                             This is to prevent this method from being called multiple times
                             while waiting for the form submit and subsequent navigation from completing.*/
                            ie2_NavigateCompleteAutoReset.WaitOne(5000);
                            return;
                        }
                        catch (Exception err)
                        {
                            Logger.Log(err.ToString(), Logger.StatusFlag.Error, this.ToString(), "WebFormSignOn");
                            return;
                        }
                        finally
                        {
                            /*Remove the event handler*/
                            ie2.NavigateComplete2 -= ie2_NavigateComplete2;

                        }
                    }
                }
            }
        }
    }

    void ie2_NavigateComplete2(object pDisp, ref object URL)
    {
        ie2_NavigateCompleteAutoReset.Set();
    }

回答1:

It turns out that each tab in IE 8 has it's own process and handle. In the original code i was always getting the handle from the first IEFrame. I modified the code (below) and now it works. The change is that instead of looking for just the first IEFrame handle, the code also looks for a LocationURL that matches the url that triggerd the method that calls WebFormsSignOut.

private void WebFormSignOn(int iEFramHandle,string addressBarText)
{
    var shellWindows = new SHDocVw.ShellWindows();
    foreach (SHDocVw.InternetExplorer ie2 in shellWindows)
    {
        if (ie2.LocationURL==addressBarText)
        { //rest of the code (see orignal post)


回答2:

Internet Explorer does not have any public tab APIs (beyond allowing you to target a navigation to a new foreground or background tab). Each ActiveX control or BHO is loaded individually into an individual tab instance. Trying to walk down from the ShellWindows collection isn't likely to work in general, instead you should have your plugin reach out to its hosting site (e.g. IObjectWithSite::SetSite will convey this info) which will allow you to determine your hosting tab.