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

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

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

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

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

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

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

Практическая работа №9.

Создание и  использование  DLL в Delphi. DLL Wizard. Создание форм в DLL

 

Основные понятия 

DLL – Dynamic Link Library – это разновидность исполняемых файлов Windows. Файл, в котором располагается динамическая библиотека, обычно имеет расширение .dll, но может быть и другое, например, .exe.

Динамически подключаемая библиотека представляет собой выполняемый  модуль, код и ресурсы которого могут использоваться другими динамическими  библиотеками и приложениями. DLL-библиотека подключается в период выполнения приложения, её код не копируется в исполняемые файлы программ (в отличие от обычных библиотечных модулей, которые подсоединяются на этапе компоновки). Достоинства:

  • • не увеличивает объём кода приложений;
  • • одним экземпляром DLL могут совместно пользоваться несколько прикладных программ;
  • • подключение библиотеки происходит динамически (runtime);
  • • DLL можно обновлять не меняя приложений, использующий эту библиотеку, при условии сохранения интерфейса вызова её функций;
  • • поддерживают многоязыковые проекты, то есть можно использовать библиотеки, написанные на других языках программирования.
  • Итак, основные достоинства  – это гибкость и экономия памяти и дискового пространства. Компоновка обычных модулей Delphi выполняется  статически, то есть во время компиляции, копия кода всех используемых модулей помещается в exe-файл. Это приводит к тому, что программы, использующие один и тот же модуль, будут содержать большое количество повторяющегося кода. При одновременном запуске таких программ код будет дублироваться в памяти.

    В некоторых случаях  основная причина использования DLL заключается в гибкости создаваемого приложения. Например, при создании текстового редактора невозможно предусмотреть  форматы файлов, которые появятся в  будущем. Однако разрабатываемое приложение должно быть приспособлено к работе с новыми версиями форматов. При использовании динамических библиотек поддержка нового формата сводится к написанию DLL и распространению её среди пользователей, которым она может потребоваться. В этом случае в exe-файл включается инструкция о том, где программа должна искать необходимый код.

    Динамические библиотеки могут экспортировать только процедуры  и функции. Описанные в них  типы, константы, массивы и другие языковые конструкции предназначены исключительно для внутреннего использования. В DLL рекомендуется помещать процедуры и функции, реализующие дополнительные возможности программы.

    Как и любая программа DLL компилируется совместно с  модулем System, что позволяет определить ссылку на экземпляр DLL через переменную HInstance и передать ссылку тем функциям, которые ожидают её в качестве параметра. При обращении к DLL включается счётчик (Hprevinst) и при каждом новом обращении счетчик увеличивается на единицу. DLL не выгружается из памяти до тех пор, пока значение счётчика не станет равным нулю.

    Проблем с поиском DLL не возникает, если DLL и исполняемый  файл программы располагаются в  одном каталоге. Если программы, использующие DLL, находятся в разных каталогах, то целесообразно поместить DLL в каталог, просматриваемый Windows по умолчанию при загрузке DLL. Windows ищет DLL в следующих местах и в следующем порядке:

  • • каталог, из которого было загружено приложение;
  • • текущий каталог;
  • • системный каталог Windows;
  • • только для Windows NT: системный каталог 16-разрядной Windows;
  • • каталог Windows;
  • • каталоги, перечисленные в переменной окружения PATH.
  • В случае динамического  импорта при вызове LoadLibrary можно  указать для DLL полный путь, тогда Windows просмотрит только заданный каталог. При статическом импорте такой возможности нет. Основной недостаток DLL – это отсутствие проверки типов. Обращаясь к функции, фактически даём указание компилятору вызвать функцию, о которой он ничего не знает. Если будет указано неверное количество параметров или параметры будут неверных типов, то вызов функции может привести к непредсказуемым последствиям. Найти подобную ошибку очень сложно.

    Изучение DLL предусматривает рассмотрение двух вопросов: создание библиотеки и  её использование.

     

    Структура DLL

    По своей сути DLL похожи на модули, но их код больше напоминает программы. По функциональному назначению и модуль и DLL представляют собой библиотеки подпрограмм, но организованы они по-разному. Динамические библиотеки – это особая разновидность программ, предоставляющих код или данные другим программам. DLL имеет обязательный заголовок, который начинается со служебного слова library.

    Процедуры и функции  записываются так же, как принято  в программах, но их необходимо явным  образом экспортировать, чтобы они стали доступны другим программам или динамическим библиотекам. Для этого вводится секция exports, в которой перечисляются экспортируемые библиотекой процедуры и функции. В качестве разделителя при перечислении используется запятая, завершается секция exports точкой с запятой. В DLL может быть несколько секций exports. Обязательно включается секция инициализации, которая, однако, может быть пустой. Шаблон DLL приведён ниже.

    library MyDll;

    uses //Перечень подключаемых модулей

    ания процедур и функций}

    {Описexports //Перечень экспортируемых процедур и функций

    begin

    {Секция инициализации} 

    end.

     

    Создание DLL

    Для создания DLL необходимо выполнить действия:

  • • командой File|New|Other открыть диалоговое окно New Items и на вкладке New выбрать DLL Wizard;
  • • в появившейся заготовке DLL целесообразно (но не обязательно) убрать лишние строки (директиву компилятору и комментарий);
  • • присвоить библиотеке имя и сохранить её в файле .dpr под тем же именем, что записано после слова library;
  • • описать необходимые процедуры и функции;
  • • перед блоком begin … end добавить секцию exports, в которой перечислить экспортируемые процедуры и функции;
  • • сохранить внесённые изменения и откомпилировать DLL командой Project|Compile.
  • В результате появится файл с расширением .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 стали доступны прикладной программе, они должны быть импортированы. Различают два способа доступа:

  • • статический импорт – с помощью директивы компилятора external;
  • • динамический импорт – с использованием функций ядра Windows: LoadLibrary, FreeLibrary и GetProcAddress.
  • Статический импорт применяют  чаще, так как он удобнее и проще  в реализации. Однако достоинства DLL в полной мере проявляются при использовании динамического импорта.

     

    Статический импорт

    В текст приложения в  интерфейсную секцию помещают external-объявления подпрограмм DLL, которые предполагается вызывать:

  • • записывают ключевое слово procedure или function;
  • • указывают название подпрограммы;
  • • добавляют служебное слово external, сообщающее компилятору, что код подпрограммы расположен вне программы или модуля;
  • • записывают строку, задающую имя библиотеки, в которой находится процедура или функция;
  • • при необходимости вводят идентификатор index и уникальный номер или идентификатор name и новое имя, позволяющие однозначно определить подпрограмму в библиотеке.
  • В примере 1 объявлены  функции Max, Min и Mean из библиотеки Mathlib. После  этого объявленные функции можно  использовать так, как будто они являются частью программы. Рассмотренный пример является простейшим способом импорта подпрограмм из DLL, так как помимо собственно имени подпрограммы её можно импортировать по номеру и имени в библиотеке. Если подпрограмма в библиотеке была объявлена с модификатором stdcall, то при организации импорта надо добавить этот модификатор.

    Приложение

    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,b));

    end;

     

    end.

     

     

     

    Интерфейсный  модуль

    Доступ к данным dll-библиотеки принято осуществлять с использованием процедурного интерфейса, то есть с  помощью специальных интерфейсных модулей. При создании интерфейсного  модуля (модуля импорта) рекомендуется  следующая последовательность действий:

  • • открыть файл проекта, в котором надо организовать вызов процедур или функций из динамической библиотеки;
  • • создать модуль импорта. Для этого выполнить команду File|New и в открывшемся окне выбрать Unit. В файле проекта в разделе Uses появится ссылка на созданный модуль;
  • • в секцию interface модуля импорта внести описания, указывающие компилятору формат вызова процедур и функций;
  • • сохранить модуль импорта в файле.
  • Примеры 2 и 3 поясняют работу с библиотекой Beeper, содержащей единственную процедуру BeepMe. При вызове этой процедуры компьютер подаёт звуковой сигнал. В примере 2 используется статический импорт без интерфейсного модуля.

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