Статьи Королевства Дельфи


Использование функциональности IE или заметки о WebBrowser - часть 8


procedure TFormSimpleWB.WebBrowser1NewWindow2(Sender: TObject; var ppDisp: IDispatch; var Cancel: WordBool); var newForm:TFormSimpleWB; begin newForm:=TFormSimpleWB.Create(Application); newForm.Show; ppDisp:=newForm.WebBrowser1.ControlInterface; end;

С остальными методами должно быть более-менее понятно из их названия. Если это не так - можно посмотреть уже упоминаемую статью Александра Лозовюка.

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

Первым делом это TWebBrowser.Document:IDispatch . Через это свойство можно получить доступ к интерфейсу IHtmlDocument2.. Далее через этот интерфейс можно получить доступ к большинству средств по взаимодействию с загруженным документом. То есть это очень интересное и "нужное" свойство. Но немного забегая наперед, скажу, что если Вы попытаетесь использовать TWebBrowser.Document:IDispatch, то Вы рано или поздно заметите довольно странную "утечку" памяти в процессе навигации. В чем же дело? После анализа ситуации, удалось определить, что для любой интерфейсной ссылки на документ, которая получена через этот свойство, счетчик использования "необоснованно" увеличивается на 1 и соответствующий COM-обьект никогда не будет освобожден. При более детальном изучении нашлась и создательница этой проблемы - function TOleControl.GetIDispatchProp(Index: Integer): IDispatch;, через которую и работает TWebBrowser.Document:IDispatch (я речь веду о Delphi5, возможно в Delphi4 все нормально, не проверял). Детальный рассказ об этой ситуации выходит за рамки этой статьи..
К счастью эту проблему легко обойти, использовав для получения IHtmlDocument2 альтернативные возможности, хотя бы WebBrowser1.ControlInterface.Document .

Также хочется упомянуть о property LocationURL: WideString; Как утверждается в вышеупомянутой статье Александра Лозовюка , оно содержит URL ресурса, загруженного в браузер. Того же мнения придерживается и контекстная справка от Delphi5. Мало того - об этом также говорится в - во всяком случае так было на момент написания статьи ...

Но это не совсем так. Дополним наш "шедевр" обработчиком события окончания загрузки документа:

implementation {$R *.DFM} uses mshtml; procedure TFormSimpleWB.WebBrowser1DocumentComplete(Sender: TObject; const pDisp: IDispatch; var URL: OleVariant); begin // Caption:=WebBrowser1.LocationURL+' '+ ((pDisp as IWebBrowser).Document as IHtmlDocument2).URL; end;

Обратите внимание на включение модуля mshtml, который позволяет использовать функциональность mshtml.dll.

Перед тем как продолжить рассказ я снова вынужден сделать маленькое отступление в сторону COM.

Обратите внимание, как имея в руках интерфейс типа IDispatch от броузера (параметр pDisp), который закончил загрузку документа (это можно подсмотреть в описании события DocumentComplete в MSDN ), мы посредством "as" получаем интерфейс типаbIWebBrowser на тот же объект (здесь имеем неявный вызов QueryInterface). Этот интерфейс при помощи свойства Documentпbозволяет нам получить интерфейс IHtmlDocument2 к загруженому документу. И вот в конце-концов через этот интерфейс мы можем обратится к интересующему нас свойству URL , которое и возвращает адрес того ресурса, который в действительности загружен в браузер (а property LocationURL говорит только о том, что мы броузеру сказали загружать). Да, нам еще не раз придется продиратся через такие дебри интерфейсов, свойств и запросов. И что наиболее печально - MSDN не всегда внятно говорит где и от кого можно запросить интересующий нас интерфейс ... Также на первых порах вызывает недоумение тот факт, почему тот же IWebBrowser.Document есть типа IDispatch, а не хотя бы тот же IHtmlDocument2. Но это довольно легко понять, если вспомнить во первых, что WebBrowser позволяет работать с ним разного рода скриптовым языкам, а во вторых, что интерфейс IDispatch позволяет вызывать свойства и методы по имени (что собственно и делают скриптовые языки). В принципе, мы бы также работать в Delphi с WebBrowser в стиле скриптовых языков, но я сознательно не привожу примеров такого подхода, так как он чреват возникновением разного рода ошибок, которые можно будет обнаружить только во время выполнения (и которые отсеиваются на этапе компиляции при использовании "нормальных" интерфейсов).

Но довольно теории - сделаем маленький эксперимент: запустим "шедевр" на выполнение и дадим команду навигации на заведомо отсутствующий ресурс. И что же мы видим:



Взглянем на заголовок окна нашей формы - до символов есть значение, которое возвращает property LocationURL , после - действительный адрес того ресурса, который отображается браузером по окончании загрузки.
Прошу понять меня правильно - этот пример я привел с целью еще один раз показать, что даже в фирменных материалах бывают неточности ... К сожаленью, такие неточности нам обходятся иногда очень дорого ...




Начало  Назад  Вперед