Большой архив статей, книг, документации по программированию, вебдизайну, компьютерной графике, сетям, операционным системам и многому другому
 
<Добавить в Избранное>    <Сделать стартовой>    <Реклама на сайте>    <Контакты>
  Главная Документация Программы Обои   Экспорт RSS E-Books
 
 

   Программирование -> Delphi / Pascal -> Использование и создание DLL в Delphi


Использование и создание 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}

implementation

{Определяем внешнюю библиотечную функцию}

function GetSimpleText(LangRus: Boolean): PChar; stdcall; external 'MYDLL.DLL';

procedure Button1Click(Sender: TObject);
begin
  {И используем ее}
  ShowMessage(StrPas(GetSimpleText(True)));
  ShowMessage(StrPas(GetSimpleText(False)));
  {ShowMessage - показывает диалоговое окно с указанной надписью; StrPas - преобразует строку PChar в string}
end;

Теперь то же самое, но вторым способом - с динамической загрузкой:

Пример 2. Динамическая загрузка DLL

{... Здесь идет заголовок файла и определение формы TForm1 и ее экземпляра Form1}

var
      Form1: TForm1;
      GetSimpleText: function(LangRus: Boolean): PChar;
      LibHandle: THandle;

procedure Button1Click(Sender: TObject);
begin
  {"Чистим" адрес функции от "грязи"}
  @GetSimpleText := nil;
  {Пытаемся загрузить библиотеку}
  LibHandle := LoadLibrary('MYDLL.DLL');
  {Если все OK}
  if LibHandle >= 32 then begin
    {...то пытаемся получить адрес функции в библиотеке}
    @GetSimpleText := GetProcAddress(LibHandle,'GetSimpleText');
    {Если и здесь все OK}
    if @GetSimpleText <> nil then
      {...то вызываем эту функцию и показываем результат}
      ShowMessage(StrPas(GetSimpleText(True)));
  end;
  {И не забываем освободить память и выгрузить DLL}
  FreeLibrary(LibHandle);
end;

ПРИМЕЧАНИЕ: Следует воздерживаться от использования типа string в библиотечных функциях, т.к. при его использовании существуют проблемы с "разделением памяти". Подробней об этом можно прочитать (правда, на английском) в тексте пустого проекта DLL, который создает Delphi (File -> New -> DLL). Так что лучше используйте PChar, а затем при необходимости конвертируйте его в string функцией StrPas.

Ну а теперь разберем непосредственно саму библиотеку DLL:

Пример 3. Исходник проекта MYDLL.DPR

library mydll;

uses SysUtils, Classes;

{Определяем функцию как stdcall}
function GetSimpleText(LangRus: Boolean): PChar; stdcall;
begin
  {В зависимости от LangRus возвращаем русскую (True) либо английскую (False) фразу}
  if LangRus then
    Result := PChar('Здравствуй, мир!')
  else
    Result := PChar('Hello, world!');
end;

{Директива exports указывает, какие функции будут экспортированы этой DLL}
exports GetSimpleText;

begin
end.

Размещение в 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;

...
exports ShowMyDialog;

function ShowMyDialog(Msg: PChar): Boolean;
begin
  {Создаем экземпляр Form1 формы TForm1}
  Form1 := TForm1.Create(Application);
  {В Label1 выводим Msg}
  Form1.Label1.Caption := StrPas(Msg);
  {Возвращаем True только если нажата OK (ModalResult = mrOk)}
  Result := (Form1.ShowModal = mrOk);
  {Освобождаем память}
  Form1.Free;
end;

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

Создание плагинов

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

Т.е., например, чтобы создать плагин к графическому редактору, который бы выполнял преобразование изображений, Вам нужно предусмотреть как минимум две функции в плагине (и, соответственно, вызвать эти функции в программе) - функция, которая бы возвращала имя плагина (и/или его тип), чтобы добавить этот плагин в меню (или в тулбар), плюс главная функция - передачи и приема изображения. Т.е. сначала программа ищет плагины, потом для каждого найденного вызывает его опозновательную функцию со строго определенным именем (например, GetPluginName) и добавляет нужный пункт в меню, затем, если пользователь выбрал этот пункт - вызывает вторую функцию, которой передает входное изображение (либо имя файла, содержащего это изображение), а эта функция, в свою очередь, обрабатывает изображение и возвращает его в новом виде (или имя файла с новым изображением). Вот и вся сущность плагина... :-)

Эпилог

В этой статье отображены основные стороны использования и создания библиотек DLL в Borland Delphi. Если у Вас есть вопросы - скидывайте их мне на E-mail: snick@mailru.com, а еще лучше - пишите в конференции этого сайта (Delphi. Общие вопросы), чтобы и другие пользователи смогли увидеть Ваш вопрос и попытаться на него ответить!

Автор: Карих Николай
Источник: www.vlata.com/delphi/

Ссылки по теме
Сайт внутри EXE файла
Работа с параллельным портом под Windows
Создание компонент в Delphi
Как работать с реестром в Delphi
Разработка WEB-сервисов в среде Delphi 8
OpenGL и Delphi на практике
 

Компьютерная документация от А до Я - Главная

 

 
Интересное в сети
 
10 новых программ
CodeLobster PHP Edition 3.7.2
WinToFlash 0.7.0008
Free Video to Flash Converter 4.7.24
Total Commander v7.55
aTunes 2.0.1
Process Explorer v12.04
Backup42 v3.0
Predator 2.0.1
FastStone Image Viewer 4.1
Process Lasso 3.70.4
FastStone Image Viewer 4.0
Xion Audio Player 1.0.125
Notepad GNU v.2.2.8.7.7
K-Lite Codec Pack 5.3.0 Full


Наши сервисы
Рассылка новостей. Подпишитесь на рассылку сейчас и вы всегда будете в курсе последних событий в мире информационных технологий.
Новостные информеры. Поставьте наши информеры к себе и у вас на сайте появится дополнительный постоянно обновляемый раздел.
Добавление статей. Если вы являетесь автором статьи или обзора на тему ИТ присылайте материал нам, мы с удовольствием опубликуем его у себя на сайте.
Реклама на сайте. Размещая рекламу у нас, вы получите новых посетителей, которые могут стать вашими клиентами.
 
Это интересно
 

Copyright © CompDoc.Ru
При цитировании и перепечатке ссылка на www.compdoc.ru обязательна. Карта сайта.