WatiN, запуск Internet Explorer и дескриптор окна IWebBrowser2 - PullRequest
0 голосов
/ 13 октября 2011

Я изучал следующий фрагмент кода от 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):

    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, но я подумал сначала спросить здесь, в Центре программистов, на случай, если мне не хватает чего-то очевидного.

Спасибо всем заранее. Любой отзыв приветствуется.

Ура, Доминик

1 Ответ

1 голос
/ 14 октября 2011

Я начал копаться во внутренней оконной структуре 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 НИКОГДА не идентичен HWND объекта TabWindowClass, из которого он получен.

  2. IEFrame-> HWND совпадает с ЛЮБЫМ из свойств IWebBrowser2.HWND в том же Интернетеисследовательский процесс.Это верно, даже если у нас есть несколько вкладок, открытых в одном процессе Internet Explorer.

  3. Атрибут Process.MainWindowHandle процесса Internet Explorer (когда мы запускаем Internet Explorer программно) идентиченIEFrame-> HWND и, таким образом, идентичен объектам IWebBrowser2.

  4. Активную вкладку можно получить с помощью HWND IEFrame сразу (используя метод, который я обрисовал в общих чертах)в оригинальном сообщении).

Мои наиболее образованные предположения относительно того, почему вышеупомянутая раскладка hwnd такова:

  1. Любой, кто вРедмонд сделал эту hwnd-связь между IEFrame и IWebBrowser2, потому что на самом деле есть только 1 активное окно вкладок за раз (в то время как у пользователя создается иллюзия X количества вкладок).Или ...

  2. Поскольку существовала необходимость поддерживать обратную совместимость с уже существующим кодом, предназначенным для предыдущих версий IE, и этот код использовал HWND IEFrame для получения объекта IWebBrowser2.

В любом случае я чувствую, что при реализации этого подключения HWND может возникнуть внутренняя ошибка при доступе к нему из интерфейса IWebBrowser2, что приводит к InvalidCastException.

Любой, кто лучше разбирается в этом вопросе, пожалуйста, не стесняйтесь написать одну или две строки.Надеюсь, что это поможет.

Ура, Доминик

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...