Использование DLLProc
Выше я уже говорил о том, что код инициализации динамической библиотеки может быть помещен в блок begin...end. Однако кроме этого зачастую необходимо предусмотреть некоторые действия, выполняемые в процессе выгрузки DLL из оперативной памяти. В отличии от других типов модулей, модуль DLL не имеет ни секции initialization, ни секции finalization. К примеру, вы можете динамически выделить память в главном блоке, однако не понятно, где эта память должна быть освобождена. Для решения этой проблемы существует DLLProc - специальная процедура, вызываемая в определенные моменты функционирования DLL.
Для начала следует сказать о самой причине существования DLLProc. Динамическая библиотека получает сообщения от Windows в моменты своей загрузки и выгрузки из оперативной памяти, а также в тех случаях, когда какой-нибудь очередной процесс, использующий функции и/или ресурсы, хранящиеся в библиотеке, загружается в память. Такая ситуация возможно в том случае, когда библиотека необходима для функционирования нескольких приложений. А для того, чтобы вы имели возможность указывать, что именно должно происходить в такие моменты, необходимо описать специальную процедуру, которая и будет ответственна за такие действия. К примеру, она может выглядеть следующим образом:
Code: |
procedure MyFirstDLLProc(Reason: Integer); begin if Reason = DLL_PROCESS_DETACH then {DLL is unloading. Cleanup code here.} end; |
Однако системе совершенно не очевидно, что именно процедура MyFirstDllProc ответственна за обработку рассмотренных выше ситуаций. Поэтому вы должны поставить в соответствие адрес нашей процедуры глобальной переменной DLLProc. Это необходимо сделать в блоке begin...end примерно так:
Code: |
begin DLLProc := @MyDLLProc; { Что-нибудь еще, что должно выполняться в процессе инициализации библиотеки } end. |
Ниже представлен код, демонстрирующий один из возможных вариантов применения DLLProc.
Code: |
library MyFirstDLL; uses SysUtils, Classes, Forms, Windows;
var SomeBuffer: Pointer;
procedure MyFirstDLLProc(Reason: Integer); begin if Reason = DLL_PROCESS_DETACH then {DLL is выгружается из памяти. Освобождаем память, выделенную под буфер.} FreeMem(SomeBuffer); end;
procedure HelloWorld(AForm: TForm); begin MessageBox(AForm.Handle, 'Hello world!', 'DLL Message Box', MB_OK or MB_ICONEXCLAMATION); end;
{Какой-нибудь код, в котором используется SomeBuffer.}
exports HelloWorld;
begin {Ставим в соответствие переменной DLLProc адрес нашей процедуры.} DLLProc := @MyFirstDLLProc; SomeBuffer := AllocMem(1024); end. |
Как можно увидеть, в качестве признака того или иного события, в результате которого вызывается процедура MyFirstDll, является значение переменной Reason. Ниже приведены возможные значения этой переменной.
DLL_PROCESS_DETACH
библиотека выгружается из памяти; используется один раз;
DLL_THREAD_ATTACH
в оперативную память загружается новый процесс, использующий ресурсы и/или код из данной библиотеки;
DLL_THREAD_DETACH
один из процессов, использующих библиотеку, "выгружается" из памяти.
Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.
ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!