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



return CoGetObject(pwszObject, 0, IID_IApe, (void**)&rpApe);

}


Как и в предыдущем случае, когда использовался Class Moniker, уровень изоляции, обеспеченный CoGetObject, позволяет клиенту задавать сколь угодно сложную стратегию активации, не меняя ни единой строки кода.


Время жизни сервера

В предыдущих разделах было показано, как СОМ автоматически загружает DLL с целью перенесения реализации объектов в адресное пространство клиентских программ. Однако пока не обсуждалось, как и когда эти DLL выгружаются. Вообще говоря, серверные DLL могут предотвращать преждевременную выгрузку, но именно клиент выбирает момент, когда DLL фактически перестают использоваться. Клиенты, желающие освободить неиспользуемые DLL, вызывают API-функцию СОМ CoFreeUnusedLibraries:


void CoFreeUnusedLibraries(void);


Обычно эта подпрограмма вызывается клиентами в свободное время с целью собрать мусор в своем адресном пространстве. При вызове CoFreeUnusedLibraries СОМ опрашивает каждую из загруженных DLL, чтобы выявить, какие из них не используются. Это делается посредством вызова в каждой DLL функции DllCanUnloadNow, которая должна быть явно экспортирована из этой динамически подключаемой библиотеки.

Функция DllCanUnloadNow, которую экспортирует DLL каждого сервера, должна соответствовать следующей сигнатуре:


HRESULT DllCanUnloadNow(void);


Если DLL желает быть освобожденной, то она возвращает S_OK. Если DLL хочет остаться загруженной, то она возвращает S_FALSE. Серверные DLL должны оставаться загруженными по крайней мере до тех пор, пока сохраняются интерфейсные указатели на ее объекты. Это означает, что в DLL должен быть счетчик всех существующих ссылок на объекты. Чтобы упростить реализацию этого, большинство DLL содержат одну переменную для счетчика блокировок (lock count) и используют две функции для автоматического инкрементирования и декрементирования этого счетчика:


LONG g_cLocks = 0; void LockModule(void)

{ InterlockedIncrement(&g_cLocks); }

void UnlockModule(void)

{ InterlockedDecrement(&g_cLocks); }


При наличии этих подпрограмм реализация DllCanUnloadNow становится чрезвычайно простой:


STDAPI DllCanUnloadNow(void)

{ return g_cLocks == 0 ? S_OK : S_FALSE; }


Oстается только вызывать в подходящее время подпрограммы LockModule и UnlockModule.

Существуют две основные причины, которые должны оставлять DLL сервера загруженной: внешние ссылки на экземпляры объектов и объекты класса, а также невыполненные вызовы