Рейтинговые книги
Читем онлайн Программирование на Visual C++. Архив рассылки - Алекс Jenter

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 125 126 127 128 129 130 131 132 133 ... 156

Библиотека MFC требует наличия кода инициализации, и тут уж ничего не поделаешь. Если очень хочется использовать библиотеку оконных классов в сверхмалых проектах, посмотрите в сторону ATL/WTL и их расширений (например, Attila).

Используйте SEH вместо C++ Exceptions

Обработка исключений в стиле C++ неизбежно потребует стартового кода CRT. Если исключения использовать необходимо, попробуйте воспользоваться структурными исключениями Win32 с помощью ключевых слов __try, __except, __finally  и т.д. Для их использования нужно подключить библиотеку импорта kernel32.lib.

Попробуйте позаимствовать необходимую функцию из исходных файлов CRT

Visual C++ поставляется с большим набором исходных файлов, в число которых входит и реализация CRT. Их изучение, кстати, приносит и еще одну выгоду – это поможет разобраться, как именно устроена поддержка стандартной библиотеки. В общем, "Use the source, Luke"!

Используйте директиву #pragma intrinsic

Некоторые функции, требующие инициализации CRT, могут быть попросту вставлены компилятором в точку вызова. К ним относятся cos, strlen и многие другие. Изучите документацию на #pragma intrinsic и опцию компилятора /Oi.

Для преобразования типов воспользуйтесь Automation API

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

Можно использовать как функции высокого уровня VariantChangeType/VariantChangeTypeEx, так и вспомогательные функции преобразования вида VarXXXFromYYY. В приведенном выше блоке кода, например, поможет функция VarI4FromR8:

double t;

long a;

VarI4FromR8(t, &a); // Никаких проблем с внешними ссылками

Использование Automation API позволит не только решить проблему преобразования, описанную выше, но и учесть при этом региональные настройки – например, получить локализованную строку даты. Кроме того, функция VarBstrCmp поможет при сравнении строк unicode (но будьте осторожны с ней – в старых версиях Windows она отличается от новых реализаций, также нужно иметь установленный Service Pack 4 или выше для VC, иначе заголовочный файл будет содержать некорректное описание этой функции).

Для использования этих функций необходимо подключить библиотеку импорта oleaut32.lib.

До следующей встречи!

Алекс Jenter [email protected] Duisburg, 2001. Публикуемые в рассылке материалы принадлежат сайту RSDN. 

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

Выпуск №62 от 3 февраля 2002 г.

Здравствуйте, уважаемые подписчики!

СТАТЬЯ 

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

Автор: Борис Гулай aka BoresExpress

Источник: журнал "Программист" №1 за 2002

Исходные тексты примера – 11 KB

Всем памятны обвинения в адрес Microsoft в том, что включение браузера Microsoft Internet Explorer в состав операционной системы Windows недопустимо. Ответом корпорации было то, что браузер является неотъемлемой частью системы. Теперь мы можем сказать даже больше – Internet Explorer как единое приложение не существует. Это набор компонентов, которые собираются в единое целое только при запуске приложения. Сейчас мы попробуем включить в этот стройный ряд компонентов свой, чтобы он тоже стал неотъемлемой частью, ну если не операционной системы, то конкретной копии браузера точно.

Архитектура Internet Explorer

Что мы будем делать?

Что же представляет собой плагин для Internet Explorer? Это обычный внутрипроцессный (In Process) COM-сервер (т.е. DLL-файл), который содержит объект, реализующий как минимум 2 интерфейса: IOleCommandTarget и IObjectWithSite. Кроме того, наш dll-файл должен экспортировать не менее 2 функций: DllGetClassObject и DllCanUnloadNow. Думаю, их назначение всем известно.

Наш плагин будет очень простым. Он будет сохранять все ссылки страницы, которые указывают на файлы с заданными в .ini-файле расширениями в результирующий файл. Такой плагин может быть полезен, например, при создании списков закачиваемых файлов для download-менеджеров. Искать и сохранять ссылки он будет при нажатии на кнопку, которую мы добавим на панель инструментов браузера, или при выборе соответствующего пункта в меню 'Сервис'. А кнопку и пункт меню мы будем делать доступными (enabled) только в том случае, если в браузере открыт файл с расширением .htm или .html (это мы сделаем просто для демонстрации такой возможности).

Как это работает?

Теперь, когда мы определились, что будем писать, самое время узнать, как это будет работать. А работать это будет следующим образом.

Прежде всего, браузер загружает нашу библиотеку, это происходит вместе с загрузкой самого IE. Затем, после первого нажатия на кнопку (!), он вызывает экспортируемую функцию DllGetClassObject и запрашивает у неё указатель на интерфейс IClassFactory. Далее, из полученного интерфейса он вызвает метод CreateInstace и запрашивает у него интерфейс IUnknown. Это должен быть IUnknown компонента, который реализует и IOleCommandTarget и IObjectWithSite.

Два вышеназванных интерфейса должны быть реализованы именно в одном компоненте. Internet Explorer будет запрашивать один через QueryInterface другого. Поэтому реализовать их отдельно нет никакой возможности.

Такое поведение контейнера выглядит логичным, если принять во внимание то, зачем компоненту интерфейс IObjectWithSite. Через его метод SetSite браузер передаёт указатель на интерфейс, через который можно добраться до IWebBrowser – основного интерфейса WebBrowser Control. Это может потребоваться компоненту, при обработке нажатия на кнопку или выбора пункта меню, если он захочет узнать, в каком контексте произошло это событие. Поэтому совершенно логично, что IObjectWithSite должен реализовывать тот же компонент, который обрабатывает нажатие на кнопку.

После того, как произошло первое нажатие на кнопку, Internet Explorer вызывает метод SetSite интерфейса IObjectWithSite и передаёт в него IUnknown объекта, реализующего интерфейс IShellBrowser. Хочу обратить Ваше внимание, что вызов вышеназванного метода происходит только один раз.

Затем, в ответ на нажатие кнопки, вызывается метод IOleCommandTarget::Exec, в котором и происходит обработка события.

После вызова IObjectWithSite::SetSite IE периодически вызывает метод IOleCommandTarget::QueryStatus, где плагин может, при необходимости, изменить статус своей кнопки и пункта меню (enabled/disabled).

При завершении своей работы браузер вызывает IObjectWithSite::SetSite со значением NULL в качестве единственного аргумента, что говорит плагину о необходимости освободить (Release) сохранённый после первого вызова SetSite интерфейс браузера (если он его сохранял, конечно). Затем IE освобождает все интерфейсы плагина и при положительном ответе функции DllCanUnloadNow выгружает плагин.

Так выглядят, в общих чертах, то, что нам придётся запрограммировать.

Как это написать?

После знакомства с механизмом интеграции плагинов в Internet Explorer, мы можем приступать к написанию кода. Я предполагаю, что читатель знаком с основами COM, поэтому не буду описывать создание COM-сервера и добавление в него компонентов. А сразу перейду к самому интересному – реализации методов интерфейсов, которые необходимы плагину для полноценного функционирования.

Следует сразу (пока Вы ещё не успели начать работу) сказать, что метод IObjectWithSite::GetSite в реализации не нуждается (хотя в примере он и реализован), т.к. браузер его никогда не вызывает (он ведь всегда знает, какая страница в нём открыта).

Начнём мы с самого простого, а именно с метода IObjectWithSite::SetSite. Для начала добавим в объявление объекта переменную типа IWebBrowser2Ptr (я предпочитаю использовать то, что в MSDN называется compiler COM support classes; это значительно ускоряет работу). Через эту переменную мы всегда будем иметь доступ ко всем предоставляемым браузером интерфейсам.

Код этого метода выгладит следующим образом:

STDMETHODIMP IMyIEExtention::SetSite(IUnknown *pUnkSite) {

 if (!pUnkSite) {

  if (m_pWebBrowser2.GetInterfacePtr()) m_pWebBrowser2.Release();

  return S_OK;

 }

 IServiceProviderPtr pServProv(pUnkSite);

 return pServProv->QueryService(SID_SWebBrowserApp, IID_IWebBrowser2, (void**)&m_pWebBrowser2);

}

В начале я проверяю, не хочет ли IE сказать мне этим вызовом, что происходит завершение его работы и я должен освободить его интерфейсы. Дальше – интересней. Я запрашиваю интерфейс IWebBrowser2, но не как обычно, через вызов QueryInterface, а посредством вызова метода QueryService, предварительно полученного интерфейса IServiceProvider.

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

Предположим, существует некое приложение-контейнер, которое использует несколько COM-серверов. У каждого из них, естественно, есть доступ к интерфейсам контейнера (посредством IObjectWithSite::SetSite, например). Но вот кому-то из COM-серверов потребовалось получить доступ к интерфейсам другого COM-сервера, также содержащегося в контейнере.

1 ... 125 126 127 128 129 130 131 132 133 ... 156
На этой странице вы можете бесплатно читать книгу Программирование на Visual C++. Архив рассылки - Алекс Jenter бесплатно.
Похожие на Программирование на Visual C++. Архив рассылки - Алекс Jenter книги

Оставить комментарий