Сущность технологии СОМ. Библиотека программиста
Шрифт:
Чтобы дать возможность разработчику новой версии класса прозрачно удовлетворять запросы на активацию для других CLSID , в СОМ введено понятие эмуляции классов (class emulation). Эмуляция классов позволяет разработчику компонента указать, что старый CLSID заменен новым, альтернативным CLSID, эмулирующим семантику исходного класса. Это позволяет прежним клиентам, делающим запросы на активацию с использованием прежнего CLSID, получать экземпляры нового усовершенствованного класса. Для индикации того, что у класса имеется новая альтернативная версия, в СОМ существует такая API-функция:
HRESULT CoTreatAsClass([in] REFCLSID rclsidOld, [in] REFCLSID rclsidNew);
Пусть Сhimp2
// cause Chimp activation calls to activate Chimp2
// заставим запросы на активацию Chimp активизировать Chimp2
HRESULT hr = CoTreatAsClass(CLSID_Chimp, CLSID_Chimp2);
Эта API-функция добавляет следующий ключ реестра (registry key)
[HKCR\CLSID\{CLSID_Chimp}\TreatAs] [1] @={CLSID_Chimp2}
Вызов CoTreatAsClass c CLSID_NULL в качестве второго параметра удаляет настройку TreatAs:
// cause Chimp activation calls to activate Chimps
1 Отметим, что CLSID_Chimp и CLSID_Chimp2 являются сокращенной записью канонической формы фактических GUID, состоящих из 32 знаков.
// заставим запросы на активацию Chimp
// активизировать Chimps
HRESULT hr = CoTreatAsClass(CLSID_Chimp, CLSID_NULL);
Этот запрос восстанавливает исходную реализацию класса в состояние, предшествующее эмуляции. Клиенты могут запросить установку эмуляции данного класса, используя API-функцию CoGetTreatAsClass:
HRESULT CoGetTreatAsClass ([in] REFCLSID rclsidOld, [out] REFCLSID *pclsidNew);
Если запрошенный класс эмулируется другим классом, то CLSID эмулирующего класса будет возвращен посредством второго параметра и вся подпрограмма возвратит S_OK . Если же запрошенный класс не эмулируется другим классом, то посредством второго параметра будет возвращен исходный CLSID и подпрограмма возвратит S_FALSE. Необходимо также отметить, что в момент написания этой книги эмуляция классов не работает должным образом для удаленных запросов на активацию.
Категории компонентов
Как подчеркивалось в этой главе, основные примитивы активации СОМ требуют, чтобы вызывающей программе при создании новых экземпляров класса было известно его точное имя. Иногда, однако, бывает полезно просто потребовать, чтобы подходящим являлся любой класс, удовлетворяющий некоторым семантическим ограничениям. Кроме того, прежде чем сделать запрос на активацию, было бы полезно знать, какие сервисные средства класс требует от своих клиентов. В этом случае не будут создаваться объекты, которые клиент не готов должным образом поддерживать. Эти проблемы послужили причиной для создания категорий компонентов (component categories).
СОМ дает разработчикам возможность группировать родственные СОМ-классы в логические группы, или категории компонентов. Чаще всего все классы внутри категории будут реализовывать один и тот же набор интерфейсов. В то же время простое разделение пространства классов на части по признаку, какие интерфейсы какой класс реализует, не обеспечивает должного уровня модульности для многих приложений. Категории компонентов выступают как метаинформация, показывающая, какие классы совместимы с определенными семантическими ограничениями.
Категория компонентов есть группа логически родственных СОМ-классов, которые разделяют общий ID
[HKCR\CLSID\{CLSID_Chimp}\Implemented Categories\{CATID_Mammals}]
[HKCR\CLSID\{CLSID_Chimp}\Implemented Categories\{CATID_Simians}]
Эти элементы реестра обычно добавляются во время саморегистрации. Каждая известная категория компонентов в системе имеет запись в разделе реестра HKEY_CLASSES_ROOT\Component Categories
Каждая категория имеет свой собственный уникальный подключ, названный как CATID. Под этим подключом каждая категория имеет одну или более именованных величин, содержащих текстовое описание этой категории. Например, двум показанным выше категориям понадобятся такие элементы реестра:
[HKCR\Component Categories\{CATID_Mammals}] 409="Bears live young"
[HKCR\Component Categones\{CATID_Simians}] 409="Eats Bananas"
Отметим, что в этом примере используется величина 409, являющаяся кодом локализации, или локальным идентификатором языка LCID (locale identifier), для U.S.English. Другая местная специфика может поддерживаться путем добавления дополнительных именованных величин.
Классы также могут указать, что они требуют от клиента функциональное назначение определенного типа. Обычно такая поддержка принимает вид узловых интерфейсов (site interfaces), которые клиент предоставляет активированному объекту. Для того, чтобы разделить эти предоставляемые клиентом сервисы на категории, не зависящие от отдельного интерфейса, СОМ позволяет классам объявлять второй тип категорий ID; он может использоваться клиентами для гарантии того, что они не активировали компонент, который не могут должным образом принять. Рассмотрим следующие две категории сервисов, предоставляемых клиентом: CATID_HasOxygen и CATID_HasWater. Поскольку для выживания шимпанзе необходимы кислород и вода, разработчик Chimp должен объявить, что эти две категории сервисов, предоставляемых клиентом, необходимы для активации. Это делается с помощью подключей из Required Categories:
[HKCR\CLSID\{CLSID_Chimp}\Required Categories\{CATID_HasOxygen}]
[HKCR\CLSID\{CLSID_Chimp}\Required Categories\{CATID_HasWater}]
Кроме того, ID этих двух категорий следует внести в реестр под ключом HKEY_CLASSES_ROOT\Component Categories
Получив эти записи, сам клиент перед активацией должен убедиться в том, что он удовлетворяет запрошенным категориям. СОМ не обеспечивает согласование с клиентом.
Элементы категорий компонентов могут быть зарегистрированы либо с помощью явных функций реестра, либо с использованием предлагаемого СОМ менеджера категорий компонентов (component category manager). Этот менеджер категорий компонентов объявляется в СОМ как создаваемый СОМ-класс (CLSID_StdComponentCategoriesMgr), который реализует интерфейс ICatRegister для регистрации информации о категории и интерфейс ICatInformation для запроса информации о категории. Интерфейс ICatRegister позволяет библиотекам DLL сервера легко добавлять в реестр необходимые элементы: