1.4 Использование 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
Прежде чем начать использование какой-либо процедуры или функции, находящейся в динамической библиотеке, вам необходимо загрузить DLL в оперативную память. Загрузка библиотеки может быть осуществлена одним из двух способов: статическая загрузка и динамическая загрузка. Оба метода имеют как преимущества, так и недостатки.
Статическая загрузка означает, что динамическая библиотека загружается автоматически при запуске на выполнение использующего ее приложения. Для того чтобы использовать такой способ загрузки, вам необходимо воспользоваться ключевым словом external при описании экспортируемой из динамической библиотеки функции или процедуры. DLL автоматически загружается при старте программы, и Вы сможете использовать любые экспортируемые из нее подпрограммы точно так же, как если бы они были описаны внутри модулей приложения. Это наиболее легкий способ использования кода, помещенного в DLL. Недостаток метода заключается в том, что если файл библиотеки, на который имеется ссылка в приложении, отсутствует, программа откажется загружаться.
Смысл динамического метода заключается в том, что вы загружаете библиотеку не при старте приложения, а в тот момент, когда вам это действительно необходимо. Сами посудите, ведь если функция, описанная в динамической библиотеке, используется только при 10% запусков программы, то совершенно нет смысла использовать статический метод загрузки. Выгрузка библиотеки из памяти в данном случае также осуществляется под вашим контролем. Еще одно преимущества такого способа загрузки DLL - это уменьшение (по понятным причинам) времени старта вашего приложения. А какие же у этого способа имеются недостатки? Основной, как мне кажется, - это то, что использование данного метода является более хлопотным, чем рассмотренная выше статическая загрузка. Сначала вам необходимо воспользоваться функцией Windows API LoadLibrary. Для получения указателя на экспортируемой процедуры или функции должна использоваться функция GetProcAddress. После завершения использования библиотеки DLL должна быть выгружена с применением FreeLibrary.
- Введение
- Глава 1. Разработка динамически подключаемых библиотек DLL
- 1.1 Аргументы в пользу использования DLL
- 1.2 Основы разработки DLL
- 1.3 Экспорт функций из DLL
- 1.4 Использование DLLProc
- 1.5 Вызов процедур и функций, загруженных из DLL
- Глава 2. Разработка программы
- 2.1 Постановка задачи
- 2.2 Описание механизма программы
- 2.3 Блок схемы
- 2.4 Структуры данных
- 2.5 Системные требования
- Заключение
- 1.Назначение динамически подключаемых библиотек
- 15. Понятие динамически подключаемой библиотеки. Структура dll-библиотеки. Создание dll-библиотеки. Использование dll-библиотеки в программе. Статический и динамический импорт.
- Лабораторная работа 34. Использование динамически подключаемых библиотек (DLL).
- Динамически подключаемые библиотеки (dll)
- 3 Динамически подключаемые библиотеки.
- 11. Динамически подключаемые библиотеки (dll). Явная и неявная загрузка dll.
- 2.5.5.4. Динамически подключаемые библиотеки
- 2.4. Динамически подключаемые библиотеки.
- Разработка библиотек dll