1. Привязка библиотеки к программе (статическая загрузка)
Недостатки:
- нет эффекта экономии ресурсов (библиотека загружается при запуске программы и выгружается при завершении программы)
- при отсутствии хотя бы одной из необходимых библиотек в папке с программой, либо в папке $windir$/system программа не запускается и выдает сообщение об ошибке
- при отсутствии хотя бы одной из необходимых функций в библиотеке при запуске программа выдает сообщение об ошибке и не запускается
Преимущества:
- легкость использования
У этого способа много недостатков. Но все же он будет полезен начинающим программистам. Для использования функций или процедур из библиотеки таким способом нужно всего лишь в разделе implementation указать имя функции или процедуры примерно так:
//если функция
function FunctionName(Par1: Par1Type; Par2: Par2Type; ParN : ParNType): ReturnType; stdcall; external "MyDLL.dll" name "FunctionName" index FunctionIndex;
//если процедура
procedure ProcedureName(Par1: Par1Type; Par2: Par2Type; ...); stdcall; external "MyDLL.dll" name "ProcedureName" index ProcIndex;
Рассмотрим обьявление функции.
function FunctionName(Par1: Par1Type; Par2: Par2Type; ParN : ParNType): ReturnType; - Это собственно обьявление функции
external "MyDLL.dll" эта директива указывает на имя библиотеки, из которой будет вызвана функция (в нашем случае это MyDLL.dll)
name "FunctionName" необьязательная директива, которая указывает на имя функции в библиотеке; используется для повышения скорости доступа к функциям (имя определяется внутри библиотеки)
index FunctionIndex тоже необьязательная директива, использующаяся для ускорения доступа к функциям; указывает на индекс функции (индекс обьявляется в самой библиотеке).
Рассматривать обьявление процедуры не имеет смысла, т.к. процедурв вызывается точно так же (за исключением того, что у процедура ничего не возвращает). Вот и все! Теперь можно пользоваться обьявленой функцие в пределах модуля, в котором она была обьявлена.
Рассмотрим пример на основе нашей демонстрационной библиотеки, которую мы скомпилировали выше.
Создайте новый проект Project1 и на его форму поместите четыре поля Edit. Присвойте им такие имена: Num1Edit, Num2Edit, OpEdit, ResultEdit. Так же поместите одну кнопку, имя которой значения не имеет. В разделе implementation обьявите функцию:
implementation
function MyFunc(num1, num2, Errcode : Integer; Operation : PChar) : Integer; stdcall; external "Project2.dll" name "MathFunc" index 1;
А обработчик единственной кнопки приведите к примерно такому виду:
procedure TForm1.DoItButtonClick(Sender: TObject);
const
Errcode : Integer=978987;//код ошибки - может быть абсолютно любым.
var
Num1, Num2, Result_ : Integer;//для проверки чисел
Operation : String;//операция, для передачи параметра функции
begin
try //прежде чем передать числа
Num1 := StrToInt(Num1Edit.Text); //функции проверим их
Num2 := StrToInt(Num2Edit.Text);
except
Num1Edit.Text := "0";
Num2Edit.Text := "0";
ResultEdit.Text := "Введите целые ЧИСЛA";
EXIT;
end;
Operation := OpEdit.Text; //также проверим, введена ли правильная команда.
if (Operation<>"plus")and(Operation<>"minus")and(Operation<>"multiply")
and(Operation<>"div")and(Operation<>"mod") then
begin
ResultEdit.Text := "Введите корректную команду";
Exit;
end;
Result_ := MyFunc(Num1, Num2, Errcode, PChar(Operation)); //использование библиотечной функции
if Result_=Errcode then //если функция возвратила код ошибки то
begin //то сообщаем об этом.
ResultEdit.Text := "ОШИБКА";
EXIT;
end
else //а если результат отличный от кода ошибки
ResultEdit.Text := IntToStr(Result_);//то выводим его
end;
Обратите внимание, что мы используем функцию из библиотеки так же, как и если она была бы написана в модуле. Ещё раз повторяю, что при привязке библиотеки к программе функцию можно использовать только в тех модулях, в которых она была обьявлена. Вот вам мини калькулятор, который работает на (хотел было сказать на батарейках) DLL.
2. Динамическая загрузка
Недостатки:
- громоздкость и сложность кода
- функции библиотеки доступны только тогда, когда библиотека загружена в память
Преимущества:
- начисто лишен всех недостатков первого способа + некоторые другие преимущества перед первым способом
Этот способ довольно сложен, особенно для новичков. Но преимуществ перед первым способом у него куда больше. Для работы с динамически загружаемыми библиотеками просто необходимо знать три WinAPI функции: LoadLibrary, GetProcAddress И FreeLibrary.
LoadLibrary(LibFileName: PChar) - загружает библиотеку LibFileName в память. Если библиотека загружена удачно, то функция возвращает дескриптор (THandle) DLL в памяти.
GetProcAddress(Module: THandle; ProcName: PChar) - находит точку входа в функцию ProcName. Внимание! Здесь нужно указать NAME функции, а не её название. Если функция найдена, то функция GetProcAddress возвращает дескриптор (TFarProc) функции в загруженной DLL.
FreeLibrary(LibModule: THandle) - выгружает библиотеку LibModule. При этом вся занятая этой библиотекой память освобождается. Следует заметить, что после вызова этой процедуры функции данной библиотеки больше недоступны и обращение к ним вызовет исключение.
Для того, что бы динамически загрузить функцию из библиотеки, то необходимо её обьявить в разделе var:
MyFunc: function(num1, num2, Errcode : Integer; Operation : PChar) : Integer; stdcall;
Также нужно обьявить переменную типа THandle. "На пальцах" не обьяснишь, поэтому давайте рассмотрим пример динамической загрузки DLL на основе нашей демонстрационной библиотеки.
Откройте предыдущий проект с демонстрацией статическо загрузки. В разделе var обьявите пару новых переменных:
LibHandle: THandle;
MyFunc: function(num1, num2, Errcode : Integer; Operation : PChar) : Integer; stdcall;
Обработчик кнопки приведите к такому виду:
procedure TForm1.DoItButtonClick(Sender: TObject);
const
Errcode : Integer=978987;//код ошибки - может быть абсолютно любым.
var
Num1, Num2, Result_ : Integer;//для проверки чисел
Operation : String;//операция, для передачи параметра функции
begin
try //прежде чем передать числа
Num1 := StrToInt(Num1Edit.Text); //функции проверим их
Num2 := StrToInt(Num2Edit.Text);
except
Num1Edit.Text := "0";
Num2Edit.Text := "0";
ResultEdit.Text := "Введите ЧИСЛA";
EXIT;
end;
Operation := OpEdit.Text; //также проверим, введена ли правильная команда.
if (Operation<>"plus")and(Operation<>"minus")and(Operation<>"multiply")
and(Operation<>"div")and(Operation<>"mod") then
begin
ResultEdit.Text := "Введите корректную команду";
Exit;
end;
//до этого момента код остался без изменений.
@MyFunc := nil; //очищаем адрес функции
LibHandle := LoadLibrary("Project2.dll");//пытаемся загрузить библиотеку
if LibHandle >= 32 then
begin //если все прошло успешно то
@MyFunc := GetProcAddress(LibHandle, "MathFunc");//пытаемся найти адрес функции
if @MyFunc <> nil then //если адрес найден (функция существует в библиотеке)
Result_ := MyFunc(Num1, Num2, Errcode, PChar(Operation)); //использование библиотечной функции
if Result_=Errcode then //если функция возвратила код ошибки то
begin //то сообщаем об этом.
ResultEdit.Text := "ОШИБКА";
EXIT;
end
else //а если результат отличный от кода ошибки
ResultEdit.Text := IntToStr(Result_);//то выводим его}
end;
end;
Заключение
В этой статье мы коснулись лишь основных аспектов программирования с применением динамически-подключаемых библиотек. А ведь в DLL можно хранить всякие картинки и даже формы! С помощью них удобно создавать всякие плагины. Но это уже совсем другая история
Список литературы
Для подготовки данной работы были использованы материалы с сайта http://www.soch.imperium.by
... окне редактирования кода? Вот эти файлы содержат как раз эти схемы, которые можно создавать в том окне. .DFM - Delphi Form File: здесь в двоичном виде хранится описание формы и компонентов, которая эта форма содержит .~DF - Резервная копия файла формы: в большинсте случаев она бесполезна, зря засоряет винчестеры. Так что гнать в шею! (точнее отключить в настройках :) .DOF - Delphi Options File: ...
... Можете ли вы предсказать результат выражения '1'+ '2'+3? Если вы сказали '6', то вы тоже попались. Посмотрим повнимательнее, '1'+ '2' будет... конечно '12', 12+3=15. Это и есть правильный ответ. Итак, мы увидели семь чудес Delphi, семь - из многих. Это не значит, что они - самые яркие или самые чудесные. Но на них можно многому научиться. Возьмем последнее, только что рассмотренное нами, чудо. ...
... в базе данных упрощает поиск необходимых данных. Наличие большого объема информации, которые требуются работникам различных организаций, оправдывает создание программистами баз данных, для удобства работы. Данная БД весьма актуальна для мастерских по ремонту бытовой техники. 1.2 Модель данных Реляционная модель данных описывает: 1. структуры данных в виде наборов отношений, ...
0 комментариев