WatiN, Internet Explorer启动和IWebBrowser2窗口句柄



我正在研究下面一段来自WatiN的代码,它处理启动和附加到Internet Explorer:

    private static IEBrowser CreateIEPartiallyInitializedInNewProcess(Uri uri)
    {
        var m_Proc = CreateIExploreInNewProcess(uri);
        var helper = new AttachToIeHelper();
        var action = new TryFuncUntilTimeOut(TimeSpan.FromSeconds(Settings.AttachToBrowserTimeOut))
        {
            SleepTime = TimeSpan.FromMilliseconds(500)
        };
        var ie = action.Try(() =>
        {
            m_Proc.Refresh();
            var mainWindowHandle = m_Proc.MainWindowHandle;
            // return mainWindowHandle != IntPtr.Zero ? GetIWebBrowser2Directly(mainWindowHandle) : null;
            return mainWindowHandle != IntPtr.Zero
                ? helper.FindIEPartiallyInitialized(new AttributeConstraint("hwnd", mainWindowHandle.ToString()))
                : null;
        });
        if (ie != null) return ie._ieBrowser; 
        // if (ie != null) return new IEBrowser(ie);
        throw new BrowserNotFoundException("IE", "Timeout while waiting to attach to newly created instance of IE.", Settings.AttachToBrowserTimeOut);
    }

WatiN所做的是启动Internet Explorer并等待它获得。mainwindowwhandle(这是在Internet Explorer中显示内容的"窗口"的句柄)。一旦它获得了这个窗口句柄,它就会获得一个用户桌面上正在运行的所有IWebBrowser2窗口的列表,并尝试用IWebBrowser2集合中的一个(如果有的话)窗口句柄来匹配进程的. mainwindowwhandle。

这种方法最重要的问题是IWebBrowser2。HWND属性(需要与。mainwindowwhandle进行比较)可以非常有问题,不稳定和喜怒无常,因为当您试图访问它时,它每隔一次都会抛出InvalidCastException(至少在我正在运行测试的机器上)。这样的操作也有开销。

这是我对任何可能更了解我在windows编程的人的问题:既然hwnd无论如何都会匹配,为什么我们不使用。mainwindowwhandle值来检索所需的IWebBrowser2马上(见上面的注释代码)通过使用以下方法(灵感来自代码WatiN本身在ShellWindow2.cs中使用):

    private static IWebBrowser2 GetIWebBrowser2Directly(IntPtr embeddedWebBrowserWindowHandle)
    {
        IHTMLDocument2 document2 = UtilityClass.TryFuncIgnoreException(() => IEUtils.IEDOMFromhWnd(embeddedWebBrowserWindowHandle));
        if (document2 == null) return null;
        IHTMLWindow2 parentWindow = UtilityClass.TryFuncIgnoreException(() => document2.parentWindow);
        if (parentWindow == null) return null;
        return UtilityClass.TryFuncIgnoreException(() => ShellWindows2.RetrieveIWebBrowser2FromIHtmlWindw2Instance(parentWindow));
    }
(作为旁注,我们甚至可以创建一个代理对象,在我的另一篇文章中描述,来缓存窗口句柄,以避免请求IWebBrowser2。

这对我来说很好。我看不到hwnd之间的任何冲突或不匹配-不知道是否有一个角落的情况,我可能会错过。我很想在WatiN论坛上问这个问题,但我想先在程序员中心问一下,以防我遗漏了一些明显的东西。

提前感谢大家。任何提示都很感谢。

欢呼,多明尼克

我开始深入研究Internet Explorer的内部窗口结构,并提出了以下层次结构(当然,不相关的窗口是允许的):

IEFrame
|
——TabWindowClass-1——convert-> FirstIWebBrowser2
|
——TabWindowClass-2——convert-> SecondIWebBrowser2
|

…|
——TabWindowClass-Nth——convert——> Nth-IWebBrowser2

通过测试,我在Windows7 + IE9(9.0.8112.16421)中得出了以下发现

  1. 有趣的是(和反直觉)IWebBrowser2。

  2. IEFrame->HWND与IWebBrowser2的ANY相同。HWND属性在同一internet explorer进程中。即使我们在同一个ie进程中打开多个选项卡也是如此。

  3. 。internet explorer进程的mainwindowandle属性(当我们以编程方式启动internet explorer时)与IEFrame->HWND相同,因此也与IWebBrowser2对象相同。

  4. 活动的选项卡可以通过使用IEFrame的HWND立即检索(使用我在原始帖子中概述的方法)。

关于为什么上述hwnd-layout成立,我最有根据的猜测是:

  1. Redmond的工作人员在IEFrame和IWebBrowser2之间进行了这种hwrd连接,因为实际上一次只有一个活动选项卡窗口(而用户被给予X个选项卡的错觉)。还是…

  2. 因为需要保持与先前版本的IE已有代码的向后兼容性,并且该代码正在使用IEFrame的HWND来获取它的IWebBrowser2对象。

在任何一种情况下,我觉得可能有一个内部错误在实现这个HWND布线时,它涉及到从IWebBrowser2接口访问它,导致InvalidCastException。

任何对这个问题有更多见解的人都可以随意写一两行。希望这些对你有帮助。

欢呼,多明尼克

相关内容

  • 没有找到相关文章

最新更新