Любые объявленные в DLL глобальные переменные недоступны за ее пределами.
Оказывается, что при загрузке динамической библиотеки в адресное пространство вызывавшего ее процесса, происходят важные события, знание которых позволит вам эффективно управлять инициализацией и выгрузкой DLL.
(Слайд 27)
Итак, перед запуском кода инициализации автоматически вызывается встроенная ассемблерная процедура _initDLL (она расположена в модуле system).
Она:
Ø сохраняет состояние регистров процессора;
Ø получает значение экземпляра модуля библиотеки и записывает его в глобальную переменную hinstance;
Ø устанавливает для глобальной переменой isLibraryзначение True (по этому значению вы всегда сможете распознать код DLL);
Ø получает из стека ряд параметров;
Ø проверяет переменную процедурного типа DLLProc;
(Слайд 28)
var DLLProc: Pointer;
Эта переменная используется для проверки вызовов операционной системой точки входа DLL. С этой переменной можно связать процедуру с одним целочисленным параметром. Такая процедура называется функцией обратного вызова системного уровня.
(Слайд 29)
Если при проверке переменной DLLProc процедура _initDLL находит связанную функцию обратного вызова, то она вызывается. При этом ей передается параметр, полученный из стека. В качестве параметра могут быть переданы четыре значения:
const
DLL_PROCESS_DETACH = 0;
DLL_PROCESS_ATTACH = 1;
DLL_THREAD_ATTACH = 2;
DLL_THREAD_DETACH = 3;
(Слайд 30)
Рассмотрим их.
Значение DLL_PROCESS_DETACH передается при выгрузке DLL из адресного пространства процесса. Это происходит при явном вызове системной функции FreeLibrary (см. ниже) или при завершении процесса.
Значение DLL_PROCESS_ATTACH означает, что библиотека отображается в адресное пространство процесса, который загружает ее в первый раз.
(Слайд 31)
Значение DLL_THREAD_ATTACH посылается всем загруженным в процесс динамическим библиотекам при создании нового потока. Обратите внимание, что при создании процесса и первичного потока посылается только одно значение DLL_PROCESS_ATTACH.
Значение DLL_THREAD_DETACH посылается всем загруженным в процесс динамическим библиотекам при уничтожении существующего потока.
(Слайд 32)
Впоследствии, при работе процесса с загруженной DLL, в случае возникновения описанных событий, функция обратного вызова вызывается снова и снова. При этом ей передается одно из рассмотренных значений.
Это хороший способ организовать в динамической библиотеке необходимую в каждом случае обработку. (Слайд 33)
Как это сделать?
Во-первых, необходимо создать процедуру, подходящую для процедурного типа DLLProc, и написать для нее исходный код, применяемый в зависимости от переданного параметра.
Во-вторых, в секции инициализации нужно связать переменную DLLProc и созданную процедуру.
(Слайд 34)
Применительно к рассматриваемому нами примеру, модернизированный исходный код библиотеки DataCheck будет выглядеть так:
Листинг 28.3. Часть исходного кода динамической библиотеки DataCheck c функцией обратного вызова
DLL_THREAD_ATTACH: ShowMessage('Создан новый поток'); DLL_THREAD_DETACH:; end; end;
begin
DLLProc := @DLLEntryPoint;
DLLEntryPoint(DLL_PROCESS_ATTACH);
end.
Процедура DLLEntryPoint обеспечивает простой показ сообщения о полученном значении параметра. В коде инициализации глобальной переменной DLLProc передается адрес процедуры DLLEntryPoint. Затем эта процедура вызывается явно с параметром DLL_PROCESS_ATTACH.
У недоверчивого читателя может возникнуть вопрос — а зачем городить такие сложности, если можно просто использовать код в секции инициализации? Дело в том, что этот код выполняется только при запуске DLL. Поэтому, как, например, вовремя уничтожить создаваемые в библиотеке объекты при завершении ее работы? Для этого можно использовать функцию обратного вызова:
Листинг 28.4. Создание и удаление объекта при загрузке и выгрузке динамической библиотеки DataCheck .
DLL_THREAD_ATTACH: ShowMessage('Создан новый поток'); DLL_THREAD_DETACH:;
end;
end;
begin
DLLProc := @DLLEntryPoint;
DLLEntryPoint(DLL_PROCESS_ATTACH);
end.
При завершении работы динамической библиотеки вызывается процедура, на которую указывает адрес, содержащийся в переменной ExitProc:
var ExitProc: Pointer;
ISDN-терминал – оборудование для передачи речевой информации и/или данных в цифровом виде. Терминал осуществляет АЦ и ЦА преобразование, управление обеспечивается встроенным микропроцессором, который также осуществляет сигнализацию с узлом коммутации по D-каналу.
Обязательным элементом структуры доступа пользователя к сети является дуплексный цифровой канал для передачи служебной (сигнальной) информации между ISDN-терминалом и АТС сети ISDN - D-канал.Помимо сигнализации, D-канал может использоваться для передачи в пакетном режиме (с относительно небольшой скоростью) пользовательской информации.
Сигнальная информация необходима для организации, поддержания и завершения сеанса связи между терминалами пользователей.
На несколько терминалов пользователя ISDN имеется один общий канал D.
Помимо D-канала структура доступа пользователя к сети предусматривает дуплексные цифровые каналы, предназначенные для передачи информации пользователей. В узкополосной ISDN эти каналы обеспечивают передачу информации со скоростью 64 Кбит/с (как в режиме коммутации каналов, так и в пакетном режиме) и называются B-каналами.
Для узкополосной ISDN в Европе и в России стандартизованы две структуры доступа:
o базовый доступ (BRI), который имеет структуру 2B+D (D=16 Кбит/с);
o доступ на первичной скорости (PRI), который имеет структуру 30B+D (D=64 Кбит/с).