logo search
Лабораторная работа6

Динамически подключаемые библиотеки (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.