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

105

Клиент

 

 

 

 

 

 

DLL

 

 

 

 

 

ВызываетCoCreateInstance

 

 

DllGetClassObject

 

 

 

 

 

 

 

 

CLSID_1

 

&CreateFunction_1

 

 

 

 

 

 

 

 

 

 

 

 

 

CLSID_2

 

&CreateFunction_2

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Фабрика класса 1

 

 

 

 

 

 

 

 

CLSID_n

&CreateFunction_n

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Компонент 1

 

 

 

 

 

 

 

 

 

 

 

 

Компонент n

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

CreateFunction_1

 

 

 

 

 

 

 

 

 

 

 

 

CreateFunction_n

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Рис. 7-4 Простая реализация фабрики класса может обслуживать неколько компонентов

В гл. 9 мы реализуем повторно применимую фабрику класса, которая использует эту структуру.

Прежде чем идти дальше, я хотел бы подчеркнуть один важный момент. Даже если один и тот же код фабрики класса используется несколькими компонентами, данный экземпляр фабрики класса может создавать только компоненты, соответствующие одному CLSID. Соотношение между экземплярами фабрики класса и CLSID всегда будет один к одному. Хотя CFactory могла бы реализовать все наши классы, любой конкретный экземпляр CFactory может создавать только компоненты одного CLSID. Это следствие того, что IClassFactory::CreateInstance не передается в качестве параметра CLSID.

Выгрузка DLL

Я достаточно долго избегал разговора о LockServer и DllCanUnloadNow. Теперь пора заняться ими.

Как мы видели в гл. 5, когда клиент динамически связывается с компонентом, он должен загрузить DLL в память. В Win32 для этой цели используется функция LoadLibrary1. Когда мы закончили работу с DLL, хотелось бы выгрузить ее из памяти. Не стоит засорять память неиспользуемыми компонентами. Библиотека СОМ предоставляет функцию CoFreeUnusedLibraries, которая, как следует из названия, освобождает неиспользуемые библиотеки. Клиент должен периодически вызывать эту функцию в периоды бездействия.

Использование DllCanUnloadNow

Но как CoFreeUnusedLibraries определяет, какие из DLL больше не обслуживают ни одного клиента и могут быть выгружены? CoCreateUnusedLibraries опрашивает DLL, вызывая DllCanUnloadNow. DllCanUnloadNow сообщает СОМ, поддерживает ли данная DLL какие-либо объекты. Если DLL никого не обслуживает, CoFreeUnusedLibraries может ее выгрузить. Чтобы проверять, есть ли еще обслуживаемые компоненты, DLL поддерживает их счетчик. Для этого в CMPNT.CPP просто добавляется следующее объявление:

static long g_cComponents = 0;

Затем IClassFactory::CreateInstance или конструктор компонента увеличивают значение g_cComponents, а деструктор компонента уменьшает его. DllCanUnloadNow дает положительный ответ тогда, когда g_cComponents равна 0.

LockServer

Обратите внимание, что я подсчитываю только обслуживаемые DLL в данный момент компоненты, но не фабрики класса. Может оказаться, что логичнее было бы подсчитывать фабрики класса вместе с самими компонентами. Для серверов внутри процесса Вы, если хотите, можете подсчитывать их. Но в гл. 10 мы познакомимся с локальными серверами, которые реализуются в EXE, а не в DLL. С «внутренней» точки зрения, начало и конец работы у серверов внутри и вне процесса отличаются. (С точки зрения «внешней» клиент не видит никаких различий.) Сервер вне процесса запускается таким способом, что внутри него мы не можем подсчитывать фабрики класса, не попадая в порочный круг, в котором сервер никогда не освобождает себя. Более подробно это обсуждается в гл. 10. Достаточно сказать, что присутствие работающей фабрики класса не гарантирует, что сервер будет удерживаться в памяти.

Это создает трудную ситуацию. Выгрузка DLL, у которой имеются исполняющиеся фабрики класса, может вызвать проблемы у клиентов. Предположим, что у клиента имеется указатель на фабрику класса, а соответствующая DLL выгружена. Если клиент попытается использовать указатель на IClassFactory, произойдет сбой. Клиенту необходим некоторый способ удержания DLL в памяти, если он собирается использовать указатель IClassFactory за пределами одной функции. IClassFactory::LockServer позволяет клиенту удерживать

1 На самом деле библиотека COM использует CoLoadLibrary, которая обращается к LoadLibrary.

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