Когда объект активирован извне процесса (то есть в другом процессе на локальной или удаленной машине), то код, реализующий методы объекта, выполняется в процессе определенного сервера и все данные-члены объекта сохраняются в адресном пространстве процесса сервера. Чтобы позволить клиенту связываться с внепроцессным (out-of-process
) объектом, СОМ прозрачно (скрытно от клиента) возвращает ему «заместитель» (proxy ) во время активации. В главе 5 подробно обсуждается, что этот «заместитель» выполняется в клиентском потоке и переводит вызовы метода, преобразованные в RPC-запросы (Remote Procedure Call – удаленный вызов процедуры), в контекст исполнения сервера, где эти RPC-запросы затем преобразуются обратно в вызовы метода текущего объекта. Это делает вызов метода менее эффективным, так как при каждом обращении к объекту требуются переключение потока и переключение процесса. К преимуществам внепроцессной (то есть работающей не в клиентском процессе) активации относятся изоляция ошибок, распределение и повышенная безопасность. В главе 6 внепроцессная активация будет рассматриваться подробно.
Использование SCM
Напомним, что SCM поддерживает три примитива активации (связывание с объектами класса, связывание с экземплярами класса, связывание с постоянными экземплярами из файлов). Как показано на рис. 3.2, эти примитивы логически разделены на уровни[1]
. Примитивом нижнего уровня является связывание с объектом класса. Этот примитив также наиболее прост для понимания.Вместо того чтобы вручную загружать код класса, клиенты пользуются услугами SCM посредством низкоуровневой API-функции СОМ CoGetClassObject
. Эта функция запрашивает SCM присвоить значение указателю на требуемый объект класса:
HRESULT CoGetClassObject(
[in] REFCLSID rclsid,
// which class object?
// Какой объект класса?
[in] DWORD dwClsCtx,
// locality?
//местонахождение?
[in] COSERVERINFO *pcsi,
// host/security info
//сведения о сервере и обеспечении безопасности
[in] REFIID riid,
// which interface?
// какой интерфейс?
[out, iidis(riid)] void **ppv);
// put it here
!// поместим его здесь!
Первый параметр в CoGetClassObject
показывает, какой класс реализации запрашивается. Последний параметр – это ссылка на указатель интерфейса, с которым нужно связаться, а четвертый параметр – это просто IID , описывающий тип указателя интерфейса, на который ссылается последний параметр. Более интересные параметры – второй и третий, которые определяют, когда объект класса должен быть активирован.В качестве второго параметра CoGetClassObject
принимает битовую маску (bitmask), которая позволяет клиенту указать характеристики скрытого и живучего состояний объекта (например, будет ли объект запущен в процессе, вне процесса или вообще на другом сервере). Допустимые значения для этой битовой маски определены в стандартном перечислении CLSCTX:
enum tagCLSCTX { CLSCTXINPROC
SERVER = 0х1,// run -inprocess
// запуск в процесс
CLSCTXINPROC
HANDLER = 0х2,// see note[2]
// смотрите сноску[2]
CLSCTXLOCAL
SERVER = 0х4,// run out-of-process
// запуск вне процесса
CLSCTXREMOTE
SERVER = 0х10// run off-host
// запуск вне хост-машины
} CLSCTX;
Эти флаги могут быть подвергнуты побитному логическому сложению (bit-wise-ORed together), и в случае, когда доступен более чем один запрошенный CLSCTX
, СОМ выберет наиболее эффективный тип сервера (это означает, что СОМ будет, когда это возможно, использовать наименее значимый бит битовой маски). Заголовочные файлы SDK также включают в себя несколько сокращенных макросов, которые сочетают несколько флагов CLSCTX , используемых во многих обычных сценариях:
#define CLSCTXINPROC (CLSCTX
INPROCSERVER | \ CLSCTX
INPROCHANDLER) #define CLSCTX
SERVER (CLSCTXINPROCSERVER |\ CLSCTXLOCAL
SERVER |\ CLSCTXREMOTE
SERVER)#define CLSCTXALL (CLSCTX
INPROCSERVER | \ CLSCTX
INPROCHANDLER | \ CLSCTX
LOCALSERVER | \ CLSCTX
REMOTESERVER)
Заметим, что такие среды, как Visual Basic и Java, всегда используют CLSCTXALL
, показывая тем самым, что подойдет любая доступная реализация.Третий параметр CoGetClassObject
– это указатель на структуру, содержащую информацию об удаленном доступе и безопасности. Эта структура имеет тип COSERVERINFO и позволяет клиентам явно указывать, какой машине следует активировать объект, а также как конфигурировать установки обеспечения безопасности, используемые при создании запроса на активацию объекта:
typedef struct COSERVERINFO
{
DWORD dwReserved1;
// reserved
, must be zero// зарезервировано, должен быть нуль
LPWSTR pwszName;
// desired host name, or null
// желаемое имя хост-машины или нуль
COAUTHINFO *pAuthInfo;
// desired security settings
// желаемые установки безопасности DWORD dwReserved2;
// reserved, must be zero