logo
Posobie_Ravino_Atamanov

2.5.5.4. Динамически подключаемые библиотеки

Динамически подключаемые библиотеки (dllDynamic Link Library) являются ключевым компонентом при написании любого современного приложения Windows. Они представляют собой программные модули, содержащие процедуры и функции, данные или ресурсы, которые могут совместно использоваться несколькими различными приложениями Windows. Одно из основных и, пожалуй, главных назначений библиотек dll ‑ позволить загружать процедуры и функции в память только в случае необходимости во время выполнения приложения, а не компилировать их в само приложение и таким образом загружать в память всякий раз при запуске, независимо от того понадобятся они либо нет. Кроме того, несколько приложений могут использовать одни и те же процедуры и функции, хранящиеся в dll, одновременно. И самое главное, библиотеки dll являются универсальными относительно языка программирования, то есть dll может быть написана на языке C++, а само приложение, использующее библиотеку — на Delphi.

Таким образом, преимущества динамически подключаемых библиотек:

1. Универсальность. Любой программист, зная описания и имена функций, находящихся в библиотеке, может использовать их. При этом ему совсем не обязательно знать, как работают эти функции. Главное ‑ результат.

2. Удобность отладки. Можно разместить несколько важных функций в библиотеке и объявить их в программе. При этом программист будет работать с библиотекой, отлаживая эти функций, не трогая основную программу.

3. Хранилища ресурсов. В dll можно хранить ресурсы, такие как рисунки, формы, иконки меню, и т.д.

4. Модульность и расширение. С помощью библиотек можно легко создавать плагины, расширяющие стандартные возможности программы. Т.е. можно не выпускать различные версии программы, а выпускать плагины или модифицированные (например, с исправленными ошибками) версии библиотек.

5. Совместное использование. Если библиотека загружена, то её могут использовать и другие приложения.

6. Экономия ресурсов. Библиотеку можно загрузить и выгрузить тогда, когда это действительно необходимо. Например, программа в нужный момент загрузила dll, вызвала функцию, сделала работу и выгрузила библиотеку до следующего раза.

Создание динамически подключаемой библиотеки. Для создания новой динамической библиотеки нужно выбрать из меню File пункт New и затем Other. В окне создания нового проекта (рисунок 8) нужно выбрать на закладке New пункт DLL Wizard.

Рисунок 8 ‑ Окно создания нового проекта dll.

В результате будет создан пустой проект с одним только модулем, содержащим следующий текст:

library Project2;

uses

SysUtils,

Classes;

{$R *.res}

begin

end.

Сохранить созданный проект необходимо в отдельную папку, присвоив (желательно) осмысленное имя. Для этого необходимо выбрать из меню File пункт Save All, и будет предложено сохранить только один проект и никаких модулей. Указанное имя проекта буде присвоено откомпилированному dll файлу. Например, если имя проекта Tractor.dpr, то библиотека будет иметь имя Tractor.dll.

Теперь нужно добавить в библиотеку необходимое количество функций. В приведенном ниже примере добавляется функция с именем Radius.

library Tractor;

uses

SysUtils,

Classes;

Function Radius(V,deltaV,B:Real):Real; stdcall;

begin

Radius:=(V/deltaV)*0.5*B;

end;

exports Radius index 10;

{$R *.res}

begin

end.

Ключевое слово StdCall, которое стоит после типа возвращаемого функцией значения, говорит о том, что для вызова процедуры нужно использовать стандартный тип вызова. Если не указать ключевое слово StdCall, то параметры будут передаваться способом, заложенным фирмой Borland. Этот способ работает быстрее, но он не совместим со стандартными правилами. Это означает, что если к библиотеке будут обращаться программы сторонних разработчиков, например на языках Visual C++ или других то будут проблемы.

После описания функции идёт ключевое слово exports. За ним должны идти описания подпрограмм, которые должны быть доступны внешним программам. Если функцию Radius не описать в разделе exports, то её будет невозможно вызвать из внешней программы.

После имени функции может стоять ключевое слово index с числом. Данный индекс не является обязательным, в этом случае вызов подпрограммы будет осуществляться по ее имени. Однако когда программе нужно будет выполнить функцию Radius, то она будет просматривать все функции динамической библиотеки и искать функцию с указанным именем. Это очень неэффективно и перед первым вызовом будет ощущаться большая задержка. Чтобы хоть немного ускорить процесс вызова таких функций желательно использовать индексы. В качестве которого выступает целое число в диапазоне от 0 до 32767. Индексы и имена должны быть уникальными!

Теперь необходимо откомпилировать (а не запустить) проект (Ctrl+F9 или выбрать команду Compile из меню Project). В результате будет создана динамическая библиотека Tractor.dll.

Не нужно пытаться запускать проект, потому что это библиотека, и она не может выполняться самостоятельно. Поэтому при попытке запуска появится сообщение об ошибке (рисунок 9):

Рисунок 9 – Сообщение компилятора при попытке запуска проекта dll-библиотеки

Использование динамически подключаемой библиотеки. Связать функцию из dll-библиотеки с приложением можно двумя методами: статической и динамической загрузки. Рассмотрим способом статической загрузки как наиболее простой и легкий в использовании метод, не требующий от программиста знания WinAPI. Однако у этого способа имеется и ряд недостатков. В частности, библиотека загружается при запуске приложения и выгружается при завершении, таким образом, нет экономии ресурсов; при отсутствии хотя бы одной из необходимых библиотек, или подпрограмм в библиотеке, дальнейшее выполнение приложения не представляется возможным.

Для использования функций или процедур из библиотеки необходимо в разделе implementation в программном модуле приложения дать ссылку на соответствующую подпрограмму. Фрагмент кода приведен ниже:

implementation

function Radius(V,deltaV,B:Real):Real; external 'Tractor.dll' index 10;

{$R *.dfm}

В данном примере приведено ключевое слово external после которого следует имя подключаемой dll библиотеки. Желательно, чтобы сама библиотека располагалась в том же каталоге, что и основная программа. Теперь функцию можно использовать в программе.