Как добавить свой пункт в контекстное меню IE
Возможность добавить собственный пункт в контекстное меню IE позволяет пользователю настроить свой броузер "под себя", расширяя его функциональность в нужную ему сторону.
К примеру, с сайта lingvo.yandex.ru вы можете загрузить модуль для IE, позволяющий получать через сеть перевод с английского или на английский любого выделенного вами в окне браузера слова или словосочетания. Удобно? Несомненно! Выделяете в броузере нужное слово, пара щелчков мышью и перед вами страница с переводом. Кроме этого существует множество модулей различных поисковиков (yandex.ru, google.com, codeproject.com), позволяющих быстро производить поиск по соответствующим сайтам. Также, альтернативные менеджеры загрузки файлов (GetRight, FlashGet и т.п.) считают своим долгом оставить след в контекстном меню IE.
После этого небольшого вступления, я думаю стало понятно в каких приложениях это может пригодиться. Давайте теперь разберемся - как это работает. Чтобы не тренироваться на кошках, попробуем написать компонент, реализующий поиск по нашему любимому сайту (если кто не понял - RSDN.ru)
Покопаемся в реестреInternet Explorer хранит информацию о различных расширениях в реестре. В частности, "нестандартные" пункты контекстного меню можно найти по следующему адресу:
ПРИМЕЧАНИЕДобавляя разделы в ветвь HКEY_CURRENT_USER, вы влияете на настройки Internet Explorer'а только для текущего пользователя. Чтобы добавить требуемую функциональность для всех пользователей, следует использовать ветвь HKEY_LOCAL_MACHINE.
Не волнуйтесь, если раздел MenuExt на вашем компьютере отсутствует. Это всего лишь означает, что у вас пока нет дополнительных пунктов. В общем случае, чтобы добавить собственный элемент в контекстное меню, необходимо создать один раздел и пару параметров (выделены жирным). Параметры Contexts и Flags необязательны. Их значение будет пояснено ниже.
Таким образом, добавив по указанному пути новый ключ, мы создадим новый пункт контекстного меню. В качестве имени ключа следует указать текст, который будет использован при отображении меню. Также можно использовать символ "&", определяющий горячую клавишу. Значение по умолчанию для этого ключа должно содержать URL страницы, содержащей скрипт, который и будет выполнен при выборе данного элемента.
Броузер обращается к скрипту следующим образом. Содержимое страницы по соответствующему адресу загружается внутрь скрытого HTML-диалога, скрипт запускается на выполнение, по окончании которого, скрытый диалог автоматически уничтожается.
Скрипт обработкиИтак, меню добавлено, осталось написать скрипт. В следующем примере, показано, как по выбору пункта меню открыть новое окно с результатами поиска по сайту RSDN. В качестве строки для поиска передается текст выделения в активном окне.
Через свойство menuArguments объекта external можно обратиться к объекту окна (window), в котором было вызвано контекстное меню. Ну, а через этот объект легко получить доступ ко всей объектной модели Interner Explorer.
Использование COM-компонентовЕсли по каким-либо причинам возможностей JavaScript/VBScript недостаточно, можно привлечь тяжелую артиллерию. Действительно, достаточно написать простой COM-объект и активизировать его из скрипта.
В следующем примере показан один из вариантов подобной реализации. В данном случае СОМ-объект содержит единственный метод Run, в который передается ссылка на объект окна.
Получив в методе Run указатель на объект окна, можем сделать что-нибудь хорошее. Например, перейти на сайт RSDN.
Используя подобную технику, легко реализовать практически любую функциональность. Например, FlashGet использует похожий прием для реализации пунктов "Закачать при помощи FlashGet" и "Закачать все"
ПРИМЕЧАНИЕНесмотря на то, что мы создаем и используем COM-объект внутри Internet Explorer'а, помечать его как "безопасный" (CATID_SafeForScripting, CATID_SafeForInitializing ) необязательно.
Контекст отображенияВ прошлом примере мы добавили собственный пункт меню к IE. Однако, если задуматься, отображение нашего пункта не всегда разумно. Например, бессмысленно добавлять команду "RSDN Search" в ответ на шелчок правой клавишей на картинке или элементе ActiveX. Следовательно, имеет смысл определить контекст отображения нашего пункта меню, т.е. сообщить IE, в каких случаях следует показывать наш пункт, а в каких нет. Это можно сделать добавив в раздел "&RSDN Search" необязательный параметр Contexts .
Параметр Contexts содержит идентификатор контекстного меню, определяющий в ответ на какое действие отображать даный пункт. Возможна побитовая комбинация следующих вариантов.
ContextsЗначение По умолчанию0x1 Изображение0x2 Элемент управления0x4 Таблица0x8 Выделенный текст0x10 Ссылка0x20
К примеру, если мы хотим, чтобы наш пункт появлялся только на ссылке или при наличии выделенного фрагмента, необходимо в параметре Contexts прописать значение 0x30 (0x10 | 0x20).
Модальный режимЗадав другой необязательный параметр - Flags = 0x1 , можно заставить IE выполнять скрипт в модальном режиме. При этом, создаваемый диалог не будет скрытым, а скрипт будет запущен подобно вызову метода ShowModalDialog . К исходному окну можно обратиться также через external.menuArguments. Позаботится о закрытии диалогового окна, в этом случае, придется самостоятельно.
Чтобы продемонстрировать данный способ в действии, усложним первый пример. Давайте предоставим пользователю возможность редактировать текст поискового запроса. Для этого необходимо создать простенький HTML-диалог следующего содержания.
Как видите ничего сложного. Обычный HTML. Обычный JavaScript. При этом внешний вид HTML-диалога практически не отличается от "стандартного" диалога. В функции BodyLoad передаем выделенный фрагмент текста в строку редактирования. По нажатию кнопки "Найти", запускаем скрипт поиска на RSDN. Да, и не забываем закрыть окно.
Информация о событииПри выборе пункта меню, объект event окна источника (external.menuArguments.event) содержит некоторую полезную информацию, которую можно использовать из скрипта. Например, объект на котором щелкнули мышью, можно получить из свойства event.srcElement . А свойство event.type содержит одну из следующих строк, определяющих тип отображаемого меню:
- MenuExtDefault
- MenuExtImage
- MenuExtControl
- MenuExtTable
- MenuExtTextSelect
- MenuExtAnchor
- MenuExtUnknown
Используя эту информацию, можно реализовать собственное (отличное от других) поведение для разных типов контекстного меню.
Примеры, примерыДля демонстрации вышеизложенного приведу четыре примера:
- RSDN Search Скрипт поиска по выделенному фрагменту текста
- RSDN Search2 HTML-диалог поиска по сайту
- Goto RSDN! СОМ-объект, реализующий переход на RSDN.ru
- RSDN Search СОМ-объект, реализующий поиск по выделенному фрагменту
1 и 2-ой примеры содержат скрипты WSH (Windows Script Host) избавляющие от ручного копания в реестре. Чтобы добавить новый пункт достаточно запустить файл install.vbs . Убедитесь, что каталоги файлов со скриптами указаны верно:
В третьем примере добавление соответствующего пункта меню происходит одновременно с регистрацией COM-объекта, поэтому запускать дополнительные скрипты не требуется. Убедитесь только, что скрипт GoRSDN.dll.htm лежит в том же каталоге, что и GoRSDN.dll.
ПРИМЕЧАНИЕВы, наверное, обратили внимание на странное имя скрипта - GoRSDN.dll.htm. К сожалению, это обусловлено производственной необходимостью. Язык скриптов реестра в ATL (RGS - ReGistry Script) поддерживает простой и элегантный способ общения с реестром. Чтобы задать местоположение файла c COM-объектом, в нем используется предопределенная метка-заполнитель - %MODULE%. При вызове функции регистрации, эта метка заменяется на результат вызова функции GetModuleFileName. Существует возможность определять собственные метки-заполнители. Однако в данном случае, можно поступить проще, написав в RGS-файле следующее: '%MODULE%.htm'. При этом, в качестве URL скрипта будет прописан путь к файлу GoRSDN.dll.htm. Что, собственно, и требовалось.
Элегантное решение проблемы предложил Алексей Кирюшкин. Его способ продемонстрирован в четвертом примере. Воспользуемся тем обстоятельством, что Internet Explorer умеет загружать HTM-страницы из ресурсов. При этом можно импортировать скрипт в ресурсы DLL содержащей COM-объект. В этом случае соответствующий RGS-скрипт будет выглядеть так: