Динамически подключаемые библиотеки (dll)
Динамически подключаемые библиотеки (DLL- Dynamic Link Library) представляют собой универсальный механизм интегрирования в программу процедур и функций, написанных другими программистами и на других языках программирования. DLL представляют структуру, внешне напоминающую модуль, но без возможности использования переменных, типов, констант (только процедуры и функции!). Для экспортирования классов используют пакеты (см. раздел о создании компонент).
Процедуры DLL подключаются к программе в момент ее выполнения, т.е. динамически, тогда как из модуля они подключаются во время компоновки программы, т.е. статически. Поэтому, если изменить содержимое процедуры DLL, то перекомпилировать программу нет необходимости. В случае с модулем - придется при каждом изменения процедуры компилировать сам модуль и саму программу.
Создадим DLL, в которой поместим 4 процедуры для работы с комплексными числами. Для создания заготовки библиотечного модуля выберем пункт меню File\New\Unit. Сохраним проект под именем Cmplx и запишем следующий текст:
Library Cmplx;
Uses
SysUtils, Classes;
{$R *.RES}
//Это описание типа придется вставлять везде, где используется
//эта библиотека!
Type TComplex=record
Re,Im:Real;
End;
Function AddC(x, y:TComplex): TComplex; stdcall;
Begin
Result.Im := x.Im + y.Im;
Result.re := x.Re + y.Re
End;
Function SubC(x, y:TComplex): TComplex; stdcall;
Begin
Result.Im := x.Im - y.Im;
Result.re := x.Re - y.Re
End;
Function MulC(x, y:TComplex): TComplex; stdcall;
Begin
Result.Im := x.Re* y.Im –x.Im * y.Re;
Result.re := x.Re* y.Re +x.Im * y.Im
End;
Function DivC(x, y:TComplex): TComplex; stdcall;
Var z:Real;
Begin
Z := sqr(y.Re)+ sqr(y.Im);
try
Result.Re := (x.Re* y.Re +x.Im * y.Im)/z;
Result.Im := (x.Re* y.Im –x.Im * y.Re)/z;
Except
Result.Re := 1e+309;
Result.Im := 1e+309;
end
End;
Exports
AddC index 1 name ‘ADDC’ resident,
SubC index 2,
MulC index 3,
DivC index 4;
Begin
End.
Все функции нашей DLL используют соглашение stdcall, которое обеспечивает совместимость новых функций с функциями API Windows 32, что позволило бы обращаться к нашей DLL из программ, написанных на других языках программирования. Соглашение register используется компилятором автоматически, а процедуры применимы только для программ, написанных на Object Pascal. В Windows существует понятие "резидентных функций" DLL, то есть тех функций, которые находятся в памяти на протяжении всего времени существования DLL в памяти. Такие функции объявляются ключевым словом resident.
В разделе Exports перечислены все имена процедур DLL и присвоены индексы каждой из них. В случае, если имя процедуры может совпадать с именем других процедур, ей присваивается свое внешнее имя в апострофах после слова name.
Для использования подпрограмм из DLL необходимо описать их как внешние, добавив за словом External имя библиотеки в апострофах и указав индекс процедуры или внешнее имя:
Function DivC(x, y:TComplex): TComplex; stdcall;External ‘Cmplx’;
Function SubC(x, y:TComplex): TComplex; stdcall;External ‘Cmplx’ index 2;
Function AddC(x, y:TComplex): TComplex; stdcall;External ‘Cmplx’ name ‘ADDC’;
Программа может загружать DLL и без External с помощью трех стандартных функций: LoadLibrary, GetProcAddress, FreeLibrary(Handle). Пусть на форме помещено окно Memo1 и кнопка Button1. По нажатию кнопки выполняются арифметические действия над случайно образованными комплексными числами.
Implementation
Type TComplex=record
Re,Im:Real;
End;
TComplexFunc=function (x, y:TComplex): TComplex; stdcall;
Procedure TfmExample.Button1Click(Sender:TObject);
Var x,y,z:TComplex;
AddC, SubC, MulC, DivC: TComplexFunc;
Handle: LongWord;
Procedure OutPut(Operation: Char);
Var S:String;
Begin
Case Operation of
‘+’: z:=AddC(x,y);
‘-’: z:=SubC(x,y);
‘*’: z:=MulC(x,y);
‘/’: z:=DivC(x,y);
End;
S:=’(‘ + FormatFloat(‘+0.0000;-0.0000’, x.re) + ’,’ + FormatFloat(‘+0.0000;-0.0000’, x.im)+’)’ + Operation + ’(‘ + FormatFloat(‘+0.0000;-0.0000’, y.re) + ’,’ + FormatFloat(‘+0.0000;-0.0000’, y.im) + ’)=(’ + FormatFloat(‘+0.0000;-0.0000’, z.re)+’,’+
FormatFloat(‘+0.0000;-0.0000’, z.im)+’)’;
Memo1.Lines.Add(S);
End;
Begin
//Загружаем библиотеку в память при выполнении программы
Handle := LoadLibrary(‘Cmplx.dll’);
If Handle=0 then
Begin
ShowMessage(‘Не найдена библиотека CMPLX.dll’);
Halt
End;
//Определяем адреса функций
@AddC:= GetProcAddress(Handle, PChar(LongInt(1)));
@SubC:= GetProcAddress(Handle, PChar(LongInt(2)));
@MulC:= GetProcAddress(Handle, PChar(LongInt(3)));
@DivC:= GetProcAddress(Handle, ‘DivC’);
x.re:=random;
x.im:=random;
y.re:=random;
y.im:=random;
Output(‘+’);
Output(‘-’);
Output(‘*’);
Output(‘/’);
Memo1.Lines.Add(‘’);
//Освобождаем библиотеку из памяти
FreeLibrary(Handle);
End;
С помощью DLL можно вызывать формы из связанных с библиотекой модулей. Для этого в библиотеке используется ссылка Uses на связанные модули формы и объявляются экспортируемые из DLL подпрограммы, в которых реализуется вызов соответствующих форм. Например так:
Library DLLWithForm;
Uses SysUtils,
Classes,
DLLFormUnit in ‘DLLFormUnit.pas’{DLLForm}
{$R *RES}
Exports
showform, freeform;
Begin
End.
- Новые технологии.
- Создание новых компонент
- Добавление свойств
- Добавление методов
- Добавление событий
- Разработка ресурсов для компоненты
- Установка компоненты
- Испытание компоненты
- Редактирование компоненты
- Создание справочной службы помощи
- Динамически подключаемые библиотеки (dll)
- Работа с буфером обмена
- Динамический обмен данными (dde)
- Связывание и внедрение объектов (ole)
- Упражнения: