Исползование Dll

Автор: Пользователь скрыл имя, 03 Ноября 2012 в 08:04, практическая работа

Описание работы

Практическая работа №9.
Создание и использование DLL в Delphi. DLL Wizard. Создание форм в DLL

Работа содержит 1 файл

Прак работа 9_DLL_К.doc

— 149.50 Кб (Скачать)

 

 

Пример 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;
  • • использование адресов для вызова процедур и функций;
  • • освобождение библиотеки.
  • Динамический импорт менее удобен и требует существенно  больших усилий при реализации. Но есть и достоинства: более эффективно используется память; программа получает полный контроль над подключением DLL-библиотек. Например, если окажется, что вызываемая подпрограмма отсутствует, то есть возможность обработать ошибку и принять соответствующее решение. Более того, обеспечивается возможность организации работы с библиотекой, которой не существует на момент компиляции приложения. Загрузка DLL выполняется функцией: LoadLibrary(LibFileName:PChar):HModule;

    где LibFileName – строка, содержащая имя библиотеки. Если загрузить библиотеку не удалось, то функция возвращает код  ошибки – число в диапазоне  от 0 до 32.

    При завершении работы с  библиотекой используется функция

    FreeLibrary(LibModule: HModule):Boolean;

    где LibModule – дескриптор DLL-библиотеки, возвращённый функцией LoadLibrary.

    Таким образом, при работе с библиотекой потребуется переменная типа HModule для хранения дескриптора  библиотек. После загрузки DLL можно воспользоваться функцией:

    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.

    Последовательность создания многомодульной библиотеки:

  • 1) выполнить команду File|New и выбрать DLL для получения заготовки проекта библиотеки;
  • 2) выполнить команду File|New, выбрать Unit для создания нового модуля;
  • 3) сохранить заготовки под нужными именами; 
  • 4) наполнить модуль содержанием: объявить и сформировать процедуры и функции (в интерфейсной секции выполнить объявления, а в секции implementation – записать тексты соответствующих подпрограмм);
  • 5) в файле проекта создать секцию exports; выбрать определённый способ распознавания подпрограмм (по имени или по индексу);
  • 6) сохранить модуль и проект;
  • 7) скомпилировать проект командой Project|Build All.
  • При необходимости пункты 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(Application);

      • построим диаграмму;
      • выведем на экран форму в модальном режиме командой Form1.ShowModal;
      • разрушим форму после её закрытия командой Form1.Free;

     

    В файле библиотеки 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(Application);

    Form1.Series1.AddBar(a,'',clteecolor);

    Form1.Series1.AddBar(b,'',clteecolor);

    Form1.Series1.AddBar(c,'',clteecolor);

    Form1.Series1.AddBar(d,'',clteecolor);

    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.

     

     

     

    ВОПРОСЫ ДЛЯ САМОКОНТРОЛЯ

  • 1. Чем объясняется широкое использование DLL?
  • 2. Какую структуру имеет DLL?
  • 3. Что и как записывается в секции exports?
  • 4. Может ли имя процедуры в вызывающем приложении не совпадать с именем процедуры в библиотеке?
  • 5. По какому признаку компилятор определяет, что код процедуры расположен вне приложения?
  • 6. В чём принципиальное отличие динамического импорта от статического?
  •  

    Источник Культин ?




    Информация о работе Исползование Dll