Выбрать главу

Другая возможная ловушка при выполнении клиентского процесса состоит в совместном использовании контекста защиты. Когда клиент активизирует объект внутри процесса, методы объекта выполняются с использованием мандата (credential ) защиты клиента. Это означает, что объекты, созданные привилегированными пользователями, могут нанести значительные повреждения. Кроме того, это означает, что объекты, созданные клиентами с относительно меньшей степенью доверия, могут не получить достаточных привилегий для доступа к ресурсам, необходимым для корректного функционирования объекта. К сожалению, нет простого способа обеспечения внутрипроцессного объекта его собственным контекстом защиты.

Еще один подводный камень при внутрипроцессной активации состоит в том, что она не позволяет производить распределенные вычисления. Если объект должен быть активирован в адресном пространстве клиента, то по определению он разделит CPU (central processor unit – центральный процессор) и другие локальные ресурсы с клиентом. Внутрипроцессная активация также делает затруднительным совместное использование одного и того же объекта несколькими клиентскими процессами. Хотя понятие апартамента и допускает экспорт объектных ссылок из любого процесса (включая и те процессы, которые по традиции рассматривались как клиентские), тем не менее, трудно представить себе семантику активации для совместного использования внутрипроцессного экземпляра.

Для решения этих проблем COM допускает активацию классов в отдельных процессах. При активации в отдельном процессе каждый класс (или группа классов) может иметь свой отдельный контекст защиты. Это означает, что разработчик класса сам контролирует, каким пользователям позволено связываться с его объектами. Кроме того, разработчик класса контролирует, какой набор мандатов защиты должен использовать процесс. В зависимости от фактической упаковки класса разработчик класса также управляет тем, когда окружающий процесс закончится (и закончится ли вообще). Наконец, активация класса в отдельном процессе обеспечивает уровень изоляции ошибок, достаточный для изоляции клиента и объектов от завершения в результате ошибок друг друга.

Активация и SCM

Диспетчер управления COM-сервисами (Service Control Manager – SCM ) обеспечивает связь между CLSID и серверными процессами в реестре. Это позволяет SCM запускать серверный процесс при поступлении клиентских запросов на активацию. Если предположить, что код для класса будет упакован как образ процесса (ЕХЕ), а не как DLL, то достаточно использовать ключ реестра LocalServer32 вместо InprocServer32, как показано в следующем примере:

[HKCR\CLSID\{27EE6A26-DF65-11d0-8C5F-0080C73925BA}] @="Gorillaquot;

[HKCR\CLSID\{27EE6A26-DF65-11d0-8C5F-0080C73925BA}\LocalServer32] @="C:\ServerOfTheApes.exe"

Ожидается, что внепроцессный сервер установит эти ключи во время самоинсталляции. В отличие от своих внутрипроцессных аналогов, внепроцессные серверы не экспортируют известные библиотеки DllRegisterServer и DllUnregisterServer. Вместо этого внепроцессный сервер должен проверить командную строку на наличие известных ключей /RegServer и /UnregServer[1]. Имея вышеуказанные элементы реестра, SCM начнет новый серверный процесс с использованием файла ServerOfTheApes.ехе, при первом запросе на активацию класса Gorilla. После этого извещение SCM о том, какие классы фактически являются доступными из нового процесса, будет обязанностью серверного процесса.

Как уже рассматривалось в главе 3, процессы могут контактировать с SCM для связывания ссылок на объекты класса, экземпляров класса и постоянных экземпляров. Для осуществления этого в COM предусмотрены три функции активации (CoGetClassObject, CoCreateInstanceEx и CoGetInstanceFromFile). Они, как и высокоуровневые моникеры, предназначены для того, чтобы скрыть детали реализации каждой стратегии связывания. В каждой из этих трех стратегий активации для вызова объекта к жизни используется объект класса. Как уже рассматривалось в главе 3, когда активация объекта осуществляется внутри процесса, DLL класса загружается самой COM, а для выборки соответствующих объектов класса используется известная точка входа DllGetClassObject. Однако пока не рассматривалось, как объекты могут быть активированы через границы процессов.

Процесс становится серверным процессом для определенного класса после явной саморегистрации с помощью SCM. После такой регистрации любые активационные запросы класса, для которых необходима внепроцессная активация, будут отосланы к зарегистрированному серверному процессу[2]. Серверные процессы саморегистрируются с помощью SCM API-функции CoRegisterClassObject:

HRESULT CoRegisterClassObject(

[in] REFCLSID rclsid,

// which class?

// какой класс?

[in] IUnknown *pUnkClassObject,

// ptr to class object

// указатель на объект класса

[in] DWORD dwClsCtx,

// locality

// локализация

[in] DWORD dwRegCls,

// activation flags

// флаги активации

[out] DWORD *pdwReg);

// association ID

// ID связи

При вызове CoRegisterClassObject библиотека COM сохраняет ссылку на объект класса, указанную в качестве второго параметра, и связывает объект класса с его CLSID в организованной внутри библиотеки таблице. В зависимости от флагов активации, использованных при вызове, библиотека COM может также сообщать локальному SCM, что вызывающий процесс является теперь серверным процессом для указанного класса. CoRegisterClassObject возвращает двойное слово (DWORD), которое представляет связь между CLSID и объектом класса. Это двойное слово можно использовать для завершения связи (а также для извещения SCM о том, что вызывающий процесс более не является серверным процессом для данного CLSID) путем вызова API-функции CoRevokeClassObject:

HRESULT CoRevokeClassObject([in] DWORD dwReg);

// association ID

// ID связи

Два параметра типа DWORD являются примером тонкого устройства CoRegisterClassObject . Эти параметры дают вызывающему объекту контроль над тем, как и когда объект класса является доступным.

А каким образом и на какой срок сделать доступным объект класса, вызывающему объекту позволяют решить флаги активации, передающиеся CoRegisterСlassObject в качестве четвертого параметра. COM предусматривает следующие константы для использования в этом параметре:

вернуться

1 Хорошо реализованные серверы проверяют также наличие –RegServer и –UnregServer . Все четыре ключа не зависят от регистра (case).

вернуться

2 В зависимости от того, как класс сконфигурирован в локальном регистре, регистрация серверного процесса может обратиться ко всем клиентским процессам или только к тем клиентским процессам, которые выполняются с тем же мандатом защиты и/или с той же windows-станцией.