Internet explorer WatiN、Internet Explorer启动和IWebBrowser2窗口句柄

Internet explorer WatiN、Internet Explorer启动和IWebBrowser2窗口句柄,internet-explorer,watin,hwnd,iwebbrowser2,Internet Explorer,Watin,Hwnd,Iwebbrowser2,我正在研究WatiN的以下代码,该代码负责启动和连接Internet Explorer: private static IEBrowser CreateIEPartiallyInitializedInNewProcess(Uri uri) { var m_Proc = CreateIExploreInNewProcess(uri); var helper = new AttachToIeHelper(); var action =

我正在研究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并等待它得到.MainWindowHandle(显示Internet Explorer内内容的“窗口”的句柄)。一旦获得此窗口句柄,它将获得在用户桌面上启动并运行的所有IWebBrowser2窗口的列表,并尝试将进程的.MainWindowHandle与来自IWebBrowser2集合的一个窗口句柄(如果有)相匹配

这种方法最重要的问题是,IWebBrowser2.HWND属性(需要与.MainWindowHandle进行比较)可能是有问题的、不稳定的和喜怒无常的,因为当您尝试访问它时(至少在我正在运行测试的机器上),它每隔一段时间就会抛出InvalidCastException。此外,还有这样一个操作的开销

我的问题是,对于那些可能更了解我的windows编程知识的人来说:既然HWND无论如何都会匹配,为什么我们不使用.MainWindowHandle值通过使用以下方法立即检索所需的IWebBrowser2(请参阅上面注释掉的代码)(受WatiN在ShellWindow2.cs内部使用的代码启发):

(作为旁注,我们甚至可以创建一个代理对象(如我在另一篇文章中所述)来缓存窗口句柄,以避免向IWebBrowser2.HWND索要它)

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

提前谢谢大家。任何提示都将不胜感激

干杯,
Dominick

我开始深入研究InternetExplorer的内部窗口结构,并提出了以下层次结构(当然,不相关的窗口也可以使用):

IEFrame
|
--TabWindowClass-1--转换-->第一个IWebBrowser2
|
--TabWindowClass-2--转换-->第二个IWebBrowser2
|

|
--TabWindowClass N--转换-->N-IWebBrowser2

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

  • 有趣的是(与直觉相反),IWebBrowser2.HWND与它所来自的TabWindowClass的HWND并不完全相同

  • IEFrame->HWND与同一internet explorer进程中的任何IWebBrowser2.HWND属性相同。即使在同一internet explorer进程中打开了多个选项卡,也是如此

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

  • 激活的选项卡可以通过使用IEFrame的HWND来检索(使用我在原始文章中概述的方法)

  • 关于上述hwnd布局为何适用,我最有根据的猜测是:

  • Redmond的人在IEFrame和IWebBrowser2之间进行了这种hwnd连接,因为实际上一次只有一个活动的选项卡窗口(而用户被赋予了X个选项卡的错觉)。或者

  • 因为需要保持与针对早期版本IE的现有代码的向后兼容性,并且该代码使用IEFrame的HWND获取其IWebBrowser2对象

  • 在这两种情况下,当从IWebBrowser2接口访问HWND连接时,我觉得可能在HWND连接的实现中存在一个内部缺陷,导致InvalidCastException

    任何对这个问题有更深入了解的人,请随时写一两行。希望这些帮助

    干杯, 多米尼克

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