Иными словами, приложение содержит один или несколько классов (компонентов), каждый класс реализует один или несколько
интерфейсов, и каждый интерфейс описывает один или несколько методов. Причем каждый класс может входить не более чем в
одно приложение.
Имеется два типа приложений : библиотечные и серверные. Библиотечное оформляется в виде DLL и загружается в адресное
пространство
клиента. Серверное также оформляется в виде DLL, но при его активации запускается суррогатный процесс
(dllhost.exe), в адресное пространство которого и загружается эта DLL. Тип приложения определяется при его создании.
Например, при использовании Component Services задается приписываемый всему приложению атрибут, задающий его тип
активации - библиотечное или серверное приложение.
Классы бывают конфигурированные и неконфигурированные. Конфигурированный класс включен
в некоторое приложение и,
следовательно, ему приписаны атрибуты. Класс, не включенный в приложение, не имеет атрибутов и зарегистрирован только в
реестре системы.
Теперь рассмотрим, как выглядит приложение во время выполнения. Все, что говорилось ранее о процессах, потоках,
апартаментах имеет место и в COM+. Но эта архитектура усложняется введением новых элементов: контекст
и активность.
Начнем с контекста. Каждый объект инкапсулирует данные и методы. Обычно говорят, что данные описывают состояние
объекта. Однако в COM+ данные, инкапсулированные в объекте, не определяют полностью состояние объекта. Эти данные
определяют только ту часть состояния объекта, которая связана с бизнес-логикой приложения. Но конфигурированный объект в
COM+ участвует также в
транзакциях и в других сложных процессах, поддерживаемых сервисами COM+. Часть состояния
объекта, отражающая его требования к среде выполнения и то, как он использует сервисы в данный момент времени, называется
контекстом объекта. Для сохранения контекста объекта используется так называемый объект контекста, который автоматически
формируется при активации объекта и сопровождает объект до его деактивации
. Получить доступ к объекту контекста для
заданного объекта можно вызвав из данного объекта функцию
WINOLEAPI CoGetObjectContext
(
[in] REFIID riid,
[out] LPVOID **ppv
};
Первый параметр задает GUID запрашиваемого интерфейса, реализованного объектом контекста (IID_IObectContext,
IID_IObjectContextInfo, IID_IObjectContextActivity, IID_IContextState
). Во втором параметре возвращается адрес
указателя на запрошенный интерфейс. Используя эти интерфейсы объект может не только узнать свое текущее состояние, но и
изменить его. Рассматривать данные интерфейсы здесь мы не будем, т.к. первоначально необходимо изучить сервисы, для
использования которых эти интерфейсы и разработаны.
Термин контекст используется еще в одном смысле - множество объектов, живущих в одном апартаменте и имеющих одинаковые
требования к среде выполнения. Контекст объекта определяется при его активации и зависит как от атрибутов, приписанных
соответствующему классу, так и от контекста объекта, инициировавшего активацию данного объекта (активатора). Если
активированный объект является экземпляром неконфигурированного класса, то возможны два варианта. Если активированный
объект и его активатор живут в одном апартаменте, то активированный объект помещается в контекст активатора. В противном
случае активированный объект помещается в так называемый контекст по умолчанию своего апартамента. Для объектов,
размещенных в контексте по умолчанию, недоступны никакие сервисы.
Итак, каждый объект в COM+ живет в некотором контексте. Различные контексты не
пересекаются друг с другом и не
пересекают границы апартаментов.
Понятие контекста тесно связано с понятием перехвата. Именно механизм перехвата обеспечивает учет семантики, определенной
при задании атрибутов компонента. Don Box в статье ``Windows 2000 Brings Significant Refinements to the COM(+) Programming
Model'', Microsoft System Journal, May 1999, так описывает схему перехвата
1. Компонент описывает свои требования используя атрибуты.
2. Во время создания объекта система проверяет - выполняется ли активатор (код
, вызвавший CoCreateInstance) в среде,
совместимой с конфигурацией класса ?
3. Если ответ на предыдущий вопрос положителен, то перехват не нужен, и
CoCreateInstance возвращает прямой указатель
на объект.
4. В противном случае CoCreateInstance передает управление среде, совместимой с требованиями класса, создает там объект
и возвращает прокси.
5. Этот прокси обеспечивает совместимость среды выполнения с требованиями класса, выполняя определенные действия до и
после каждого вызова метода.
Фактически понятие перехват появилось даже ранее MTS (Microsoft Transaction Server). В приведенную выше схему полностью
укладывается процесс создания нового экземпляра класса с заданной
потоковой моделью в рамках COM. Вообще, Don Box
называет принцип перехвата краеугольным камнем современного COM программирования.
В COM маршализация указателей на интерфейс требовалась при вызове через границу апартамента. В COM+ такая маршализация
требуется при вызове через границу контекста. В соответствии с принципом перехвата только в рамках одного контекста можно
использовать прямые указатели на интерфейс.
Как и
в COM маршализация и демаршализация указателей на интерфейс выполняется автоматически при создании, активации
объекта и при вызове функций, возвращающих указатели на интерфейс. В остальных случаях, для получения указателя на
интерфейс объекта из другого контекста необходимо явным образом выполнить процедуры маршализации и демаршализации
указателя на интерфейс. Для этого можно использовать функции
CoMarshalInterface и CoUnmarshalInterface. Для некоторой
оптимизации этого процесса можно проектировать объекты с FTM и использовать GIT, как это было в COM.