Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Роджерсон Д. - Основы COM - 2000.pdf
Скачиваний:
411
Добавлен:
13.08.2013
Размер:
2.4 Mб
Скачать

172

Обратите внимание, что CoRevokeClassObject передается пресловутый магический признак, который мы получили ранее от CoRegisterClassObject.

Изменения в LockServer

Серверы внутри процесса экспортируют функцию DllCanUnloadNow. Библиотека СОМ вызывает ее, чтобы определить, можно ли выгрузить сервер из памяти. DllCanUnloadNow реализована при помощи статической функции CFactory::CanUnloadNow, которая проверяет значение статической переменной CUnknown::s_ActiveComponents. Всякий раз при создании нового компонента этот счетчик увеличивается. Однако, как обсуждалось в гл. 7, мы не увеличиваем его значение при создании новой фабрики класса. Следовательно, сервер допускает завершение своей работы даже при наличии у него активных фабрик класса.

Теперь должно быть понятно, почему мы не учитывали фабрики класса вместе с активными компонентами. Первое, что делает локальный сервер, это создает свои фабрики класса; последнее, что он делает, — удаляет их. Если бы для завершения работы серверу нужно было дожидаться ликвидации этих фабрик, ждать ему пришлось бы долго — потому что именно он и должен их ликвидировать перед окончанием работы. Поэтому клиент должен использовать функцию IClassFactory::LockServer, если он хочет гарантировать, что сервер присутствует в памяти, пока клиент пытается создавать компоненты.

Нам необходимо внести некоторые изменения в LockServer, чтобы использовать эту функцию в локальном сервере. Позвольте мне пояснить необходимость изменений. DLL не управляет временем своей жизни. EXE загружает DLL, и EXE выгружает DLL. Однако EXE управляют временем своего существования и могут выгружаться сами. Никто не будет выгружать модуль EXE, он должен делать это сам. Следовательно, нам необходимо изменить LockServer, чтобы завершить работу EXE, когда счетчик блокировок становиться равным нулю. Я добавил к CFactory новую функцию-член CloseExe, которая посылает WM_QUIT в цикл выборки сообщений приложения:

#ifdef _OUTPROC_SERVER_ void CFactory::CloseExe()

{

if (CanUnloadNow() == S_OK)

{

::PostThreadMessage(s_dwThreadID, WM_QUIT, 0,0);

}

}

#else

// CloseExe ничего не делает для сервера внутри процесса. void CFactory::CloseExe() { /*Пусто*/ }

#endif

Заметьте, что для сервера внутри процесса эта функция ничего не делает. Чтобы сделать код изумительно эффективным, я просто вызываю CloseExe из LockServer.

HRESULT __stdcall CFactory::LockServer(BOOL block)

{

if (block)

{

::InterlockedIncrement(&s_cServerLocks);

}

else

{

::InterlockedDecrement(&s_cServerLocks);

}

// Для сервера вне процесса проверить, можно ли завершить работу программы.

CloseExe();

return S_OK;

}

необходимо также вызывать CloseExe из деструкторов компонентов; это еще одно место, где модуль EXE может определить, нужно ли ему завершить работу. Для этого я изменил деструктор Cunknown:

CUnknown::~CUnknown()

{

::InterlockedDecrement(&s_cActiveComponents);

//Если это сервер EXE, завершить работу.

CFactory::CloseExe();

}

Соседние файлы в предмете Программирование на C++