Цитата
Экспорт функций из DLL
Как уже говорилось выше, для экспорта процедур и функций из DLL, необходимо использовать ключевое слово export. Еще раз обратите внимание на представленный выше листинг библиотеки MiFirstDll. Поскольку процедура HelloWorld определена как экспортируемая, то она может быть вызвана на выполнение из других библиотек или приложений. Существуют следующие способы экспорта процедур и функций: экспорт по имени и экспорт по порядковому номеру.
Наиболее распространенный способ экспорта - по имени. Взглянем на приведенный ниже текст:
exports
SayHello,
DoSomething,
DoSomethingReallyCool;
Следует обратить внимание на то, что Delphi автоматически назначает порядковый номер каждой экспортируемой функции (процедуре) независимо от того, определяете вы его явно или нет. Явное определение индекса позволяет вам лично управлять порядковым номером экспортируемой функции или процедуры.
Для того, чтобы определить выполняется ли ваш кодек в DLL или в вызывающем приложении, можно воспользоваться глобальной переменной IsLibrary. Она принимает значение true в том случае, если код вызывается из библиотеки и false в случае выполнения процедуры или функции из вызывающего приложения.
Кроме этого, в поставку Delphi входит весьма полезная утилита tdump, которая предоставляет данные о том, какая информация экспортируется из указанной DLL.
Использование 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
один из процессов, использующих библиотеку, "выгружается" из памяти.
Как уже говорилось выше, для экспорта процедур и функций из DLL, необходимо использовать ключевое слово export. Еще раз обратите внимание на представленный выше листинг библиотеки MiFirstDll. Поскольку процедура HelloWorld определена как экспортируемая, то она может быть вызвана на выполнение из других библиотек или приложений. Существуют следующие способы экспорта процедур и функций: экспорт по имени и экспорт по порядковому номеру.
Наиболее распространенный способ экспорта - по имени. Взглянем на приведенный ниже текст:
exports
SayHello,
DoSomething,
DoSomethingReallyCool;
Следует обратить внимание на то, что Delphi автоматически назначает порядковый номер каждой экспортируемой функции (процедуре) независимо от того, определяете вы его явно или нет. Явное определение индекса позволяет вам лично управлять порядковым номером экспортируемой функции или процедуры.
Для того, чтобы определить выполняется ли ваш кодек в DLL или в вызывающем приложении, можно воспользоваться глобальной переменной IsLibrary. Она принимает значение true в том случае, если код вызывается из библиотеки и false в случае выполнения процедуры или функции из вызывающего приложения.
Кроме этого, в поставку Delphi входит весьма полезная утилита tdump, которая предоставляет данные о том, какая информация экспортируется из указанной DLL.
Использование 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
один из процессов, использующих библиотеку, "выгружается" из памяти.