Операторная часть библиотеки состоит из кода инициализации
библиотеки. Код инициализации выполняется только один раз при
первоначальной загрузке библиотеки. Когда другие прикладные прог-
раммы будут использовать уже загруженную библиотеку, код инициа-
лизации повторно не выполняется, но увеличивается счетчик исполь-
зования DLL.
DLL хранится в памяти, пока ее счетчик использования больше
нуля. Когда счетчик использования становится нулевым, указывая,
что все использующие DLL прикладные программы завершили работу,
она удаляется из памяти. При этом выполняется код процедуры выхо-
да. Процедуры выхода регистрируются с помощью переменной
ExitProc, которая описывается в Главе 22 "Вопросы управления".
Код инициализации DLL обычно выполняет такие задачи как ре-
гистрация класса окна для содержащихся в DLL оконных процедур и
установка начальных значений для глобальных переменных DLL. Уста-
новив в нулевое значение переменную ExitCode, код инициализации
библиотеки может указать состояние ошибки (ExitCode описывается в
модуле System). По умолчанию ExitCode равна 1, что указывает на
успешную инициализацию. Если код инициализации устанавливает зна-
чение этой переменной в 0, то DLL выгружается из системной памя-
ти, и вызывающая прикладная программа уведомляется о неудачной
загрузке DLL.
Когда выполняется библиотечная процедура выхода, переменная
ExitCode не содержит код завершения процесса. Вместо этого
ExitCode содержит одно из значений wep_System или wep_Free_DLL,
определенных в модуле WinTypes. wep_System указывает на заверше-
ние работы Windows, а wep_Free_DLL указывает на то, что выгружена
данная DLL.
Приведем пример библиотеки с кодом инициализации и процеду-
рой выхода:
library Test;
{$S-}
uses WinTypes, WinProcs;
var
SaveExit: Pointer;
procedure LibExit; far;
begin
if ExitCode = wep_System_Exit then
begin
.
.
B.Pascal 7 & Objects/LR - 190 -
.
{ выполняется завершение работы системы }
.
.
.
end else
begin
.
.
.
{ разгружается DLL }
.
.
.
end;
ExitProcess : SaveExit;
end;
begin
.
.
.
{ выполнить инициализацию DLL }
.
.
.
SaveExit := ExitProc; { сохранить старый указатель
процедуры выхода }
ExitProc := @LibExit; { установка процедуры выхода
LibExit }
end.
В защищенном режиме DOS передаваемое процедуре выхода DLL
значение ExitCode всегда равно 0 и соответствует wep_FREE_DLL.
После разгрузки DLL экспортируемая функция вызывает процеду-
ру WEP (процедура выхода Windows) DLL, если она присутствует.
Библиотека Borland Pascal автоматически экспортирует функцию WEP,
которая продолжает вызывать записанный в переменной ExitProc ад-
рес, пока ExitProc не примет значения nil. Поскольку этот меха-
низм процедур выхода соответствует работе с процедурами выхода в
программах Borland Pascal, и в программах, и в библиотеках вы мо-
жете использовать одну и ту же логику процедур выхода.
Поскольку операционная система при завершении DLL переключа-
ет внутренний стек, процедуры выхода в DLL должны компилироваться
с запрещением проверки стека (в состоянии {$S-}). Кроме того, ес-
ли в процедуре выхода DLL происходит ошибка этапа выполнения,
операционная система аварийно завершает работу, поэтому вы для
предотвращения ошибок этапа выполнения вы должны включить в свой
код достаточное количество проверок.