Как запустить Internet Explorer или подключиться к немуИсточник: delphikingdom
Автор: Сергей Осколков, королевство DelphiВ продолжение нескольких статей на Королевстве о работе с компонентом TWebBrowser хочу затронуть пару вопросов работы с Internet Explorer, которые раньше, кажется, не обсуждались. Почти все уже было в ответах Круглого стола, здесь - более подробно. Сначала немного теории Internet Explorer и его объекты.На рисунке изображена архитектура Internet Explorer (IE). Для того, чтобы соединить компоненты в целое, используются элементы ActiveX и интерфейсы ActiveDocument. Сам исполняемый файл IE мал (у меня на машине IE6 - 89 КБ). Он предоставляет окно и панель инструментов и непосредственно управляет элементом-браузером WebBrowser (ShDocVw.dll). Этот элемент, в свою очередь, управляет компонентом MSHTML.dll, который осуществляет парсинг (разбор) html и его отображение в окне браузера, а также предоставление документа в виде объектной модели. MSHTML, в свою очередь, управляет скриптовыми движками, плагинами и т.д. для отображения своего содержимого. WebBrowser также управляет активными документами, которые могут быть в него загружены, например документами MS Office. Как WebBrowser, так и MSHTML предоставляют свои интерфейсы для внешних программ. Первый из них может использоваться как элемент ActiveX. Компонент TWebBrowser из палитры компонентов Дельфи - это просто обертка для него. Практические выводы из написанного следующие: для управления браузером в целом обычно мы используем методы TWebBrowser. Например, для загрузки документа или его печати. Для доступа к элементам документа мы используем интерфейсы, объявленные в MSHTML, основной из которых - IHtmlDocument2, получаемый через свойство TWebBrowser.Document. Еще я бы отметил интерфейс IHtmlWindow, который соответсвует объекту window в javascript. Через него также можно выполнить ряд полезных действий и получить доступ к элементам страницы. Теперь - к более конкретным вопросам. Создаем и запускаем.Напомню, что компонент TWebBrowser и интерфейс IWebBrowser2 - основной интерфейс для управления браузером, объявлены в модуле ShDocVw.pas. Для работы с интерфейсами MSHTML нужно импортировать одноименную библиотеку типов MSHTML.tlb (меню Project->Import Type Library, выбрать Microsoft Html Object Library). Первая задача: запустить Internet Explorer и открыть в нем документ. Для запуска можно, конечно, воспользоваться функциями CreateProcess или ShellExecute, как для любой другой программы. Однако мы воспользуемся рассматриваемыми методами.
Здесь мы запускаем IE и открываем в нем нужный документ с диска или Веб-страницу. Если не уничтожать переменную WB сразу же, как в примере, то через нее мы имеем доступ к загруженному документу и также можем управлять экземпляром IE. Например, закрыть его. Непосредственно в интерфейсе IWeBrowser2 метода для этого нет. Однако в ShDocVw.pas объявлен интерфейс IWebBrowserApp = interface(IWebBrowser), который содержит метод Quit. Я не очень понимаю, почему это так, но работает и (WB as IWebBrowserApp).Quit, и просто WB.Quit - закрывается запущенный экземпляр IE. В модуле ShDocView также определен тип TInternetExplorer. Им тоже можно пользоваться в описанных целях.
В примере запускается Internet Explorer, мы подключаемся к его событию OnBeforeNavigate2 и открывается страница (здесь - с жесткого диска). При дальнейших переходах IE на другие страницы, строка адреса (URL) будет добавляться в элемент Memo. Мы также имеем возможность закрыть этот экземпляр IE из своей программы методом IE.Quit. Подключаемся.Следующая задача - подключиться к уже запущенному экземпляру IE. Если попытаться использовать функцию GetActiveOleObject('InternetExporer.Application'); то мы получим сообщение об ошибке EOleSysError с сообщением "Операция недоступна". Дело в том, что, видимо из соображений безопасности, IE как сервер автоматизации, после запуска недоступен внешним программам. Это осуществлено так: при старте любой сервер автоматизации регистрирует себя с помощью функции CoRegisterClassObject. Если установить соответствующий флаг (REGCLS_SINGLEUSE) в этой функции, то объект будет недоступен другим приложениям. Однако, подключиться к интерфейсу IWebBrowser2 запущенного IE все-таки можно! В том же модуле ShDocVw.pas объявлен интерфейс IShellWindows. Через него можно подключиться ко всем открытым окнам IE и Проводника (Explorer) Windows. Отличить первые от вторых можно по наличию свойства Document. Для доступа воспользуемся стандартными для коллекций методом Item(i) и свойством Count. Здесь я натолкнулся на один подводный камень. Попробуем вывести адреса загруженных страниц во всех экземплярах IE в компонент Memo следующим образом:
При выполнении этот код вызывал ошибку Interface not supported. Оказалось, что у окон проводника свойство Document может быть не равно nil и они благополучно проходят проверку, но при применении оператора as (Document as IHtmlDocument2) возникает исключение, т.к. получить интерфейс IHtmlDocument2 не удается. Как же правильно провести проверку? Здесь можно воспользоваться тем, что в применении к интерфейсам оператор as является оберткой для вызова метода QueryInterface и при компиляции преобразуется в вызовы указанного метода. Метод IUnknown.QueryInterface я и применил. Если окно является окном IE, то мы получим интерфейс IHtmlDocument2, а функция возвратит результат S_OK. В другом случае результат функции будет иным. Работающий код таков:
Кстати говоря, окна Проводника тоже поддерживают интерфейс IWebBrowser2, и через него можно определить, какая папка открыта в окне в данный момент. Подключившись к окну IE мы далее можем управлять им и получить доступ к загруженному в него документу. Например, можно закрыть все окна, где адрес страницы не отвечает заданным условиям. Можно также получить доступ к событиям IWebBrowser2. Кроме того, в модуле ShDocVw объявлен интерфейс событий DShellWindowsEvents DShellWindowsEvents = dispinterface ['{FE4106E0-399A-11D0-A48C-00A0C90A8F39}'] procedure WindowRegistered(lCookie: Integer); dispid 200; procedure WindowRevoked(lCookie: Integer); dispid 201; end; Если подключиться к нему, то можно отслеживать события возникновения и уничтожения окон IE и Windows Explorer. Интерфейс IHtmlWindow2Получив указатель на интерфейс Document: IHtmlDocument2, мы можем через него получить доступ к интерфейсу IHtmlWindow2, который соответствует объекту window в javasript. var W: IHtmlWindow2; W:=Document.ParentWindow; Не буду описывать все его свойства, их можно найти в MSHTML_TLB.pas, упомяну только процедуру procedure Alert(const message: WideString); Эта процедура выводит окно с сообщением в браузере. Другой, на мой взгляд, необычный для Дельфи способ использования этого интерфейса - обращение к именованным объектам страницы. Как известно, в javascript объект window является объектом самого высокого уровня в иерархии, включающим в себя все остальные. К объектам, имеющим имя, можно обращаться через него - window.myObjectName. Если использовать тип OleVariant, т.е. позднее связывание, то это можно использовать и в Дельфи. Пусть на странице есть сценарий javascript, в котором описана функция showsearch(). Открыв эту страницу в TWebBrowser или в IE, как описано раньше, мы можем вызвать эту функцию.
|