Любые объявленные в DLL глобальные переменные недоступны за ее пределами.
Оказывается, что при загрузке динамической библиотеки в адресное пространство вызывавшего ее процесса, происходят важные события, знание которых позволит вам эффективно управлять инициализацией и выгрузкой DLL.
Итак, перед запуском кода инициализации автоматически вызывается встроенная ассемблерная процедура _lnitDLL (она расположена в модуле System). Она сохраняет состояние регистров процессора; получает значение экземпляра модуля библиотеки и записывает его в глобальную переменную hlnstance; устанавливает для глобальной переменой IsLibrary значение True (по этому значению вы всегда сможете распознать код DLL); получает из стека ряд параметров; проверяет переменную процедурного типа DLLProc:
var DLLProc: Pointer;
Эта переменная используется для проверки вызовов операционной системой точки входа DLL. С этой переменной можно связать процедуру с одним целочисленным параметром. Такая процедура называется функцией обратного вызова системного уровня.
Если при проверке переменной DLLProc процедура _initDLL находит связанную функцию обратного вызова, то она вызывается. При этом ей передается параметр, полученный из стека.
В качестве параметра могут быть переданы четыре значения: const
DLL_PROCESS_DETACH = 0;
DLL_PROCESS_ATTACH = 1;
DLL_THREAD_ATTACH = 2;
DLL_THREAD_DETACH = 3;
Рассмотрим их.
□ Значение DLL PROCESS DETACH передается при выгрузке DLL из адресного пространства процесса. Это происходит при явном вызове системной функции FreeLibrary (см. ниже) или при завершении процесса.
□ Значение DLL PROCESS ATTACH означает, что библиотека отображается в адресное пространство процесса, который загружает ее в первый раз.
□ Значение DLL thread_attach посылается всем загруженным в процесс динамическим библиотекам при создании нового потока. Обратите внимание, что при создании процесса и первичного потока посылается только одно значение DLL_PROCESS ATTACH.
□ Значение DLL такЕАЕ)DETACH посылается всем загруженным в процесс динамическим библиотекам при уничтожении существующего потока.
Впоследствии, при работе процесса с загруженной DLL, в случае возникновения описанных событий, функция обратного вызова вызывается снова и снова. При этом ей передается одно из рассмотренных значений.
Это хороший способ организовать в динамической библиотеке необходимую в каждом случае обработку. Как это сделать?
Во-первых, необходимо создать процедуру, подходящую для процедурного типа DLLProc, и написать для нее исходный код, применяемый в зависимости от переданного параметра.
Во-вторых, в секции инициализации нужно связать переменную DIJLJttjc и созданную процедуру.
Применительно к рассматриваемому нами примеру, модернизированный исходный код библиотеки DataCheck будет выглядеть так:
Листинг28.3. Часть исходногокодадинамическойбиблиотеки DataCheck с функцией обратного вызова '.- ■ < . .
{Часть исходного кода опущена (см. листинг 24.2)}
exports
IsValidlnt,
IsValidDate index 1,