Автор: Пользователь скрыл имя, 03 Ноября 2012 в 08:04, практическая работа
Практическая работа №9.
Создание и использование DLL в Delphi. DLL Wizard. Создание форм в DLL
Пример 2. Библиотека Beeper. Статический импорт
Библиотека
library Beeper;
uses Windows;
procedure BeepMe; stdcall;
begin
MessageBeep (0);
end;
Exports
BeepMe index 1 name 'BeepMe';
begin
end.
Приложение
unit SoundForm;
interface
uses
Windows, Dialogs, Messages, SysUtils, Classes, Graphics, Controls, Forms, StdCtrls;
procedure BeepMe; stdcall; external 'Beeper';
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
BeepMe;
end;
end.
program Sound;
uses
Forms,
SoundForm in 'SoundForm.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
В примере 3 приведён интерфейсный модуль SoundUnit, в котором определены три разных варианта вызова процедуры BeepMe из Beeper.dll: по имени, по имени в библиотеке и по номеру. Кроме того, показано, что в приложении процедуре можно давать другое имя (BeepMeTwo, BeepMeThree).
Пример 3. Библиотека Beeper. Статический импорт с интерфейсным модулем
Приложение
unit SoundUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
procedure BeepMe; external 'Beeper';
procedure BeepMeTwo; external 'Beeper' name 'BeepMe';
procedure BeepMeThree; external 'Beeper' index 1;
type
TForm3 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
procedure Button3Click(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form3: TForm3;
implementation
{$R *.dfm}
procedure TForm3.Button3Click(Sender: TObject);
begin
BeepMeThree;
end;
procedure TForm3.Button1Click(Sender: TObject);
begin
BeepMe;
end;
procedure TForm3.Button2Click(Sender: TObject);
begin
BeepMeTwo;
end;
end.
program SoundUnitForm;
uses
Forms,
SoundUnit in 'SoundUnit.pas' {Form3};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm3, Form3);
Application.Run;
end.
Динамический импорт
Для организации динамического импорта надо программно задать действия, которые при статическом импорте выполняет загрузчик DLL. Действия выполняются через функции Windows в следующем порядке:
Динамический импорт
менее удобен и требует существенно
больших усилий при реализации. Но
есть и достоинства: более эффективно используется память;
программа получает полный контроль над
подключением DLL-библиотек. Например, если
окажется, что вызываемая подпрограмма
отсутствует, то есть возможность обработать
ошибку и принять соответствующее решение.
Более того, обеспечивается возможность
организации работы с библиотекой, которой
не существует на момент компиляции приложения.
Загрузка DLL выполняется функцией: LoadLibrary(LibFileName:PChar)
где LibFileName – строка, содержащая имя библиотеки. Если загрузить библиотеку не удалось, то функция возвращает код ошибки – число в диапазоне от 0 до 32.
При завершении работы с библиотекой используется функция
FreeLibrary(LibModule: HModule):Boolean;
где LibModule – дескриптор DLL-библиотеки, возвращённый функцией LoadLibrary.
Таким образом, при работе
с библиотекой потребуется
GetProcAddress(Module: HModule; ProcName:PChar):Pointer;
где Module – дескриптор загруженного dll-модуля;
ProcName – имя или целочисленный индекс подпрограммы, экспортируемой библиотекой.
Если подпрограмма вызывается по имени, то в параметре ProcName передаётся указатель на нуль-терминальную строку, содержащую имя подпрограммы. Если используется номер, то в двух младших байтах ProcName передаётся индекс, а старшие два байта должны быть равны нулю.
Результат – указатель на точку входа в экспортируемую подпрограмму. Если при вызове по имени окажется, что подпрограммы не существует, то будет возвращено nil. Если же используется индекс, то при отсутствии подпрограммы nil не возвращается, поэтому надёжнее пользоваться именем.
В примере 4 реализован динамический импорт функции Min из библиотеки MathLib.dll. Для работы с адресом функции объявлен процедурный тип TMin и переменная Min этого типа:
type TMin = function (X, Y: Integer): Integer;
Var Min: TMin;
В дальнейшем переменной Min присваивается значение адреса, возвращаемого функцией GetProcAddress. Оперция @ означает получение адреса:
@Min := GetProcAddress(LibHandle, 'Min');
Пример 4. Библиотека MathLib. Динамический импорт
Приложение
unit DinMath2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
type
TMin = function (X, Y: Integer): Integer;
var
LibHandle: HModule; { handle of the loaded DLL }
Min: TMin; { pointer to the Min function }
a,b:integer;
begin
LibHandle := LoadLibrary('MathLib.dll');
if LibHandle < 32 then
begin
ShowMessage('Could not load DLL.');
Halt;
end;
@Min := GetProcAddress(LibHandle, 'Min');
if @Min = nil then
begin
FreeLibrary(LibHandle);
ShowMessage('Could not link to procedure in DLL.');
Halt;
end;
a:=strToInt(edit1.text);
b:=strToInt(edit2.text);
edit3.text:=intToStr(min(a,b))
FreeLibrary(LibHandle);
end;
end.
Многомодульные библиотеки
Ранее были рассмотрены приёмы создания простейших DLL. Реальные библиотеки часто являются многомодульными.
В этом случае файл проекта dll-библиотеки должен содержать раздел uses, подключающий все необходимые модули, раздел exports и операторный блок Begin ... end, инициализирующий библиотеку. При этом каждый модуль может иметь секции initialization и finalization.
Последовательность создания многомодульной библиотеки:
При необходимости пункты 2-4 повторить требуемое число раз. В результате появится файл библиотеки с расширением .dll.
Создание форм в DLL
Примером многомодульной библиотеки является DLL, содержащая форму. Особенность такой библиотеки заключается в том, что необходимо предусмотреть команды для создания, отображения и уничтожения формы.
Воспользуемся приведённым в предыдущем разделе сценарием для создания DLL с формой. В библиотеку поместим процедуру, которая будет генерировать форму и строить на ней диаграмму по полученным данным. Затем создадим приложение, вызывающее разработанную процедуру.
Этап 1. Создание библиотеки
С помощью команды File|New сформируем заготовку проекта библиотеки.
Добавим в проект форму.
Сохраним заготовку проекта библиотеки под именем MyLib.dpr, а модуль формы – под именем fmGraph.pas. В разделе uses библиотеки MyLib появится ссылка на модуль формы: fmGraph in 'fmGraph.pas' {Form1};
Поместим на форму нужные компоненты, в частности, Chart и зададим значения свойств.
Объявим в секции interface экспортируемую процедуру drawchart с директивой export:
procedure drawchart(Handle:tHandle; a,b,c,d:integer); export;
В разделе implementation сформируем текст процедуры drawchart:
Application.Handle:=Handle;
Form1:=TForm1.Create(
В файле библиотеки MyLib.dpr сформируем раздел exports и зададим способ экспорта drawchart. Например, exports drawchart index 1;
Сохраним доработанные файлы MyLib.dpr и fmGraph.pas.
Откомпилируем библиотеку командой Project|Build All.
Для проверки работоспособности библиотеки надо создать демонстрационную программу, которая будет использовать функцию drawchart.
Этап 2. Создание приложения
Начнём создание нового приложения.
Разместим на форме нужные элементы (например четыре однострочных редактора для ввода данных и кнопку) и зададим их свойства.
Сохраним проект под именем Demo.dpr, а модуль формы – под именем fmDemo.pas.
Впишем в секцию implementation сведения о нужной процедуре и правила её вызова:
procedure drawchart(Handle:tHandle; a,b,c,d:integer); external 'mylib' index 1;
Запишем обработчик для кнопки. Предусмотрим в нём вызов процедуры из DLL: drawchart(Handle,a,b,c,d);
Сохраним изменённые файлы.
Командой Run запустим проект на компиляцию и выполнение.
Полные тексты библиотеки и приложения приведены в примере 5.
Пример 5. Библиотека, использующая форму
Библиотека
library MyLib;
uses
SysUtils,
Classes,
fmGraph in 'fmGraph.pas' {Form1};
exports
drawchart index 1;
begin
end.
unit fmGraph;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, TeeProcs, TeEngine, Chart, Series;
type
TForm1 = class(TForm)
Chart1: TChart;
Series1: TBarSeries;
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
procedure drawchart(Handle:tHandle; a,b,c,d:integer); export;
implementation
{$R *.dfm}
procedure drawchart(Handle:tHandle; a,b,c,d:integer);
begin
Application.Handle:=Handle;
Form1:=TForm1.Create(
Form1.Series1.AddBar(a,'',
Form1.Series1.AddBar(b,'',
Form1.Series1.AddBar(c,'',
Form1.Series1.AddBar(d,'',
Form1.ShowModal;
Form1.Free;
end;
end.
Приложение
unit Demo;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
procedure drawchart(Handle:tHandle; a,b,c,d:integer); external 'mylib' index 1;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var a,b,c,d:integer;
begin
a:=strtoint(edit1.text);
b:=strtoint(edit2.text);
c:=strtoint(edit3.text);
d:=strtoint(edit4.text);
drawchart(Handle,a,b,c,d);
end;
end.
ВОПРОСЫ ДЛЯ САМОКОНТРОЛЯ
Источник Культин ?