DELPHISOURCE
Домой | Статьи | Книги | FAQ | Компоненты | Программы |
Архив сайта | Реклама на сайте | Ссылки | Связь |
Использование и создание DLL в Delphi
Введение
В связи с бурным развитием технологий программирования, все больше людей сталкиваются с проблемой наращивания возможностей своих программ. Данная статья посвящена именно этому вопросу, а именно - программирование DLL в Borland Delphi. Кроме того, так как мы затронем вопросы по использованию библиотек DLL, то попутно коснемся импортирования функций из чужих DLL (в том числе и системных, т.е. WinAPI).
Области применения DLL
Итак, зачем же нужны библиотеки DLL и где они используются?.. Перечислим лишь некоторые из областей их применения:
Отдельные библиотеки, содержащие полезные для программистов дополнительные функции. Например, функции для работы со строками, или же - сложные библиотеки для преобразования изображений.
Хранилища ресурсов. В DLL можно хранить не только программы и функции, но и всевозможные ресурсы - иконки, рисунки, строковые массивы, меню, и т.д.
Библиотеки поддержки. В качестве примера можно привести библиотеки таких известных пакетов, как: DirectX, ICQAPI (API для ICQ), OpenGL и т.д.
Части программы. Например, в DLL можно хранить окна программы (формы), и т.п.
Плагины (Plugins). - Вот где настоящий простор для мыслей программиста! Плагины - дополнения к программе, расширяющие ее возможности. Например, в этой статье мы рассмотрим теорию создания плагина для собственной программы.
Разделяемый ресурс. DLL (Dynamic Link Library) может быть использована сразу несколькими программами или процессами (т.н. sharing - разделяемый ресурс)
Краткое описание функций и приемов для работы с DLL
Итак, какие же приемы и функции необходимо использовать, чтобы работать с DLL? Разберем два метода импортирования функций из библиотеки:
1 способ. Привязка DLL к программе. Это наиболее
простой и легкий метод для использования функций, импортируемых из DLL.
Однако (и на это следует обратить внимание) этот способ имеет очень
весомый недостаток - если библиотека, которую использует программа, не
будет найдена, то программа просто не запустится, выдавая ошибку и сообщая
о том, что ресурс DLL не найден. А поиск библиотеки будет вестись: в
текущем каталоге, в каталоге программы, в каталоге WINDOWS\SYSTEM, и
т.д.
Итак, для начала - общая форма этого
приема:
implementation
...
function
FunctionName(Par1: Par1Type; Par2: Par2Type; ...): ReturnType;
stdcall; external 'DLLNAME.DLL' name 'FunctionName'
index FuncIndex;
// или (если не функция, а
процедура):
procedure ProcedureName(Par1: Par1Type;
Par2: Par2Type; ...); stdcall; external 'DLLNAME.DLL'
name 'ProcedureName' index ProcIndex;
Здесь: FunctionName (либо ProcedureName) - имя функции
(или процедуры), которое будет использоваться в Вашей
программе;
Par1, Par2, ... - имена параметров функции или
процедуры;
Par1Type, Par2Type, ... - типы параметров функции или
процедуры (например, Integer);
ReturnType - тип
возвращаемого значения (только для функции);
stdcall -
директива, которая должна точно совпадать с используемой в самой
DLL;
external 'DLLNAME.DLL' - директива, указывающая имя внешней
DLL, из которой будет импортирована данная функция или процедура (в данном
случае - DLLNAME.DLL);
name 'FunctionName'
('ProcedureName') - директива, указывающая точное имя функции в самой
DLL. Это необязательная директива, которая позволяет использовать в
программе функцию, имеющую название, отличное от истинного (которое она
имеет в библиотеке);
index FunctionIndex (ProcedureIndex) -
директива, указывающая порядковый номер функции или процедуры в DLL. Это
также необязательная директива.
2 способ. Динамическая загрузка DLL. Это гораздо
более сложный, но и более элегантный метод. Он лишен недостатка первого
метода. Единственное, что неприятно - объем кода, необходимого для
осуществления этого приема, причем сложность в том, что функция,
импортируемая из DLL достуна лишь тогда, когда эта DLL загружена и
находится в памяти... С примером можно ознакомиться ниже, а пока - краткое
описание используемых этим методом функций
WinAPI:
LoadLibrary(LibFileName: PChar) - загрузка
указанной библиотеки LibFileName в память. При успешном завершении функция
возвращает дескриптор (THandle) DLL в
памяти.
GetProcAddress(Module: THandle; ProcName:
PChar) - считывает адpес экспоpтиpованной библиотечной функции. При
успешном завершении функция возвращает дескриптор (TFarProc)
функции в загруженной DLL.
FreeLibrary(LibModule:
THandle) - делает недействительным LibModule и освобождает
связанную с ним память. Следует заметить, что после вызова этой процедуры
функции данной библиотеки больше недоступны.
Практика и примеры
Ну а теперь пора привести пару примеров использования вышеперечисленных методов и приемов:
Пример 1. Привязка DLL к программе |
{... Здесь идет заголовок файла
и определение формы TForm1 и ее экземпляра
Form1} |
Теперь то же самое, но вторым способом - с динамической загрузкой:
Пример 2. Динамическая загрузка DLL |
{... Здесь идет заголовок файла
и определение формы TForm1 и ее экземпляра
Form1} |
ПРИМЕЧАНИЕ: Следует воздерживаться от использования типа string в библиотечных функциях, т.к. при его использовании существуют проблемы с "разделением памяти". Подробней об этом можно прочитать (правда, на английском) в тексте пустого проекта DLL, который создает Delphi (File -> New -> DLL). Так что лучше используйте PChar, а затем при необходимости конвертируйте его в string функцией StrPas.
Ну а теперь разберем непосредственно саму библиотеку DLL:
Пример 3. Исходник проекта MYDLL.DPR |
library mydll; |
Размещение в DLL ресурсов и форм
В DLL можно размещать не только функции, но и курсоры, рисунки, иконки, меню, текстовые строки. На этом мы останавливаться не будем. Замечу лишь, что для загрузки ресурса нужно загрузить DLL, а затем, получив ее дескриптор, - загружать сам ресурс соотвествующей функцией (LoadIcon, LoadCursor, и т.д.). В этом разделе мы лишь немного затронем размещение в библиотеках DLL окон приложения (т.е. форм в Дельфи).
Для этого нужно создать новую DLL и добавить в нее новую форму (File -> New -> DLL, а затем - File -> New Form). Далее, если форма представляет собой диалоговое окно (модальную форму (bsDialog)), то добавляем в DLL следующую функцию (допустим, форма называется Form1, а ее класс - TForm1):
Пример 4. Размещение формы в DLL |
function ShowMyDialog(Msg: PChar): Boolean;
stdcall; |
Если же нужно разместить в DLL немодальную форму, то необходимо сделать две функции - открытия и закрытия формы. При этом нужно заставить DLL запомнить дескриптор этой формы.
Создание плагинов
Здесь мы не будем подробно рассматривать плагины, т.к. уже приведенные выше примеры помогут Вам легко разобраться в львиной части программирования DLL. Напомню лишь, что плагин - дополнение к программе, расширяющее ее возможности. При этом сама программа обязательно должна предусматривать наличие таких дополнений и позволять им выполнять свое предназначение.
Т.е., например, чтобы создать плагин к графическому редактору, который бы выполнял преобразование изображений, Вам нужно предусмотреть как минимум две функции в плагине (и, соответственно, вызвать эти функции в программе) - функция, которая бы возвращала имя плагина (и/или его тип), чтобы добавить этот плагин в меню (или в тулбар), плюс главная функция - передачи и приема изображения. Т.е. сначала программа ищет плагины, потом для каждого найденного вызывает его опозновательную функцию со строго определенным именем (например, GetPluginName) и добавляет нужный пункт в меню, затем, если пользователь выбрал этот пункт - вызывает вторую функцию, которой передает входное изображение (либо имя файла, содержащего это изображение), а эта функция, в свою очередь, обрабатывает изображение и возвращает его в новом виде (или имя файла с новым изображением). Вот и вся сущность плагина... :-)
Эпилог
В этой статье отображены основные стороны использования и создания библиотек DLL в Borland Delphi. Если у Вас есть вопросы - скидывайте их мне на E-mail: snick@mailru.com, а еще лучше - пишите в конференции этого сайта (Delphi. Общие вопросы), чтобы и другие пользователи смогли увидеть Ваш вопрос и попытаться на него ответить!
Delphisource (2006г.) |