Сообщений 10 Оценка 136 Оценить |
Возможность добавить собственный пункт в контекстное меню IE позволяет пользователю настроить свой броузер "под себя", расширяя его функциональность в нужную ему сторону.
К примеру, с сайта lingvo.yandex.ru вы можете загрузить модуль для IE, позволяющий получать через сеть перевод с английского или на английский любого выделенного вами в окне браузера слова или словосочетания. Удобно? Несомненно! Выделяете в броузере нужное слово, пара щелчков мышью и перед вами страница с переводом. Кроме этого существует множество модулей различных поисковиков (yandex.ru, google.com, codeproject.com), позволяющих быстро производить поиск по соответствующим сайтам. Также, альтернативные менеджеры загрузки файлов (GetRight, FlashGet и т.п.) считают своим долгом оставить след в контекстном меню IE.
После этого небольшого вступления, я думаю стало понятно в каких приложениях это может пригодиться. Давайте теперь разберемся - как это работает. Чтобы не тренироваться на кошках, попробуем написать компонент, реализующий поиск по нашему любимому сайту (если кто не понял - RSDN.ru)
Internet Explorer хранит информацию о различных расширениях в реестре. В частности, "нестандартные" пункты контекстного меню можно найти по следующему адресу:
HKEY_CURRENT_USER Software Microsoft Internet Explorer MenuExt |
ПРИМЕЧАНИЕ Добавляя разделы в ветвь HКEY_CURRENT_USER, вы влияете на настройки Internet Explorer'а только для текущего пользователя. Чтобы добавить требуемую функциональность для всех пользователей, следует использовать ветвь HKEY_LOCAL_MACHINE. |
Не волнуйтесь, если раздел MenuExt на вашем компьютере отсутствует. Это всего лишь означает, что у вас пока нет дополнительных пунктов. В общем случае, чтобы добавить собственный элемент в контекстное меню, необходимо создать один раздел и пару параметров (выделены жирным). Параметры Contexts и Flags необязательны. Их значение будет пояснено ниже.
HKEY_CURRENT_USER Software Microsoft Internet Explorer MenuExt <Текст элемента меню> = <URL скрипта> DWORD Contexts = 0xXX DWORD Flags = 0xXX |
Таким образом, добавив по указанному пути новый ключ, мы создадим новый пункт контекстного меню. В качестве имени ключа следует указать текст, который будет использован при отображении меню. Также можно использовать символ "&", определяющий горячую клавишу. Значение по умолчанию для этого ключа должно содержать URL страницы, содержащей скрипт, который и будет выполнен при выборе данного элемента.
Броузер обращается к скрипту следующим образом. Содержимое страницы по соответствующему адресу загружается внутрь скрытого HTML-диалога, скрипт запускается на выполнение, по окончании которого, скрытый диалог автоматически уничтожается.
Итак, меню добавлено, осталось написать скрипт. В следующем примере, показано, как по выбору пункта меню открыть новое окно с результатами поиска по сайту RSDN. В качестве строки для поиска передается текст выделения в активном окне.
Через свойство menuArguments объекта external можно обратиться к объекту окна (window), в котором было вызвано контекстное меню. Ну, а через этот объект легко получить доступ ко всей объектной модели Interner Explorer.
rsdnsearch.htm
<SCRIPT LANGUAGE="JavaScript" defer> var parentwin = external.menuArguments; // получаем объект окна var doc = parentwin.document; // получаем объект документа var sel = doc.selection.createRange().text; // получаем текст выделения // открываем новое окно с результатами поиска по сайту Y=parentwin.open('http://www.rsdn.ru/cgi-bin/search.exe?sArt=On&sQnA=On&sForum=On&sRes=On&sFile=On&pcnt=20&extended=2&query='+sel,'Y','height=480,width=640,screenX=10,screenY=10,scrollbars=yes, toolbar=yes, titlebar=yes, status=yes, menubar=yes, location=yes, resizable'); </SCRIPT> |
Если по каким-либо причинам возможностей JavaScript/VBScript недостаточно, можно привлечь тяжелую артиллерию. Действительно, достаточно написать простой COM-объект и активизировать его из скрипта.
В следующем примере показан один из вариантов подобной реализации. В данном случае СОМ-объект содержит единственный метод Run, в который передается ссылка на объект окна.
gorsdn.htm
<SCRIPT language="VBScript"> On Error Resume Next Set MyObj=CreateObject("GoRSDN.ContextItem") If err<>0 then MsgBox("Модуль GoRSDN не установлен!") Else MyObj.Run external.menuArgements End If </SCRIPT> |
Получив в методе Run указатель на объект окна, можем сделать что-нибудь хорошее. Например, перейти на сайт RSDN.
STDMETHODIMP CMyObj::Run(LPDISPATHC pDispatch) { // получаем объект window CComQIPtr<IHTMLWindow2> pWindow = pDispatch; if (pWindow) { // Переходим на наш любимый сайт CComBSTR sUrl = L"http://www.rsdn.ru"; pWindow->navigate( sUrl); return S_OK; } return E_FAIL; } |
Используя подобную технику, легко реализовать практически любую функциональность. Например, 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-диалог следующего содержания.
rsdnsearch2.htm
<html style="width: 450px; height: 180px; margin: 10px"> <meta http-equiv="Content-Type" content="text/html; charset=windows-1251"> <head> <title>RSDN Search</title> </head> <script language="JavaScript"> function BodyLoad() { var parentwin = external.menuArguments; var doc = parentwin.document; var sel = doc.selection.createRange().text; query.value = sel; } function SearchClick() { var parentwin = external.menuArguments; parentwin.navigate("http://www.rsdn.ru/?cgi-bin/search.exe?sArt=On&sQnA=On&sForum=On&sRes=On&sFile=On&pcnt=20&extended=2&query="+query.value); //закрыть диалог window.close(); } </script> <body bgcolor="#C0C0C0" onload="BodyLoad()"> <center><table style="width:420px"> <tr><td colspan=2>Запрос</td></tr> <tr> <td width=100%><input type=text name="query" style="width:100%;" value=""></input> </td><td><input type=submit value="Найти" style="cursor:hand" onclick="SearchClick()"></input> </td></tr></table></center> <br> <hr size="1"> <p align="right"> <font face="ms sans serif" size="1">©<a href="http://www.rsdn.ru" target="_blank"> 2000 RSDN Team.</a></font> </p> </body> </html> |
Как видите ничего сложного. Обычный HTML. Обычный JavaScript. При этом внешний вид HTML-диалога практически не отличается от "стандартного" диалога. В функции BodyLoad передаем выделенный фрагмент текста в строку редактирования. По нажатию кнопки "Найти", запускаем скрипт поиска на RSDN. Да, и не забываем закрыть окно.
При выборе пункта меню, объект event окна источника (external.menuArguments.event) содержит некоторую полезную информацию, которую можно использовать из скрипта. Например, объект на котором щелкнули мышью, можно получить из свойства event.srcElement. А свойство event.type содержит одну из следующих строк, определяющих тип отображаемого меню:
Используя эту информацию, можно реализовать собственное (отличное от других) поведение для разных типов контекстного меню.
Для демонстрации вышеизложенного приведу четыре примера:
1 и 2-ой примеры содержат скрипты WSH (Windows Script Host) избавляющие от ручного копания в реестре. Чтобы добавить новый пункт достаточно запустить файл install.vbs. Убедитесь, что каталоги файлов со скриптами указаны верно:
... REG_NEWMENU = "HKCU\Software\Microsoft\Internet Explorer\MenuExt\&RSDN Search\" ' Записываем в реестр требуемые значения shell.RegWrite REG_NEWMENU, "c:\rsdn\rsdnsearch.htm", "REG_SZ" ... |
В третьем примере добавление соответствующего пункта меню происходит одновременно с регистрацией 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-скрипт будет выглядеть так:
NoRemove MenuExt { '&RSDN Search' = s 'res://%MODULE%/GORSDN.DLL.HTM' { val Contexts = d '48' } } |
Здесь, "GORSDN.DLL.HTM" - строковый идентификатор ресурса htm-скрипта в DLL.
Сообщений 10 Оценка 136 Оценить |