Использование dllProc
Выше я уже говорил о том, что код инициализации динамической библиотеки может быть помещен в блок begin...end. Однако кроме этого зачастую необходимо предусмотреть некоторые действия, выполняемые в процессе выгрузки DLL из оперативной памяти. В отличии от других типов модулей, модуль DLL не имеет ни секции initialization, ни секции finalization. К примеру, вы можете динамически выделить память в главном блоке, однако не понятно, где эта память должна быть освобождена. Для решения этой проблемы существует DLLProc - специальная процедура, вызываемая в определенные моменты функционирования DLL.
Для начала следует сказать о самой причине существования DLLProc. Динамическая библиотека получает сообщения от Windows в моменты своей загрузки и выгрузки из оперативной памяти, а также в тех случаях, когда какой-нибудь очередной процесс, использующий функции и/или ресурсы, хранящиеся в библиотеке, загружается в память. Такая ситуация возможно в том случае, когда библиотека необходима для функционирования нескольких приложений. А для того, чтобы вы имели возможность указывать, что именно должно происходить в такие моменты, необходимо описать специальную процедуру, которая и будет ответственна за такие действия. К примеру, она может выглядеть следующим образом:
procedure MyFirstDLLProc(Reason: Integer);
begin
if Reason = DLL_PROCESS_DETACH then
{DLL is unloading. Cleanup code here.}
end;
Однако системе совершенно не очевидно, что именно процедура MyFirstDllProc ответственна за обработку рассмотренных выше ситуаций. Поэтому вы должны поставить в соответствие адрес нашей процедуры глобальной переменной DLLProc. Это необходимо сделать в блоке begin...end примерно так:
begin
DLLProc := @MyDLLProc;
{ Что-нибудь еще, что должно выполняться в
процессе инициализации библиотеки }
end.
Ниже представлен код, демонстрирующий один из возможных вариантов применения DLLProc.
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 - один из процессов, использующих библиотеку, "выгружается" из памяти.