0

Internet Explorer の起動と接続を処理する WatiN の次のコードを調べていました。

    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 と比較する必要がある) が、アクセスしようとすると (少なくともテストを実行しているマシン)。また、そのような操作のオーバーヘッドがあります。

これは、私が Windows プログラミングに精通している可能性がある人への私の質問です。HWND はとにかく一致するので、必要な IWebBrowser2 をすぐに取得するために .MainWindowHandle 値を使用しないのはなぜですか (上記のコメントアウトされたコードを参照)。 ) 次のメソッドを使用します (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 への要求を回避することもできます)。

これは私にとってはうまくいきます。HWND 間の競合や不一致は見られません。これについて WatiN フォーラムで質問したくなりましたが、明らかな何かが不足している場合に備えて、まず Programmers' Central で質問することにしました。

よろしくお願いします。どんなヒントでも大歓迎です。

乾杯、ドミニク

4

1 に答える 1

1

私は Internet Explorer の内部ウィンドウ構造を掘り下げ始め、次の階層を思いつきました (無関係なウィンドウはもちろん省略されています)。

IEFrame
|
-- TabWindowClass-1 --convert--> FirstIWebBrowser2
|
-- TabWindowClass-2 --convert--> SecondIWebBrowser2
|
...
|
-- TabWindowClass-Nth --convert--> Nth-IWebBrowser2

テストの結果、Windows7 + IE9(9.0.8112.16421) で以下の結果が得られました。

  1. 興味深いことに (そして直感に反して) IWebBrowser2.HWND は、元の TabWindowClass の HWND と決して同一ではありません。

  2. IEFrame->HWND は、同じ Internet Explorer プロセスの IWebBrowser2.HWND プロパティのいずれかと同じです。これは、同じ Internet Explorer プロセスで複数のタブを開いている場合でも当てはまります。

  3. Internet Explorer プロセスの Process.MainWindowHandle 属性 (プログラムで Internet Explorer を起動したとき) は IEFrame->HWND と同じであり、したがって IWebBrowser2 オブジェクトの属性と同じです。

  4. アクティブなタブは、すぐに IEFrame の HWND を使用して取得できます (元の投稿で概説した方法を使用)。

上記の hwnd-layout が保持される理由について、私の最も経験に基づいた推測は次のとおりです。

  1. 一度にアクティブなタブ ウィンドウは 1 つしかないため (ユーザーには X 個のタブの錯覚が与えられるため)、Redmond のいずれかの人々が IEFrame と IWebBrowser2 の間でこの hwnd ワイヤリングを行いました。または ...

  2. 以前のバージョンの IE を対象とした既存のコードとの下位互換性を維持する必要があり、そのコードは IEFrame の HWND を使用して IWebBrowser2 オブジェクトを取得していたためです。

いずれの場合も、IWebBrowser2 インターフェイスからアクセスすると、この HWND 配線の実装に内部バグがあり、InvalidCastException が発生する可能性があると思います。

この問題について詳しい方は、お気軽に 1 つか 2 行お寄せください。これらが役立つことを願っています。

乾杯、ドミニク

于 2011-10-14T15:31:57.587 に答える