Напротив, флаг REGCLS_MULTIPLEUSE показывает, что объект класса может быть использован многократно, до тех пор, пока вызов функции CoRevokeСlassObject не удалит его элемент из таблицы класса библиотеки COM. Флаг REGCLS_MULTI_SEPARATE адресует последующие внутрипроцессные активационные запросы, которые могут произойти в процессе вызывающего объекта. Если вызывающий объект регистрирует объект класса с флагом REGCLS_MULTIPLEUSE , то COM допускает, что любые внутрипроцессные активационные запросы от процесса вызывающего объекта не будут загружать отдельный внутрипроцессный сервер, а будут вместо этого использовать зарегистрированный объект класса. Это означает, что даже если вызывающая программа только зарегистрировала объект класса с флагом CLSCTX_LOCAL_SERVER , то для удовлетворения внутрипроцессных запросов от того же процесса будет использован зарегистрированный объект класса. Если такое поведение неприемлемо, вызывающая программа может зарегистрировать объект класса, используя флаг REGCLS_MULTI_SEPARATE . Флаг инструктирует COM использовать зарегистрированный объект класса для внутрипроцессных запросов только в случае, если для регистрации этого класса был использован флаг CLSCTX_INPROC_SERVER . Это означает, что следующий вызов CoRegisterClassObject :
hr = CoRegisterClassObject(CLSID_Me, &g_coMe, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dw);
эквивалентен следующему:
hr = CoRegisterClassObject(CLSID_Me, &g_coMe, CLSCTX_LOCAL_SERVER | CLSCTX_INPROC, REGCLS_MULTI_SEPARATE, &dw);
В любом случае, если бы из процесса вызывающего объекта был осуществлен такой вызов:
hr = CoGetClassObject(CLSID_Me, CLSCTX_INPROC, 0, IID_IUnknown, (void**)&pUnkCO);
то никакая DLL не была бы загружена. Вместо этого COM удовлетворила бы запрос, используя объект класса, зарегистрированный посредством CoRegisterClassObject . Если, однако, серверный процесс вызвал CoRegisterClassObject таким образом:
hr = CoRegisterClassObject(CLSID_Me, &g_coMe, CLSCTX_LOCAL_SERVER, REGCLS_MULTI_SEPARATE, &dw);
то любые внутрипроцессные запросы на активацию CLSID_Me , исходящие изнутри серверного процесса, заставят DLL загрузиться.
CoRegisterClassObject связывает зарегистрированный объект класса с апартаментом вызывающего объекта. Это означает, что все поступающие запросы методов будут выполняться в апартаменте вызывающей программы. В частности, это означает, что если объект класса экспортирует интерфейс IClassFactory , то метод CreateInstance будет выполняться в апартаменте вызывающей программы. Результаты метода CreateInstance будут маршалированы из апартамента объекта класса, а это, в свою очередь, означает, что экземпляры класса будут принадлежать к тому же апартаменту, что и объект класса [3].
Серверные процессы могут регистрировать объекты класса для более чем одного класса. Если объекты класса зарегистрированы для выполнения в МТА процесса, то это означает, что поступающие запросы на активацию могут быть обслужены, как только будет завершен первый вызов CoRegisterClassObject . Во многих серверных процессах, основанных на МТА, это может вызвать проблемы, так как бывает, что процесс должен выполнить дальнейшую инициализацию. Чтобы избежать этой проблемы, в реализации COM под Windows NT 4.0 введен флаг REGCLS_SUSPENDED . При добавлении этого флага в вызов CoRegisterСlassObject библиотека COM не извещает SCM о том, что класс доступен. Это предотвращает поступление в серверный процесс входящих активационных запросов. Библиотека COM связывает CLSID с объектом класса; однако она помечает этот элемент в таблице библиотеки класса как отложенный. Для снятия этой пометки в COM предусмотрена API-функция CoResumeClassObjects :
HRESULT CoResumeClassObjects(void);
CoResumeClassObjects делает следующее. Во-первых, она помечает все отложенные объекты класса как легальные для использования. Во-вторых, она посылает SCM единственное сообщение, информируя его, что все ранее отложенные объекты класса теперь являются доступными в серверном процессе. Это сообщение обладает огромной силой, так как при его получении обновляется таблица класса SCM по всей машине и сразу для всех классов, зарегистрированных вызывающим объектом.
Получив три только что описанные API-функции, легко создать серверный процесс, экспортирующий один или более классов. Ниже приводится простая программа, которая экспортирует три класса из МТА сервера:
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
// define a singleton class object for each class
// определяем синглетон для каждого класса
static GorillaClass s_gorillaClass; static OrangutanClass s_orangutanClass;
static ChimpClass s_chimpClass; DWORD rgdwReg[3];
const DWORD dwRegCls = REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED;
const DWORD dwClsCtx = CLSCTX_LOCAL_SERVER;
// enter the MTA
Читать дальше