Отправляет email-рассылки с помощью сервиса Sendsay

Программирование на Visual С++

  Все выпуски  

Программирование на Visual С++ - No.88 (Написание Plugin'ов для IE. Часть 2)


Информационный Канал Subscribe.Ru


  ПРОГРАММИРОВАНИЕ    НА    V I S U A L   C + +
РАССЫЛКА САЙТА       
RSDN.RU  

    Выпуск No. 88 от 20 апреля 2003 г.
   
Подписчиков: 20887 

РАССЫЛКА ЯВЛЯЕТСЯ ЧАСТЬЮ ПРОЕКТА RSDN , НА САЙТЕ КОТОРОГО ВСЕГДА МОЖНО НАЙТИ ВСЮ НЕОБХОДИМУЮ РАЗРАБОТЧИКУ ИНФОРМАЦИЮ, СТАТЬИ, ФОРУМЫ, РЕСУРСЫ, ПОЛНЫЙ АРХИВ ПРЕДЫДУЩИХ ВЫПУСКОВ РАССЫЛКИ И МНОГОЕ ДРУГОЕ.

Здравствуйте!


 CТАТЬЯ

Написание Plugin'ов для Internet Explorer
Часть 2

Исходные тексты примера - linksave2.zip (~10Kb)

После публикации первой части статьи (см. «Программист» №1/2002 [статья была также опубликована в рассылке, см. выпуск 62 - AJ]) мне пришло много писем примерно следующего содержания: «Плагины – это здорово, пункт в меню – это хорошо, но нам нужен интерактив!» Поскольку «интерактив» подразумевает наличие окна на экране, то вопрос сводился к созданию так называемых Explorer Bars (или Панелей Обозревателя в русской версии IE). Полюбоваться на такую панель вы можете, выбрав какой-нибудь пункт в меню Вид > Панели обозревателя или нажав, например, Ctrl+E или Ctrl+H.

Чтобы не отвечать каждому по отдельности и в то же время как можно подробнее ответить на вопрос, я решил посвятить созданию панелей обозревателя отдельную статью.

Теоретическая часть

Для начала немного теории. Первое, что необходимо отметить – это близкое родство панелей обозревателя в IE (например, панели поиска, Ctrl+E) и панелей инструментов оболочки Windows (например, Quick Launch). Физически это одно и тоже, и для их создания требуются одни и те же шаги. Разница заключается только в ключах реестра, которые необходимо создать для регистрации панелей в браузере и оболочке соответственно.

Теперь второе. Эти самые панели бывают двух типов. Рассмотрим каждый из типов подробнее.

Панели первого типа содержат HTML-страницу. Пример такой панели – уже неоднократно упоминавшийся «Поиск». Фактически при отображении такой панели на экране браузер создает дочернее окно (можно даже сказать фрейм), в которое загружает требуемую страницу. Для создания таких панелей никаких программистских усилий не требуется, достаточно правильно прописать ключи в реестре. Эти ключи аналогичны ключам для панелей второго типа, а отличия будут отмечены особо, при описании процесса регистрации панелей.

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

Практическая часть
Создание плагина

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

Чтобы вы сразу могли оценить трудоемкость написания такого плагина, приведу список интерфейсов, которые нам необходимо реализовать:

  • IObjectWithSite
  • IDeskBand
  • IContextMenu

ПРИМЕЧАНИЕ

Хочу обратить ваше внимание на то, что интерфейс IDeskBand имеет сложную структуру наследования. Он наследует IDockingWindow, который в свою очередь наследует IOleWindow.

Реализация IContextMenu не является обязательной и необходима только для добавления пунктов в контекстное меню. Подробнее об этом интерфейсе можно прочитать в статье «Расширения оболочки Windows – обработчики контекстных меню» в «Программисте» №12/2001.

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

А интерфейс IInputObject может пригодиться, если на вашей панели присутствуют поля ввода (edit boxes). Браузер вызывает метод IInputObject::UIActivateIO каждый раз, когда ваша панель теряет или получает фокус. Благодаря этому вы можете устанавливать или убирать фокус ввода с определенных элементов управления на панели (например, полей редактирования).

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

  • IDeskBand::ContextSensitiveHelp
  • IDeskBand::ResizeBorderDW
  • IContextMenu::GetCommandString

Реализацию и назначение остальных методов мы рассмотрим далее. Методы интерфейса IObjectWithSite предназначены для организации взаимодействия плагина и контейнера (в нашем случае контейнером служит Internet Explorer). Когда панель нашего плагина отображается на экране, браузер вызывает метод IObjectWithSite::SetSite, передавая ему указатель на один из своих интерфейсов. Когда же пользователь закрывает панель, браузер вызывает этот метод со значением NULL в качестве аргумента. Так он просит нас освободить все его интерфейсы. Реализация этого метода – такая же, как и в первой статье, за исключением того, что в этом методе мы должны создать окно нашего плагина.

Код, создающий окно, расположен в методе CreateOurWindow. Выглядит он следующим образом:


bool IMyIEExtention::CreateOurWindow(HWND hParent)
{
  if (!hParent || !IsWindow(hParent))
    return false;

  if (m_hOurWindow)
    CloseDW(0);

  WNDCLASS wc;
  if (!GetClassInfo(g_hThisModule, _myWndClass, &wc))
  { //Класс еще не зарегистрирован
    ZeroMemory(&wc, sizeof(wc));
    wc.style="CS_GLOBALCLASS;"
    wc.lpfnWndProc=&MyWindowProc;
    wc.hInstance=g_hThisModule;
    wc.hbrBackground=(HBRUSH)COLOR_WINDOW;
    wc.lpszClassName=_myWndClass;

    if (!RegisterClass(&wc))
      return false;
  }

//Создаем окно
  RECT rc;
  GetClientRect(hParent, &rc);

  m_hOurWindow=CreateWindow(_myWndClass, NULL, WS_CHILD, 0,
                            0, rc.right, rc.bottom, hParent,
                            NULL, g_hThisModule, this);

  return m_hOurWindow != NULL;
}

Окно создается, как и любое другое дочернее (child) окно. Родителем в данном случае выступает окно, созданное браузером для нашей панели. Чтобы получить его дескриптор, необходимо получить из интерфейса, переданного в IObjectWithSite::SetSite, указатель на интерфейс IOleWindow и вызвать из него метод GetWindow.

Метод IObjectWithSite::GetSite браузер вызывает сразу за методом IObjectWithSite::SetSite (видимо, для проверки). В метод IObjectWithSite::GetSite просто нужно обернуть вызов QueryInterface из указателя на интерфейс, переданного в метод IObjectWithSite::SetSite.

ПРИМЕЧАНИЕ

Как показывают эксперименты (с IE5,6), метод IObjectWithSite::GetSite можно не реализовывать. Но раз Microsoft требует, значит лучше сделать.

Переходим к методам интерфейса IDeskBand. Первый из них – это метод GetWindow (который IDeskBand наследует от IOleWindow). Реализация этого метода очень проста: необходимо вернуть дескриптор нашего окна, созданного в методе IObjectWithSite::SetSite.

Теперь рассмотрим реализацию двух методов, которые IDeskBand наследует от IDockingWindow. Это метод ShowDW, в котором мы должны скрыть или показать наше окно (при помощи ShowWindow), и метод CloseDW, в котором мы должны уничтожить наше окно (при помощи DestroyWindow) и очистить все связанные с ним ресурсы.

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

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

Регистрация плагина

Регистрация панели-плагина, как вы убедитесь далее, не представляет труда. Регистрация панели, содержащей HTML-страницу, отличается некоторыми дополнительными параметрами, которые я буду отмечать особо.

Для начала необходимо зарегистрировать наш плагин как COM-сервер (подробнее см. http://www.rsdn.ru/?article/?com/introcom.xml) В том случае, если панель просто отображает HTML-страницу, то в значение по умолчанию параметра InProcServer32 записывается Shdocvw.dll.

Теперь рядом с ключом InProcServer32 (т.е. дочерним по отношения к GUID COM-сервера) необходимо создать ключ Instance. Для панелей, содержащих HTML-страницу, внутри этого ключа необходимо создать строковый параметр с именем «CLSID» и присвоить ему значение {4D5C8C2A-D075-11d0-B416-00C04FB90376}.

Теперь внутри ключа Instance необходимо создать ключ InitPropertyBag. Для HTML-панелей внутри этого ключа необходимо создать строковый параметр URL. Его значение задает адрес страницы, которая будет загружена в HTML-панель обозревателя.

Двигаемся дальше. Теперь, на том же уровне, что и InProcServer32 (и Instance) необходимо создать ключ Implemented Categories. Внутри этого ключа следует создать один из следующих ключей:

  • {00021494-0000-0000-C000-000000000046} – для горизонтальной панели
  • {00021493-0000-0000-C000-000000000046} – для вертикальной панели

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


[HKEY_CLASSES_ROOT\CLSID\{9C590067-8A6A-4db6-B052-069283790B04}]
@="Some HTML plugin"

[HKEY_CLASSES_ROOT\CLSID\
{9C590067-8A6A-4db6-B052-069283790B04}\Implemented Categories]

[HKEY_CLASSES_ROOT\CLSID\
{9C590067-8A6A-4db6-B052-069283790B04}\Implemented Categories\
{00021493-0000-0000-C000-000000000046}]

[HKEY_CLASSES_ROOT\CLSID\
{9C590067-8A6A-4db6-B052-069283790B04}\InProcServer32]
@="Shdocvw.dll"
"ThreadingModel"="Apartment"

[HKEY_CLASSES_ROOT\CLSID\
{9C590067-8A6A-4db6-B052-069283790B04}\Instance]
CLSID="{4D5C8C2A-D075-11d0-B416-00C04FB90376}"

[HKEY_CLASSES_ROOT\CLSID\
{9C590067-8A6A-4db6-B052-069283790B04}\Instance\InitPropertyBag]
URL="http://www.microsoft.com"

Заключение

Теперь, если вы прочитали обе статьи, вы умеете создавать плагины для Internet Explorer, глубоко интегрированные в браузер и осуществляющие диалог с пользователем. Этого вполне достаточно для создания легких и функциональных приложений, наподобие интегрированных download manager’ов.

Теперь дело за вами, читатели. Так стоит ли ожидать в ближайшее время резкого роста числа таких приложений?



Ведущий рассылки: Алекс Jenter   jenter@rsdn.ru
Публикуемые в рассылке материалы принадлежат сайту RSDN.

| Предыдущие выпуски     | Статистика рассылки


RLE Banner Network

http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное