Сущность технологии СОМ. Библиотека программиста

ОглавлениеДобавить в закладки К обложке

ULONG CoAddRefServerProcess(void);

ULONG CoReleaseServerProcess(void);

Эти две подпрограммы управляют счетчиком блокировок модуля от имени вызывающего объекта. Эти подпрограммы временно блокируют любой доступ к библиотеке COM, чтобы гарантировать, что во время установки счетчика блокировок новые активационные запросы не будут обслуживаться. Кроме того, если функция CoReleaseServerProcess обнаружит, что удаляется последняя блокировка в процессе, то она изнутри пометит все объекты класса в процессе как приостановленные и сообщит SCM, что процесс более не является сервером для его CLSID.

Следующие подпрограммы корректно реализуют время жизни сервера во внепроцессном сервере:

void LockModule(void) {

CoAddRefServerProcess();

// COM maintains lock count

// COM устанавливает счетчик блокировок

}

void UnlockModule(void) {

if (CoReleaseServerProcess() == 0) SetEvent(g_heventShutdown);

}

Отметим, что прекращение работы процесса в должном порядке по-прежнему остается обязанностью вызывающей программы. Однако после принятия решения о прекращении работы ни один новый активационный запрос не будет обслужен этим процессом.

Даже при использовании функций CoAddRefServerProcess / CoReleaseServerProcess все еще остаются возможности для гонки. Возможно, что во время выполнения CoReleaseServerProcess на уровне RPC будет получен входящий запрос на активацию от SCM. Если вызов от SCM диспетчеризован после того, как функция CoReleaseServerProcess снимает свою блокировку библиотеки COM, то активационный запрос отметит, что объект класса уже помечен как приостановленный, и в SCM будет возвращено сообщение об ошибке со специфическим кодом (CO_E_SERVER_STOPPING). Когда SCM обнаруживает этот специфический код, он просто запускает новый экземпляр серверного процесса и повторяет запрос, как только новый серверный процесс зарегистрирует себя. Несмотря на системы защиты, используемые библиотекой COM, остается вероятность того, что поступающий активационный запрос будет выполняться одновременно с заключительным вызовом функции CoReleaseServerProcess. Чтобы избежать этого, сервер может явно возвратить CO_E_SERVER_STOPPING как из IClassFactory::Create Instance, так и из IPersistFile::Load в том случае, если он определит, что по окончании запроса на прекращение работы был сделан еще какой-то запрос. Следующий код демонстрирует этот способ:

STDMETHODIMP MyClassObject::CreateInstance(IUnknown *puo, REFIID riid, void **ppv) {

LockModule();

// ensure we don't shut down while in call

// убеждаемся в том, что не прекращаем работу

// во время вызова HRESULT hr;

*ppv = 0;

// shutdown initiated?

// процесс останова запущен?

DWORD dw = WaitForSingleObject(g_heventShutdown, 0);

if (dw == WAIT_OBJECT_0) hr = CO_E_SERVER_STOPPING;

else {

// normal CreateInstance implementation

// нормальная реализация CreateInstance

}

UnlockModule();

return hr;

}

Во время написания этого текста ни одна из коммерческих библиотек классов COM не реализовывала этот способ.


Логин
Пароль
Запомнить меня