Я изучал следующий фрагмент кода от 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, но я подумал сначала спросить здесь, в Центре программистов, на случай, если мне не хватает чего-то очевидного.
Спасибо всем заранее. Любой отзыв приветствуется.
Ура,
Доминик