Тема ?. Использование библиотек DLL. Файл 446966401 С. 1 из 9 Тема ?. Использование динамически подключаемых библиотек (DLL, Dynamic Link Library) 1. Общие положения 1.1. Суть библиотек DLL 1.2. Создание и использование библиотек DLL в среде Delphi 1.3. DLL и разработка интерфейса 2. Пример использования DLL 2.1. Разработка процедуры, заносимой в библиотеку 2.2. Структура и содержание библиотеки 2.3. Использование библиотеки в консольном варианте приложения 2.4. Использование библиотеки в варианте с графическим интерфейсом 1. Общие положения 1.1. Суть библиотек DLL Динамически подключаемые библиотеки, или DLL – средство автономного хранения программного кода (как правило, процедур) и ресурсов (например, форм). Это самый простой способ реализации автономности компонентов приложения (за счет вынесения их в библиотеку) и предоставления в общее пользование готовых компонентов. Это общие преимущества, предоставляемые любыми программными библиотеками. Их следствиями являются: - улучшение структуры и наглядности приложения за счет уменьшения длины кода (замены фрагмента кода вызовом библиотечной процедуры); - улучшение модифицируемости приложения за счет возможности модификации кода, вынесенного в библиотеку, без изменения основной части приложения; - накопление результатов труда программистов. Библиотеки DLL оформляются как файлы с расширением .dll. В среде Delphi библиотеки по структуре схожи с библиотеками подпрограмм в языках программирования типа Фортран, C и C++. Размещаются библиотеки с расчетом на удобство использования: либо в текущем каталоге приложения (там, где расположен .exe-файл приложения), либо в системных каталогах Windows (стандартно – в Windows\System32). Если одна и та же библиотека используется несколькими приложениями, то она копируется в текущий каталог каждого из приложений. Библиотека подключается к приложению динамически, т.е. после его запуска, а не при компиляции. Основной вариант поиска библиотеки – сначала в текущем каталоге, затем в каталоге Windows\System32. В зависимости от настройки ОС при отсутствии библиотеки в указанных каталогах приложение может просто не работать, может производиться поиск в других каталогах либо выдаваться запрос на выбор библиотеки. Мы рассмотрим вариант включения в библиотеку только процедур и функций. 1.2. Создание и использование библиотек DLL в среде Delphi Создание библиотеки DLL •• Выполнить команду File/New/Other/DLL Wizard. Создается пустая заготовка файла проекта библиотеки. Модуль библиотеки инициируется ключевым словом library со стандартным именем: library Project2; uses SysUtils, Classes; {$R *.res} begin Тема ?. Использование библиотек DLL. Файл 446966401 С. 2 из 9 end. •• Файлы и модули библиотек именуются по тем же правилам, что и модули Unit: имя модуля должно совпадать с именем файла, где этот модуль сохраняется. Это надо учитывать при переименовании библиотеки, т.е. сохранении ее под желаемым именем. •• В раздел описаний вставить описания констант и типов, глобальных для процедур библиотеки. В раздел процедур вставить описания процедур. Добавить раздел экспортируемых процедур: exports <список имен процедур>; Получится следующее: library <имя библиотеки>; uses SysUtils, Classes; {$R *.res} < описания констант и типов, глобальных для процедур > < описания процедур > // раздел экспортируемых процедур exports <список имен процедур>; begin end. •• Сохранить проект библиотеки •• Скомпилировать проект библиотеки. Результат – файл <имя библиотеки>.dll •• Для изменения библиотеки (коррекции, добавления процедур) следует открыть проект, внести изменения, скомпилировать проект. Подключение библиотеки DLL •• В программе, использующей библиотеку, в разделе описаний должны содержаться описания констант и типов, глобальных для процедур – такие же, как в библиотеке. •• В разделе описания процедур программы каждая из процедур библиотеки описывается как импортируемая, или внешняя: <заголовок процедуры>; external ‘<имя библиотеки>.dll’ 1.3. DLL и разработка интерфейса Здесь представляет интерес ситуация, когда некоторое приложение едино с точки зрения выполняемых функций, но должно иметь различные интерфейсы в различных использованиях (например, для разных классов пользователей). В таком случае должна быть обеспечена относительная автономность разработки компонентов, реализующих интерфейс, и интерфейсно-независимых компонентов, выполняющих обработку данных – «движок». Последний может быть занесен в библиотеку, и тогда по сути различные приложения могут использовать единую общую часть. Такое разделение просто только на первый взгляд; это довольно нетривиальная задача уже в обычном программировании. Если же разные интерфейсы создаются с помощью инструментов разного уровня (например, средствами языка программирования и интегрированными визуальными средствами разработки приложений), то картина становится с ног на голову: различия в реализации в большой степени должны учитываться на уровне проекта. Методы здесь могут быть только эвристическими, а общие принципы остаются теми же, что при проектировании ПО в целом. Возможно, что «одно и то же приложение с разными интерфейсами» для одних задач окажется рациональнее выполнить программно как несколько независимых приложений, для других – с выделением разных интерфейсных и общей обрабатывающей части. Тема ?. Использование библиотек DLL. Файл 446966401 С. 3 из 9 2. Пример использования DLL Полностью два варианта приложения, использующих библиотеку, размещены в прилагаемых каталогах primer_tema3vopr2dll и InterfForTopDown (архивы .rar). Цель приводимого ниже текста – пояснение основных моментов, касающиеся разработки библиотеки. 2.1. Разработка процедуры, заносимой в библиотеку В рамках задания по лабораторной работе № 4 для задачи top_down оформим обработку данных (т.е. собственно решение задачи) в виде процедуры и запишем в библиотеку DLL. Будем базироваться на имеющейся разработке (см. курс «Технология разработки ПО», тема 3, вопрос 2). Здесь на уровне 0 проектирования алгоритма обработка совмещена с выводом результатов и представлена абстракцией А0.3: ....................... {решение задачи} {вх.: n, b, m, a; вых.: a или maxmin} А0.3. <решение задачи с выводом результатов по обр 3> ....................... Чтобы процедура решения была пригодна для использования во всех вариантах приложения (т.е. вариантах с разными интерфейсами), из нее следует убрать ввод-вывод. Задача имеет три варианта решения, или три вида результатов, каждому из которых соответствует своя форма (см. уровень 1, задача А0.3): Обр 3.1 Результаты Обр 3.2.1 Измененная матрица: Обр 3.2.2 (совпадает с обр 2.4) Обр 3.2.3 Обр 3.2.4 <a(1,1)> <a(1,2)> . . . <a(1,n)> ........ 1-й вариант решения <a(m,1)> <a(m,2)> . . . <a(m,n)> В массиве b есть одинаковые элементы, но матрица не содержит строки со всеми положительными элементами и не меняется Максимальное значение минимумов строк матрицы = < maxmin > 2-й вариант 3-й вариант Разделить обработку и вывод можно так: помимо входных и выходных данных задачи, включим в состав параметров процедуры дополнительный параметр, соответствующий варианту решения. В зависимости от значения этого параметра после вызова процедуры будет выводиться соответствующий вариант результатов. Тогда абстракция A0.3 уровня 0 детализируется следующим образом: A0.3a <Решение задачи с фиксацией варианта решения> A0.3b <Анализ варианта решения и вывод по соответствующему образцу> Разработка процедуры для задачи А0.3a выполняется обычным образом и приведена ниже. 1. Задача А0.3a Если в одномерном целочисленном массиве b есть хотя бы два одинаковых элемента, то заменить первую строку матрицы a , все элементы которой больше нуля, на этот массив, иначе найти максимальное значение минимальных элементов строк матрицы. 2. Входные данные цел n - число элементов массива b; число столбцов матрицы a; простая переменная; цел m - число строк матрицы a; простая переменная; цел b - исходный одномерный массив; цел a - исходная матрица; двумерный массив. Данные во внутреннем представлении (так как к моменту решения задачи А0.1 они введены); входная форма отсутствует. 3. Выходные данные цел a - измененная матрица; цел maxmin - максимальное значение минимальных элементов строк; простая переменная. Тема ?. Использование библиотек DLL. Файл 446966401 С. 4 из 9 цел resvar – вариант решения; resvar = 1, изменение матрицы; 2, поиск максимального значения минимальных элементов строк матрицы; 3, обработка не производится (ситуация, когда в массиве b есть хотя бы два одинаковых элемента, но в матрице нет строки со всеми положительными элементами) Оформление процедуры Вид - общего вида Имя – reshenie Поскольку процедура вызывается один раз, выберем для формальных параметров те же имена, что и для фактических. • Заголовок - проц reshenie (n, m, b,a, maxmin, resvar); Обращение - reshenie (n, m, b,a, maxmin, resvar); • Описание на псевдокоде {поиск строки со всеми положит. элементами в матрице} проц reshenie (n, m, b,a, maxmin, resvar); арг цел n, m; цел b(n), a(m,n); рез цел a(m,n); цел maxmin, resvar; нач <описания локальных переменных> <алгоритм тела процедуры> кон; кон reshenie; Разработка заглушки Алгоритм заглушки (тело процедуры) Для теста 1.1 (в массиве b есть два равных элемента и искомая строка есть): {Измененная матрица} a[1,1]:= -1; a[1,2]:= 0; a[1,3]:=2; a[1,4]:= -3; a[2,1]:= 2; a[2,2]:= -1; a[2,3]:=0; a[2,4]:= 2; a[3,1]:= 1; a[3,2]:= 2; a[3,3]:=3; a[3,4]:= 1; resvar:=1; Для теста 1.2 (в массиве b нет равных элементов): { Максимальное значение минимальных элементов строк матрицы } maxmin:=1; resvar:=2; Для теста 1.3 (в массиве b есть два равных элемента, но искомой строки нет): { Обработка не производится } resvar:=3; Кодирование процедуры на паскале Определение глобальных объектов Глобальный тип и константы для параметров a и b определены при кодировании процедур проверки массивов: const nmax=50; mmax=50; type arrb=array[1..nmax] of integer; arra=array[1..mmax, 1..nmax] of integer; Тема ?. Использование библиотек DLL. Файл 446966401 С. 5 из 9 Описание процедуры procedure reshenie (n,m :integer; var b:arrb; var a:arra; var maxmin: integer; var resvar: byte); var <описания локальных переменных>; begin <операторы> end; Обращение к процедуре: reshenie (n,m, b, a, maxmin, resvar); 2.2. Структура и содержание библиотеки Пусть создаваемая библиотека имеет имя TopDownDLL.dll. Только для консольного варианта с иллюстративной целью в библиотеку внесены еще процедуры проверки массивов. Для корректной локализации описаний файловые переменные выходных файлов, куда записывается диагностика ошибок, включены в список параметров (в исходном варианте процедуры были внутренними, а файловые переменные передавались как глобальные). Текст файла проекта библиотеки TopDownDLL.dpr приведен ниже. library TopDownDLL; uses SysUtils, Classes; {$R *.res} {описания констант и типов, глобальных для процедур} const nmax=50; mmax=50; type arrb=array[1..nmax] of integer; arra=array[1..mmax,1..nmax] of integer; {описания процедур} {проверка массива b} procedure provb(n:integer; var b:arrb; var bver:boolean; var res:text); var i:byte; {локальная величина} begin ....... end; {проверка массива a} procedure prova(m, n:integer; var a:arra; var aver:boolean; var res:text); var i,j:byte; {локальная величина} begin ...... end; {Решение. Вместо обработки заглушки} procedure reshenie (n,m :integer; var b:arrb; var a:arra; var maxmin: integer; var resvar: byte); var {<описания локальных переменных>}; begin ..... end; exports //список экспортируемых функций provb, prova, reshenie; begin end. Тема ?. Использование библиотек DLL. Файл 446966401 С. 6 из 9 2.3. Использование библиотеки в консольном варианте приложения Выделены изменения в программе с комментариями. program top_down (dat, res); {$APPTYPE CONSOLE} uses SysUtils; const nmax=50; mmax=50; type arrb=array[1..nmax] of integer; arra=array[1..mmax,1..nmax] of integer; var n,m, maxmin, i, j :integer; b:arrb; a: arra; nver, mver, bver, aver :boolean; {результаты анализа данных} dat,res:text; resvar:byte; {вариант решения} {проверка массива b: процедура загружается из библиотеки TopDownDLL.dll} procedure provb(n:integer; var b:arrb; var bver:Boolean; var res:text); external 'TopDownDLL.dll'; {проверка массива a: процедура загружается из библиотеки TopDownDLL.dll} procedure prova(m, n:integer; var a:arra; var aver:Boolean; var res:text); external 'TopDownDLL.dll'; { Решение задачи с фиксацией варианта решения } procedure reshenie (n,m :integer; var b:arrb; var a:arra; var maxmin: integer; var resvar: byte); external 'TopDownDLL.dll'; begin { TODO -oUser -cConsole Main : Insert code here } assign (dat,paramstr(1)); reset(dat); assign (res,paramstr(2)); rewrite(res); {вывод по обр1} writeln(res,' Задача top_down. Обработка матрицы '); {ввод, анализ, входных данных} {проверка n} readln(dat,n); writeln(res,' Исходный массив b из ', n:2, ' элементов:'); { ввод- вывод n } nver:=true; if (n<=0) or (n>=50) then {n неверно} begin nver:=false; writeln(res,' n задано неверно '); {вывод по обр 4.1} end; if nver {n верно} then begin for i:=1 to n do { ввод(b(i),i=1,n) } read(dat,b[i]); for i:=1 to n do { вывод(b(i),i=1,n) по обр 2.2 } write(res,' ',b[i]:3); writeln(res); { А0.1. проверка массива b} {вх.:n,b; вых.:bver} provb(n,b,bver,res); end; if (nver and bver) then {предыдущие данные верны} begin {ввод(m); вывод(m,n)по обр 2.3} readln(dat,m); writeln(res,' Исходная матрица ', m:2, ' х', n:2, ': '); {проверка m} mver:=true; if (m<=0) or (m>50) then {m неверно} begin mver:=false; writeln(res,' m задано неверно '); {вывод по обр 4.3} end; Тема ?. Использование библиотек DLL. Файл 446966401 С. 7 из 9 end; if (nver and bver and mver) then{предыдущие данные верны} begin { ввод((a(i,j),j=1,n),i=1,m); вывод((a(i,j),j=1,n),i=1,m)по обр 2.4; } for i:=1 to m do begin for j:=1 to n do read(dat, a[i,j]); readln(dat); end; for i:=1 to m do begin for j:=1 to n do write (res,' ',a[i,j]:3); writeln(res); end; {А0.2. проверка массива а} {вх.:m,n,a; вых.: aver} prova(m,n,a,aver,res); end; if (nver and mver and bver and aver) then {все данные верны} begin {A0.3a Решение задачи с фиксацией варианта решения} reshenie (n,m, b, a, maxmin, resvar); writeln (res, ' Результаты'); {A0.3b Анализ варианта решения и вывод по соответствующему образцу} {Заглушки} case resvar of 1: writeln (res, ' Измененная матрица'); 2: writeln (res, ' Максимальное значение минимумов строк матрицы'); 3: writeln (res, ' Матрица не меняется'); end; end else {хотя бы одно данное неверно} writeln(res,' Задача не решалась'); { вывод по обр.4.5; } close(dat); close(res); end. 2.4. Использование библиотеки в варианте с графическим интерфейсом Приводится только часть модуля, вызывающего процедуру решения. unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Grids, Spin; const nmax=50; mmax=50; type TForm1 = class(TForm) SpinEdit1: TSpinEdit; // n - число элементов массива b и столбцов матрицы a StringGrid1: TStringGrid; //таблица для ввода массива b SpinEdit2: TSpinEdit; // m - число строк матрицы a StringGrid2: TStringGrid; //таблица для ввода матрицы a Label1: TLabel; //Заголовок "Число n элементов массива B:" Label2: TLabel; //Заголовок "Исходный массив B из n элементов:" Label3: TLabel; //Заголовок "Число m строк матрицы A" Label4: TLabel; //Заголовок "Исходная матрица A m x n" Label5: TLabel; //Заголовок "Задача top_down. Обработка матрицы" Label6: TLabel; //Сообщение "Число элементов задано неверно!" Label7: TLabel; //Сообщения об ошибочных элементах массива B Button1: TButton; //Кнопка "Решить" Тема ?. Использование библиотек DLL. Файл 446966401 С. 8 из 9 procedure SpinEdit1Change(Sender: TObject); procedure SpinEdit1Exit(Sender: TObject); procedure StringGrid1Exit(Sender: TObject); procedure SpinEdit2Exit(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; arrb=array[1..nmax] of integer; arra=array[1..mmax,1..nmax] of integer; var Form1: TForm1; //Форма для ввода и анализа входных данных implementation uses Unit2; // Unit2 содержит форму для вывода результатов {$R *.dfm} procedure reshenie (n,m :integer; var b:arrb; var a:arra; var maxmin: integer; var resvar: byte); external 'TopDownDLL.dll'; //Ввод и проверка n с выводом сообщения при наличии ошибки procedure TForm1.SpinEdit1Change(Sender: TObject); begin ........ end; //Формирование таблицы для ввода массива b и столбцов таблицы для ввода матрицы a procedure TForm1.SpinEdit1Exit(Sender: TObject); var i:integer; begin ....... end; //Проверка элементов массива b при передаче фокуса ввода следующему компоненту procedure TForm1.StringGrid1Exit(Sender: TObject); var i:byte; begin ........ end; //Формирование таблицы для ввода матрицы a procedure TForm1.SpinEdit2Exit(Sender: TObject); var i,j:integer; begin ............... end; //Решение procedure TForm1.Button1Click(Sender: TObject); var n,m, maxmin, i, j :integer; b: arrb; a: arra; resvar: byte; begin if label7.Visible=false then begin //Вывод входных данных в выходную форму Form2 Тема ?. Использование библиотек DLL. Файл 446966401 С. 9 из 9 ......................... //Преобразование входных данных из строк в числа ............................. //Решение задачи с выводом результатов в Form2 {A0.3a Решение задачи с фиксацией варианта решения} reshenie (n,m, b, a, maxmin, resvar); {A0.3b Анализ варианта и вывод п соотаветствующему образцу} case resvar of 1: Form2.label4.visible:=true; //writeln (res, ' Измененная матрица'); //2: writeln (res, ' Максимальное значение минимумов строк матрицы'); //3: writeln (res, ' Матрица не меняется'); end; Form2.Visible:=true; Form1.Visible:=false; end; end; end.