Базы данныхИнтернетКомпьютерыОперационные системыПрограммированиеСетиСвязьРазное
Поиск по сайту:
Подпишись на рассылку:

Назад в раздел

Меню + TwebBrowser = Проблема?

eManual - электронная документация
ПрограммыЖелезоДрайверыХостингЭнциклопедия рекламы

Меню + TwebBrowser = Проблема?
Лозовюк Александр

Эту статью можно рассматривать как продолжение или дополнение к моей первой статье о компоненте TwebBrowser - Как сделать WebBrowser средствами Delphi 5.

В конференции я часто натыкался на вопросы типа – "Как добавить свой пункт меню в контекстное меню IE, как это делает ReGet", "Как запретить появление контекстного меню в TwebBrowser” или "Как показать свое меню вместо стандартного". А вот ответов в большинстве случаев не было, или они советовали попробовать другие компоненты. Но когда мне самому понадобилось в рамках одного проекта сразу, и запретить появление меню, и вставить свой пункт в стандартное меню IE, я решил покопать в этом направлении. И, конечно, MSDN выручила меня в этих поисках. Так что не бойтесь, меню и TwebBrowser – очень даже дружны между собой и то, что с легкостью делают ребята с ReGet Software, не такая уже и неприступная магия…


Запрещение появления меню в TwebBrowser
 

Хотя в инспекторе и есть такое свойство для этого компонента – PopurMenu, но его использование очень ограничено. Давайте для примера создадим PopurMenu с двумя произвольными пунктами и присвоим свойству PopurMenu TwebBrowser значение PopurMenu1. Запускаем приложение. Щелчок правой кнопкой мыши – ура, меню наше исправно отображаеться. Но радоваться рано. Загружаем любую страницу в браузер, снова щелкае мышкой – вместо нашего меню появляеться стандартное контекстное меню IE. Почему же так?

Компонент TwebBrowser всего лишь оболочка для COM объектов IE, а пока никакая страница не загружена – все сообщения передаются непосредственно вашей программе и, обрабатывая их, программа воспринимает TwebBrowser как обычный VCL-компонент. Поэтому наше меню и появлялось. Когда же вызван метод Navigate, управление идет уже через СОМ интерфейсы, поэтому сообщения обрабатываються не оконным компонентом, а кодом "под оболочкой".

Вообще запретить появление меню можно. Вот некоторые способы.

...

private

...

procedure WMMouseActivate(var Msg: TMessage); message WM_MOUSEACTIVATE;

end;

...

Ставим обработчик для сообщения WM_MOUSEACTIVATE на уровне головной формы приложения.

Потом пишем процедуру:

procedure TMainForm.WMMouseActivate(var Msg: TMessage);

begin

try

inherited;

//Анализируем, какая кнопка мыши нажата

if Msg.LParamHi = 516 then // если правая

// показываем свое меню

PopupMenu1.Popup(Mouse.CursorPos.x, Mouse.CursorPos.y);

Msg.Result := 0;

except

end;

end;

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

Что бы просто запретить появление меню можно преобразовать процедуру так:

procedure TForm1.WMMouseActivate(var Msg: TMessage);

begin

try

inherited;

if Msg.LParamHi = 516 then

Msg.Result:= MA_NOACTIVATEANDEAT;

except

end;

end

Значение Msg.LparamHi показывает, какая кнопка нажата. 513 - нажата левая, 516 – нажата правая.

Все, что сказано было про координаты, справедливо и здесь. Все эти решения имеют один недостаток – процедура срабатывает на каждое нажатие кнопки мыши в пределах всего приложения.

И еще один недостаток/особенность – полностью, со 100% надежностью перекрыть меню IE своим таким способом почему-то не удается, а вот просто запретить появление – да.

А можно ли управлять отображением меню на уровне самого WebBrowser? Да, отвечает MSDN.

Для этого нужно сперва получить доступ к интерфейсу IDocHostUIHandler и вызвать один из его методов – ShowContextMenu.

Учтите, версия IE – не ниже 4.0. (В С/С++ он описан в файлах Mshtmhst.h; Mshtmhst.idl )

Получить этот интерфейс можно вызывая QueryInterface с параметром IID_IDocHostUIHandler. Он предназначен для управления панелями, меню и контекстными меню WebBrowser-a.

Нас интересует пока только метод ShowContextMenu. Вот его обьявление:

function ShowContextMenu (const dwID: DWORD; const ppt: PPOINT; const pcmdtReserved: IUnknown; const pdispReserved: IDispatch): HRESULT; stdcall;

dwID – идентификатор меню, которое будет отображаться

ppt – указатель на структуру, которая указывает на координаты, где нужно отобразить меню.

pcmdTarget - ссылка на IOleCommandTarget интерфейс, который используется для запроса статуса и команд, которые должны выполняться меню.

рdispObject - ссылка на IDispatch интерфейс объекта, для того, что бы вызывать различные меню для различных объектов.

 

Метод возвращает:

S_OK -Отображается стандартное меню.

S_FALSE - Отображается другое, определенное программой меню.

DOCHOST_E_UNKNOWN - Идентификатор меню неизвестен.

 

В Internet Explorer 4.0 параметр pdispObject не используется, но в IЕ 5 и позже параметр содержит адрес IDispatch интерфейса. Таким способом можно выборочно запрещать появление контекстных меню.

Некоторые другие интересные методы IDocHostUIHandler:

function HideUI: HRESULT; stdcall; - вызываеться, когда удаляеться пункт меню или панели инструментов.

function ShowUI (const dwID: DWORD; const pActiveObject: IOleInPlaceActiveObject; const pCommandTarget: IOleCommandTarget; const pFrame: IOleInPlaceFrame; const pDoc: IOleInPlaceUIWindow): HRESULT; stdcall;

Вызиваеться, когда приложение заменяет меню или панель инструментов.

Добавление пункта в стандартное меню

Иногда, если вы пишете какое-то приложение, которое взаимодействует с браузером, вам необходимо вызвать его непосредственно из IE. Но как добавить свой пункт в меню?

Пункт меню должен быть связан через URL с файлом, который содержит текст сценария, например, на JavaScript. Для того, что бы добавить пункт меню, откройте программно в реестре ключ:

HKEY_CURRENT_USER

Software

Microsoft

Internet Explorer

MenuExt

В этом разделе создайте подраздел, который будет иметь название такое же, как и пункт меню. Значение по умолчанию содержит URL, по которому находиться скрипт. Для подчеркивания вставьте в название перед нужной буквой символ &.

Скрипт будет загружен и выполнен в скрытом окне. В его свойстве external.menuArguments будет содержаться объект window того окна, где был выполнен скрипт меню.

Пример.Вставляет пункт с названием "Демо" в стандартное меню. При нажатии выполняется скрипт, который содержится в файле "С:demo_script.htm".

 

HKEY_CURRENT_USER

Software

Microsoft

Internet Explorer

MenuExt

Open in new window = "file://c:demo_script.htm"

 

В файл впишите следующее

 

<SCRIPT LANGUAGE="JavaScript" defer>

open(external.menuArguments.location.href);

</SCRIPT>

 

Действие скрипта заключаеться в следующем:

Он открывает новое окно браузера, и загружает в него документ, который определен в external.menuArguments.location.href – окне, в котором было вызвано меню.


Дополнительные ключи.


Под ключом, где содержится URL скрипта, есть еще несколько величин.Одна из них определяет, в каком из доступных контекстных меню появиться этот новый пункт.Вторая определяет, что сценарий должен выполняться как dialog box.

Ключ "Contexts" имеет тип DWORD, и задает контексты, в которых будет появляться ваше меню. Определяется как применение операции логического ИЛИ над следующими константами:

 

(0x1 << CONTEXT_MENU_DEFAULT) (evaluates to 0x1)

(0x1 << CONTEXT_MENU_IMAGE) (evaluates to 0x2)

(0x1 << CONTEXT_MENU_CONTROL) (evaluates to 0x4)

(0x1 << CONTEXT_MENU_TABLE) (evaluates to 0x8)

(0x1 << CONTEXT_MENU_TEXTSELECT) (evaluates to 0x10)

(0x1 << CONTEXT_MENU_ANCHOR) (evaluates to 0x20)

(0x1 << CONTEXT_MENU_UNKNOWN) (evaluates to 0x40)

 

Так, к примеру, вам нужно, что бы ваше меню появлялось только когда есть выделенный текст. Тогда запишите значение 0x10 (CONTEXT_MENU_TEXTSELECT)

 

Второй ключ- flag с типом DWORD. Если первый бит установлен в 0x1, то сценарий выполняется так, если бы он был вызван методом showModalDialog. Окно, в котором выполняеться скрипт не скрываеться, и не закрываеться после выполнения сценария.

 

Как реализовать все это в Дельфи?

1. Поскольку метод вставки пунктов меню позволяет вставить только ссылку на файл со скриптом, то нужно писать скрипт который будет вызывать вашу программу и передавать ей нужные значения. Для этого нужно еще знать VBScript или JavaScript.

2. Большая проблема состоит в том, что описания интерфейса IDocHostUIHandler нет в файлах.

Но его описание есть в иходниках компонента EmbeddedWB, который можно взять на http://www.euromind.com/iedelphi/

Немножко поразбиравшись, я пришел к таким результатам:

Интерфейс не поддерживаеться стандартным TWebBrowser. Попытка перенести описание интерфейса с EmbeddedWB ник чему не приводит. Я понял с исходников, что при вызове

IUnknown(WebBrowser1) as IDocHostUIHandler происходит обращение к DefaultInterface, а он у TWebBrowser IWebBrowser2. А он не знает о нужном нам интерфейсе.

Может, эта статья и не ответила на все вопросы, а только создала новые – не знаю. Это всегда так – как только с чем-то начинаешь разбираться, сразу к старым вопросам прибавляются новые…



  • Главная
  • Новости
  • Новинки
  • Скрипты
  • Форум
  • Ссылки
  • О сайте




  • Emanual.ru – это сайт, посвящённый всем значимым событиям в IT-индустрии: новейшие разработки, уникальные методы и горячие новости! Тонны информации, полезной как для обычных пользователей, так и для самых продвинутых программистов! Интересные обсуждения на актуальные темы и огромная аудитория, которая может быть интересна широкому кругу рекламодателей. У нас вы узнаете всё о компьютерах, базах данных, операционных системах, сетях, инфраструктурах, связях и программированию на популярных языках!
     Copyright © 2001-2024
    Реклама на сайте