Меню + 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. А він не знає про потрібний нам інтерфейсі.

Може, ця стаття і не відповіла на всі питання, а тільки створила нові – не
знаю. Це завжди так – як тільки з чим-то починаєш розбиратися, відразу до старих
питань додаються нові …

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*