Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Роджерсон Д. - Основы COM - 2000.pdf
Скачиваний:
412
Добавлен:
13.08.2013
Размер:
2.4 Mб
Скачать

82

Сравнение GUID

Для сравнения GUID в OBJBASE.H определен operator==:

inline BOOL operator ==(const GUID& guid1, const GUID& guid2)

{

return !memcmp(&guid1, &guid2, sizeof(GUID));

}

Нам уже приходилось использовать эту операцию в QueryInterface. Если Вы не любите упрятывать истинный код во внешние простенькие операторы, OBJBASE.H дает определения эквивалентных по смыслу функций

IsEqualGUID, IsEqualIID и IsEqualCLSID.

Использование GUID в качестве идентификаторов компонентов

Помимо уникальной идентификации интерфейсов, GUID используется и для уникальной идентификации компонентов. В гл. 5 мы определили для создания компонентов функцию CallCreateInstance. Параметром этой функции служит строка с именем DLL, в которой содержится компонент:

IUnknown* CallCreateInstance(char* name);

В следующей главе мы заменим эту функцию на функцию библиотеки СОМ CoCreateInstance. Последняя использует для идентификации компонента не строку, а GUID. Такой GUID в СОМ называется идентификатором класса. Чтобы отличать идентификаторы классов от IID, для них используют тип CLSID.

Передача GUID по ссылке

Поскольку размер GUID 16 байтов, мы будем передавать их не по значению, а по ссылке. Именно поэтому параметром QueryInterface является ссылка на константу. Если для Вас утомительно все время писать

const IID&

можете использовать эквивалентное выражение REFID. Точно так же для передачи идентификаторов классов можно использовать REFCLSID, а для передачи GUID — REFGUID.

Теперь давайте рассмотрим, как компоненты регистрируются в системе (чтобы клиенты смогли их найти и использовать).

Реестр Windows

FAA ведет реестр всех летательных аппаратов, включая самодельные. По этому реестру можно определить, кто хозяин самолета. В этой главе мы рассмотрим чем-то похожий реестр, позволяющий определить, какой DLL принадлежит данный компонент.

Вгл. 5 при создании компонента мы передавали функции CallCreateInstance имя файла соответствующей DLL. В следующей главе мы собираемся заменить CallCreateInstance функцией библиотеки СОМ CoCreateInstance. Для идентификации компонента CoCreateInstance вместо имени файла использует CLSID (по нему определяется имя файла DLL). Компоненты помещают имена своих файлов, индексированные CLSID, в Реестр Windows. CoCreateInstance отыскивает имя файла, используя CLSID как ключ.

Вреальной жизни реестр — это учетная книга для записи предметов, имен или действий. В Windows реестр — это общедоступная база данных операционной системы. Реестр содержит информацию об аппаратном и программном обеспечении, о конфигурации компьютера и о пользователях. Любая программа для Windows может добавлять и считывать информацию из Реестра; клиенты могут искать там нужные компоненты. Но прежде чем поместить свою информацию в Реестр, надо узнать, как он устроен.

Организация Реестра

Реестр имеет иерархическую структуру. Каждый ее элемент называется разделом (key). Раздел может включать в себя набор подразделов, набор именованных параметров и/или один безымянный параметр — параметр по умолчанию (default value). Подразделы, но не параметры, могут содержать другие подразделы и параметры. Параметры могут быть разного типа, но чаще всего мы будем записывать в Реестр строки. Структура Реестра показана на рис. 6-3.

Редактор Реестра

Реестр содержит очень много информации. По счастью, нас интересует лишь малое подмножество. Лучше всего изучать Реестр, запустив Редактор Реестра — Windows-программу, позволяющую просматривать и редактировать

83

записи. Эта программа называется REGEDT32.EXE в Windows NT и REGEDIT.EXE в Windows 95*. Одно предостережение: редактируя Реестр, чрезвычайно легко повредить систему, так что будьте осторожны.

Корень

Именованный

параметр

Именованный

параметр

Раздел

Параметр по

умолчанию

 

 

 

 

Именованный

 

 

параметр

 

 

Раздел

Параметр по

 

умолчанию

 

 

Раздел

Именованный

параметр

Раздел

Параметр по

умолчанию

 

Раздел

Рис. 6-3 Структура Реестра Windows

Необходимый минимум

СОМ использует только одну ветвь дерева данных Реестра: HKEY_CLASSES_ROOT. Ниже HKEY_CLASSES_ROOT отыщите раздел CLSID. В этом разделе перечислены CLSID всех компонентов, установленных в системе. CLSID хранится в Реестре как строка формата {xxxxxxxx-xxxx-xxxx-xxxx- xxxxxxxxxxxx}. Искать CLSID в Реестре — занятие не слишком привлекательное. Поэтому в каждом разделе CLSID параметр по умолчанию задает «дружественное» имя компонента.

Пока в разделе каждого CLSID нас интересует только один подраздел — InprocServer32. Его параметр по умолчанию — имя файла DLL. Название InprocServer32 используется потому, что DLL — это сервер в процессе (in-proc); она загружается в процесс клиента и предоставляет ему сервисы. На рис. 6-4 показан пример ветви CLSID Реестра.

Как видно из рисунка, в разделе Реестра HKEY_CLASSES_ROOT\CLSID хранится CLSID компонента Tail Rotor Simulator. Дружественное имя зарегистрировано как параметр по умолчанию для CLSID компонента. Подраздел

InprocServer32 содержит имя файла DLL — C:\Helicopter\TailRotor.dll.

Имя файла и CLSID — две наиболее важные составляющие данных Реестра. Для многих компонентов СОМ ничего больше и не потребуется. Однако в некоторых случаях нужна дополнительная информация.

Другие детали Реестра

Давайте совершим краткую экскурсию по подразделам HKEY_CLASSES_ROOT. Мы уже знакомы с CLSID, и далее мы рассмотрим, какая дополнительная информация для классов хранится в этом подразделе. В начале HKEY_CLASSES_ROOT Вы можете видеть группу расширений имен файлов, зарегистрированных разными программами. После расширений следует множество других имен. По большей части это так называемые ProgID

что расшифровывается как программный идентификатор (program identifier). Мы поговорим о ProgID немного ниже. Некоторые из имен — не ProgID, а специальные разделы реестра, похожие на CLSID. Эти разделы связывают GUID с некоторыми другими данными, например, именами файлов. Такие разделы перечислены ниже.

!" AppID — Подразделы данного раздела связывают APPID (application identifier — идентификатор приложения) с именем удаленного сервера. Этот раздел использует DCOM и будет обсуждаться в гл. 10.

* В Windows NT 4.0 также имеется программа REGEDIT.EXE — Прим. перев.

84

!" Component Categories — Эта ветвь Реестра связывает CATID (component category ID — идентификатор категории компонентов) с соответствующей категорией. Категории компонентов рассматриваются ниже.

!" Interface — Данный раздел связывает IID с информацией, специфичной для интерфейса. Эта информация нужна в основном для доступа к интерфейсу «через границы» процессов. Мы рассмотрим этот раздел в гл. 10.

!" Licenses — Раздел Licenses хранит лицензии на право использования компонентов СОМ. В этой книге лицензии рассматриваться не будут.

!" TypeLib — Помимо других данных, библиотеки типа содержат информацию о параметрах функцийчленов интерфейсов. Этот раздел связывает LIBID с именем файла, в котором хранится библиотека типа. Библиотеки типов будут обсуждаться в гл. 11.

Мой компьютер

HKEY_CLASSES_ROOT

Первыми перечислены зарегистрированные расширения имен файлов

CLSID

Дружественное имя компонента

{00000300-0000-0000-C000-000000000046}

StdOleLink

InprocServer32

 

ole32.dll

 

Местоположение компонента

 

Дружественное имя компонента

{166769E1-88E8-11CF-A6BB-0080C7B2D682}

Tail Rotor Simulator

InprocServer32

C:\Helicopter\TailRotor.dll

Местоположение компонента

Рис. 6-4 Структура подраздела CLSID Реестра

ProgID

Теперь рассмотрим ProgID более подробно. Большая часть подразделов в ветви Реестра HKEY_CLASSES_ROOT

— это ProgID. ProgID отображает «дружественную», понятную программисту строку в CLSID. Некоторые языки программирования, такие как Visual Basic, идентифицируют компоненты по ProgID, а не по CLSID. Уникальность ProgID не гарантируется, поэтому существует принципиальная опасность конфликта имен. Однако с ProgID легче работать. (Кроме того, некоторые языки программирования не поддерживают структур, и в них пришлось бы использовать строковое представление GUID.)

Соглашение об именовании ProgID

По соглашению ProgID имеет следующий формат:

<Программа>.<Компонент>.<Версия>

Вот несколько примеров из Реестра:

Visio.Application.3

Visio.Drawing.4

RealAudio.ReadAudio ActiveX Control (32-bit).1

Office.Binder.95

MSDEV.APPLICATION

JuiceComponent.RareCat.1

Но этот формат — лишь соглашение, а не жесткое правило, и в Реестре на моей машине полно компонентов, которые ему не следуют.

Во многих случаях клиента не интересует версия компонента, к которой он подключается. Таким образом, у компонента часто имеется ProgID, не зависящий от версии. Этот ProgID связывается с самой последней версией компонента из установленных в системе. Соглашение об именовании не зависящих от версии ProgID сводится к отбрасыванию номера версии. Пример такого ProgID, следующего соглашению, — MSDEV.APPLICATION.

85

ProgID в Реестре

ProgID и не зависящий от версии ProgID компонента приводятся в разделе CLSID. Однако основное назначение ProgID — обеспечить получение соответсвующего CLSID. Просматривать все разделы CLSID для поиска ProgID было бы неэффективно. В связи с этим ProgID указывается непосредственно и в разделе HKEY_CLASSES_ROOT. ProgID не предназначены для представления конечным пользователям, поэтому по умолчанию значение любого раздела ProgID — дружественное для пользователя имя. В разделе ProgID имеется подраздел с именем CLSID, который содержит CLSID компонента в качестве значения по умолчанию. Не зависящий от версии ProgID также приводится непосредственно в разделе HKEY_CLASSES_ROOT. У него есть дополнительный подраздел CurVer, содержащий ProgID текущей версии компонента.

На рис. 6-5 представлен расширенный пример с рис. 6-4, включающий ProgID. В раздел CLSID компонента добавлен раздел с именем ProgID, и в него помещено значение Helicopter.TailRotor.1 — ProgID компонента. Не зависящий от версии ProgID сохранен в разделе VersionIndependentProgID. В данном примере не зависящий от версии ProgID — Helicopter.TailRotor.

HKEY_CLASSES_ROOT

CLSID

{166769E1-88E8-11CF-A6BB-0080C7B2D682} Модель хвостового винта

InprocServer32 C:\Helicopter\TailRotor.dll

ProgID Helicopter.TailRotor.1

Не зависящий от

VesionIndependentProgID

Helicopter.TailRotor

версии ProgID

Helicopter.TailRotor

 

Модель хвостового винта

 

CLSID

{166769E1-88E8-11CF-A6BB-0080C7B2D682}

 

CurVer

 

Helicopter.TailRotor.1

Helicopter.TailRotor.1

 

Модель хвостового винта

ProgID

CLSID

{166769E1-88E8-11CF-A6BB-0080C7B2D682}

Рис. 6-5 Организация разделов Реестра, в которых содержится информация, имеющая отношение к ProgID

На рисунке также показаны отдельные разделы Helicopter.TailRotor и Helicopter.TailRotor.1, расположенные непосредственно в HKEY_CLASSES_ROOT. В разделе Helicopter.TailRotor.1 имеется единственный подраздел — CLSID, который содержит CLSID компонента. Не зависящий от версии ProgID Helicopter.TailRotor содержит подразделы CLSID и CurVer. Значение по умолчанию подраздела CurVer — ProgID текущей версии компонента,

Helicopter.TailRotor.1.

От ProgID к CLSID

После того, как Вы поместили в Реестр нужную информацию, получить CLSID по ProgID и наоборот легко. Библиотека СОМ предоставляет две функции — CLSIDFromProgID и ProgIDFromCLSID, — которые производят необходимые манипуляции с Реестром:

CLSID clsid;

CLSIDFromProgID(“Helicopter.TailRotor”, &clsid);

Саморегистрация

Каким образом информация о компоненте попадает в Реестр Windows? Так как DLL знает о содержащемся в ней компоненте, она может поместить эту информацию в Реестр. Но, поскольку DLL ничего не делает сама по себе, Вам следует экспортировать следующие две функции:

STDAPI DllRegisterServer();

STDAPI DllUnregisterServer();

STDAPI определен в OBJBASE.H как

Соседние файлы в предмете Программирование на C++