Автор: Пользователь скрыл имя, 03 Ноября 2012 в 08:04, практическая работа
Практическая работа №9.
Создание и использование DLL в Delphi. DLL Wizard. Создание форм в DLL
Практическая работа №9.
Создание и использование DLL в Delphi. DLL Wizard. Создание форм в DLL
Основные понятия
DLL – Dynamic Link Library – это разновидность исполняемых файлов Windows. Файл, в котором располагается динамическая библиотека, обычно имеет расширение .dll, но может быть и другое, например, .exe.
Динамически подключаемая библиотека представляет собой выполняемый модуль, код и ресурсы которого могут использоваться другими динамическими библиотеками и приложениями. DLL-библиотека подключается в период выполнения приложения, её код не копируется в исполняемые файлы программ (в отличие от обычных библиотечных модулей, которые подсоединяются на этапе компоновки). Достоинства:
Итак, основные достоинства – это гибкость и экономия памяти и дискового пространства. Компоновка обычных модулей Delphi выполняется статически, то есть во время компиляции, копия кода всех используемых модулей помещается в exe-файл. Это приводит к тому, что программы, использующие один и тот же модуль, будут содержать большое количество повторяющегося кода. При одновременном запуске таких программ код будет дублироваться в памяти.
В некоторых случаях основная причина использования DLL заключается в гибкости создаваемого приложения. Например, при создании текстового редактора невозможно предусмотреть форматы файлов, которые появятся в будущем. Однако разрабатываемое приложение должно быть приспособлено к работе с новыми версиями форматов. При использовании динамических библиотек поддержка нового формата сводится к написанию DLL и распространению её среди пользователей, которым она может потребоваться. В этом случае в exe-файл включается инструкция о том, где программа должна искать необходимый код.
Динамические библиотеки могут экспортировать только процедуры и функции. Описанные в них типы, константы, массивы и другие языковые конструкции предназначены исключительно для внутреннего использования. В DLL рекомендуется помещать процедуры и функции, реализующие дополнительные возможности программы.
Как и любая программа DLL компилируется совместно с модулем System, что позволяет определить ссылку на экземпляр DLL через переменную HInstance и передать ссылку тем функциям, которые ожидают её в качестве параметра. При обращении к DLL включается счётчик (Hprevinst) и при каждом новом обращении счетчик увеличивается на единицу. DLL не выгружается из памяти до тех пор, пока значение счётчика не станет равным нулю.
Проблем с поиском DLL не возникает, если DLL и исполняемый файл программы располагаются в одном каталоге. Если программы, использующие DLL, находятся в разных каталогах, то целесообразно поместить DLL в каталог, просматриваемый Windows по умолчанию при загрузке DLL. Windows ищет DLL в следующих местах и в следующем порядке:
В случае динамического импорта при вызове LoadLibrary можно указать для DLL полный путь, тогда Windows просмотрит только заданный каталог. При статическом импорте такой возможности нет. Основной недостаток DLL – это отсутствие проверки типов. Обращаясь к функции, фактически даём указание компилятору вызвать функцию, о которой он ничего не знает. Если будет указано неверное количество параметров или параметры будут неверных типов, то вызов функции может привести к непредсказуемым последствиям. Найти подобную ошибку очень сложно.
Изучение DLL предусматривает рассмотрение двух вопросов: создание библиотеки и её использование.
Структура DLL
По своей сути DLL похожи на модули, но их код больше напоминает программы. По функциональному назначению и модуль и DLL представляют собой библиотеки подпрограмм, но организованы они по-разному. Динамические библиотеки – это особая разновидность программ, предоставляющих код или данные другим программам. DLL имеет обязательный заголовок, который начинается со служебного слова library.
Процедуры и функции записываются так же, как принято в программах, но их необходимо явным образом экспортировать, чтобы они стали доступны другим программам или динамическим библиотекам. Для этого вводится секция exports, в которой перечисляются экспортируемые библиотекой процедуры и функции. В качестве разделителя при перечислении используется запятая, завершается секция exports точкой с запятой. В DLL может быть несколько секций exports. Обязательно включается секция инициализации, которая, однако, может быть пустой. Шаблон DLL приведён ниже.
library MyDll;
uses //Перечень подключаемых модулей
ания процедур и функций}
{Описexports //Перечень экспортируемых процедур и функций
begin
{Секция инициализации}
end.
Создание DLL
Для создания DLL необходимо выполнить действия:
В результате появится файл с расширением .dll, для использования которого нужна запускающая программа.
Далее приведена заготовка DLL.
Library MathLib;
uses
SysUtils, Classes;
{$R *.RES}
begin
end.
В примере 1 реализована простейшая библиотека MathLib, содержащая три функции. Процедуры и функции, которые будут вызываться из библиотеки другими приложениями, могут быть объявлены с ключевым словом stdcall или export. Директива stdcall означает, что при компиляции надо использовать стандартное соглашение о вызове процедур и функций. Это позволит обращаться к подпрограммам из приложений, написанных на других языках программирования. Ключевое слово export указывает компилятору на необходимость создания специального пролога и эпилога для таких функций – они называются экспортируемыми.
В теле DLL могут быть объявлены константы, типы, переменные, процедуры и функции, но экспортировать она может только процедуры и функции.
Пример 1. Библиотека MathLib. Статический импорт
Библиотека
library MathLib;
uses
SysUtils,
Classes;
function Min(x,y:integer):integer;
begin
if x<y then Min:=x else Min:=y;
end;
function Max(x,y:integer):integer; stdcall;
begin
if x>y then Max:=x else Max:=y;
end;
function Mean(x,y:integer):extended; export;
begin
Mean:=(x+y)/2;
end;
exports Min, Max, Mean;
begin
end.
Способы экспорта
Каждая экспортируемая из DLL подпрограмма может идентифицироваться двумя уникальными ключами: числовым индексом (index) и строковым именем (name). Индекс – это целое положительное число в диапазоне от 1 до 32767. Имя представляет собой последовательность символов, в которой строчные и прописные буквы различаются. Например, секция exports может быть оформлена следующим образом:
exports
Myproc1, //По имени процедуры
Myproc2 name 'MyTest', //По новому имени
Myproc3 index 3, //По номеру
Myfunc4 index 4 name 'MaxInt', //По номеру и новому имени
Myfunc5 index 5 name 'MinInt' resident;
//По номеру и резидентному новому имени
Использование нового имени или индекса является необязательным, но в некоторых случаях очень полезно. Например, при вызове из DLL функции с именем, недопустимым по правилам языка Pascal. Если имя или индекс не заданы, то компилятор в качестве индекса назначает порядковый номер, а в качестве имени – имя процедуры или функции. Если индекс не задан, то при импортировании можно использовать только имя. Для вызова подпрограммы по индексу его надо задавать явно.
Для хранения имён экспортируемых подпрограмм в dll-файлах предусмотрены специальные таблицы. Если к имени экспортируемой подпрограммы в секции exports добавлено ключевое слово resident, то компилятор помещает его в таблицу резидентных имён, в противном случае – в таблицу нерезидентных имён. Таблица резидентных имён всегда загружается в оперативную память вместе с программным кодом DLL и остаётся там вплоть до выгрузки библиотеки. Резидентные процедуры и функции отыскиваются быстрее.
Использование DLL
Для того чтобы процедуры и функции DLL стали доступны прикладной программе, они должны быть импортированы. Различают два способа доступа:
Статический импорт применяют чаще, так как он удобнее и проще в реализации. Однако достоинства DLL в полной мере проявляются при использовании динамического импорта.
Статический импорт
В текст приложения в интерфейсную секцию помещают external-объявления подпрограмм DLL, которые предполагается вызывать:
В примере 1 объявлены
функции Max, Min и Mean из библиотеки Mathlib. После
этого объявленные функции
Приложение
unit Unit1;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
function Max(x,y:integer):integer; stdcall; external 'Mathlib';
function Min(x,y:integer):integer; external 'Mathlib';
function Mean(x,y:integer):extended; external 'Mathlib';
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
Edit5: TEdit;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var a,b:integer;
begin
a:=strtoint(edit1.text);
b:=strtoint(edit2.text);
edit3.text:=inttostr(max(a,b))
edit4.text:=inttostr(min(a,b))
edit5.text:=floattostr(mean(a,
end;
end.
Интерфейсный модуль
Доступ к данным dll-библиотеки
принято осуществлять с использованием
процедурного интерфейса, то есть с
помощью специальных
Примеры 2 и 3 поясняют работу с библиотекой Beeper, содержащей единственную процедуру BeepMe. При вызове этой процедуры компьютер подаёт звуковой сигнал. В примере 2 используется статический импорт без интерфейсного модуля.