Динамически подключаемые библиотеки
Часто, во время выполнения программы бывают случаи, когда требуется загрузить библиотеку в оперативную память, попользоваться ей некоторое время, а затем выгрузить её из оперативной памяти, так как в ней уже нет необходимости.
В этом случае пользуются тремя системными функциями операционной системы Windows, которые определены в модулеWindows.pas.
function LoadLibrary(lpLibFileName: PChar): HMODULE; stdcall;
Функция загружает библиотеку с именем lpLibFileNameв оперативную память и в качестве значения возвращает дескриптор загруженной библиотеки.
function GetProcAddress(hModule: HMODULE; lpProcName: LPCSTR): FARPROC; stdcall;
Зная по значению дескриптора hModule, местонахождение в оперативной памяти загруженной библиотеки, функция возвращает адрес (указатель) конкретной процедуры или функции с именемlpProcNameтипа LPCSTR. (Здесь LPCSTR = PAnsiChar).
function FreeLibrary(hLibModule: HMODULE): BOOL; stdcall;
Функция выгружает из оперативной памяти загруженную библиотеку. Возвращает Falseкак только библиотека выгружена.
Нужно отметить то важное обстоятельство что, данные функции являются частью ядра операционной системы Windows, так как они содержатся в базовом модулеKernel, то есть находятся в библиотекеKernel32.dll.
Данный модуль управляет базовыми вещами: файловым вводом/выводом, памятью, загрузкой и выполнением программ, потоками синхронизации объектов, поддержкой сетевой и файловых систем.
Таким образом, динамический вызов подпрограмм, процедур и функций конкретной библиотеки возможен только через посредника – операционную систему Windows. В ОСLinuxпредусмотрены другие названия подобных системных функций.
Задание 3.1. Подключим динамически библиотеку MainDll.dll к проекту и вызовем функцию суммы SummaX_Y(X,Y:real):real;
Будем использовать созданный вами ранее первый проект и библиотеку.
Скопируйте все файлы вашего первого проекта (вместе с готовой библиотекой MainDll.dll) который вы делали в первом задании, в новую папку.
Загрузите проект в Delphiв режиме программирования.
Учитывая, что нам уже не нужна статическая загрузка библиотеки в момент загрузки внешнего приложения (т.е. данного проекта), то в окне редактора кода модуля удалите все объявления импортируемых процедур и функций с ключевым словом external.
Первое что нужно сделать, так это определить переменную процедурного (procedure) или функционального (function) типа.
Объявите глобальную переменную в секции varс именем SummaX_Y функционального типа function(X,Y:real):real.
Таким образом, в окне редактора кода должна быть следующая запись (рис. 11).
Рис. 11Объявляем глобальную переменную SummaX_Y типаfunction
Далее измените надпись на кнопке на следующую:
«Запуск функции SummaX_Y из динамически подключенной библиотеки MainDll.dll»
Измените обработчик щелчка этой кнопки так, чтобы он выглядел следующим образом:
procedure TForm1.Button1Click(Sender: TObject);
var H:THandle; X,Y:real; S:string;
begin
RichEdit1.Clear;
X:=StrToFloat(Edit1.Text);
Y:=StrToFloat(Edit2.Text);
S:=Edit3.Text;
H:=LoadLibrary('MainDll.dll');
// Определяем дескриптор подключенной библиотеки MainDll.dll
if H <> 0 then begin
{Если дескриптор не равен нулю значит библиотека успешно загрузилась}
@SummaX_Y := GetProcAddress(H, 'SummaX_Y');
{Функцией GetProcAddressопределяем адрес функции с именемSummaX_Yсодержащийся в библиотеке и назначаем этот адрес переменной функционального типаSummaX_Yнашего проекта }
if @SummaX_Y<>nil then
Richedit1.Lines.Add(FloatToStr( SummaX_Y(X,Y)) );
{если адрес @ библиотечной функции успешно получен, то есть не равен нулю, то вызываем функцию SummaX_Y}
FreeLibrary(H); //Выгружаем библиотеку из памяти
end;
end;
Вот и всё! Можете запустить программу на выполнение. Программа должна работать правильно. Вернитесь в РП.
Обратите внимание на оператор @ он возвращает адрес некоторого объекта
(процедуры или функции). Его применение эквивалентно функции Addr(X): Pointer.
В данном примере мы назначаем новый адрес переменной функционального типа из нашего проекта. Именно по этому адресу в оперативной памяти находится код функции из библиотеки.
Задание 3.2 (Самостоятельно). Добавьте на форму еще 2 кнопки Button, при щелчке на которых, аналогично будут вызываться остальные 2 функции из динамически подключенной библиотеки MainDll.dll.
function ProizvX_Y(X,Y:real):real; //функция произведения двух чисел X и Y, и
function Revers(S:string):string; //функция возвращающая строку S задом–наперёд
автор и разработчик лабораторных
работ по Delphi
доцент кафедры Информационных технологий и систем
кандидат физ.-мат. наук
Санников Е.В.