Как добавить dll в delphi
Перейти к содержимому

Как добавить dll в delphi

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

Что такое DLL — знает, как минимум, большинство пользователей PC, тем более программисты, к которым Вы, скорее всего и относитесь, раз читаете эту статью. В этой статье я постараюсь пробежаться по всем общим вопросам, касающимся DLL.

Что конкретно мы рассмотрим:

  1. Как обычно, из области «Hello World», мы создадим свою первую DLL.
  2. Научимся пользоваться функциями этой DLL из своих программ.
  3. Научимся просматривать функции, которые экспортирует определенная DLL.
  4. Может, что нибудь еще.

Процесс создания DLL

Начнем с самого простого — написание своей первой DLL, которая будет содержать всего лишь одну функцию, которая выводит сообщение «Hello World».

  1. Запускаем Delphi (Я использую Delphi 6).
  2. Далее: File -> New ->Other

На закладке New дважды щелкаем по объекту DLL Wizard. Откроется новый проект. Сохраните его, например, с именем MyFirstDLL.

Чистый модуль имеет примерно такое содержание:

library MyFirstDLL; uses SysUtils, Classes; begin end.

Теперь напишем всего лишь одну функцию, которая вызовет ShowMessage() из модуля Dialogs. Следовательно, перед началом оформления процедуры допишем в раздел Uses модуль Dialogs. Что, примерно, должно у вас получится:

library MyFirstDLL; uses Dialogs; procedure MyFirstFunc; stdcall; begin ShowMessage('Hello World'); end; exports MyFirstFunc; begin end.

Как видите, тут нет ничего очень сложного. Единственное скажу, что можно вызывать функции как по имени, так и по индексу (номеру), для этого надо писать так:

exports MyFirstFunc index 1;

Если что не понятно в этом коде, то все таки постарайтесь разобраться сначала сами. Думаю, что с этим проблем не будет. Но если что, то forum.sources.ru Вам всегда рад! Идем дальше, как же можно теперь пользоваться этой (MyFirstFunc) функцией из других проектов?

Использование функций DLL

Первый шаг сделан, дело за малым. Как нам использовать эту функцию?

Есть, как минимум, два способа загрузки:

  1. Статический
  2. Динамический

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

Создаем новый проект, бросаем на форму одну кнопку и по событию OnClick этой кнопки и пишем следующее:

procedure TForm1.Button1Click(Sender: TObject); begin MyProc( ); end;

Но это еще не все! В разделе implementation проекта запишите:

implementation procedure MyProc( ); stdcall; external 'MyFirstDLL.dll' name 'MyFirstFunc';

Готово! Компилируйте проект и жмите на кнопку! Если показалось ваше сообщение, то все ок!

Теперь рассмотрим способ с динамической загрузкой. Для этого метода используют функцию LoadLibrary( ), а в конце, для выгрузки — FreeLibrary( ).

Посмотрите на примере:

procedure TForm1.Button1Click(Sender: TObject); type TMyFunc = procedure; var DLLInstance : THandle; MyFunc : TMyFunc; begin DLLInstance := LoadLibrary(PChar('MyFirstDLL.dll')); if (DLLInstance = 0) then begin MessageDlg('Невозможно загрузить DLL', mtError, [mbOK], 0); Exit; end; try @MyFunc := GetProcAddress(DLLInstance, 'MyFirstFunc'); if Assigned(@MyFunc) then MyFunc( ) else MessageDlg('Не найдена искомая процедура!.', mtError, [mbOK], 0); finally FreeLibrary(DLLInstance); end; end;

После успешной загрузки DLL функцией LoadLibrary( ), с помощью GetProcAddress( ) найдем адрес нашей функции, по которому и будем вызывать нашу процедуру из DLL. В конце, обязательно, надо сделать FreeLibrary( ). Это настолько важно, что весь код после успешной загрузки, вполть до FreeLibrary( ) я заключил в блок try finally. Это гарантирует выполнение FreeLibrary, даже если при выполнении действий внутри блока try except, возникнет непредвиденная ошибка в виде исключения (Exception).

Дело в том, что успешные вызовы LoadLibrary и FreeLibrary обязательно должны быть парными. И вот почему. Система, для каждой загружаемой процессом библиотеки, ведет внутри себя счетчик, который увеличивается на 1 при каждом успешном вызове LoadLibrary. Соответственно, при выполнени FreeLibrary, она уменьшает этот счетчик, и если он становится равным нулю, то это означает что данная библиотека более не нужна данному процессу, и ее можно смело удалить из памяти.

Если-же правило парности не соблюдать, то это может привести либо к преждевременной выгрузке (при лишнем FreeLibrary) библиотеки из памяти, либо к ее «застревании» там (при недостатке FreeLibrary).

При соблюдении же этого правила, можно не заботиться о возможной вложенности вызовов LoadLibrary / FreeLibrary.

Просмотр функций определенной DLL

Теперь посмотрим, как можно извлечь все имена функций из файлов PE формата, к которым и относится DLL. Структуру PE формата мы тут рассматривать не будем, следовательно, и исходник будет без пояснений.

Итак, создайте новый проект, бросьте на форму ListBox, в нём мы будем показывать имена функций.

Вот весь проект:

unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) lb: TListBox; procedure FormCreate(Sender: TObject); private < Private declarations >cmdline : String; ImageBase : DWord; DosHeader : PImageDosHeader; PeHeader : PImageNtHeaders; PExport : PImageExportDirectory; pname : PDWord; name : PChar; public < Public declarations >end; var Form1: TForm1; implementation procedure TForm1.FormCreate(Sender: TObject); procedure FatalOsError; begin ShowMessage(SysErrorMessage(GetLastError( ))); Abort; end; Var i: Integer; begin try if (ParamCount( ) < 1) then Abort else cmdline := ParamStr(1); ImageBase := LoadLibrary(PChar(cmdline)); if (ImageBase = 0) then FatalOsError; try DosHeader := PImageDosHeader(ImageBase); if (DosHeader^.e_magic <>IMAGE_DOS_SIGNATURE) then FatalOsError; PEHeader := PImageNtHeaders(DWord(ImageBase) + DWord(DosHeader^._lfanew)); if (PEHeader^.Signature <> IMAGE_NT_SIGNATURE) then FatalOsError; PExport := PImageExportDirectory(ImageBase + DWord(PEHeader^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY _EXPORT].VirtualAddress)); pname := PDWord(ImageBase + DWord(PExport^.AddressOfNames)); For i := 0 to PExport^.NumberOfNames - 1 do begin name := PChar(PDWord(DWord(ImageBase) + PDword(pname)^)); lb.Items.Add(name); inc(pname); end; finally FreeLibrary(ImageBase); end; except Application.ShowMainForm := False; Application.Terminate; end; end; end.

Если вы захотите сами разобраться в коде и у вас что-то не будет получаться, то на нашем форуме вам обязательно помогут, заходите!

Прицепляем наш Viewer ко всем DLL

У нас есть готовая DLL с функцией, есть просмотрщик функций. Осталось добавить некой функциональности для удобства дальнейшей работы. Давайте сделаем это. В проводнике открываем любую папку. Идем в Сервис -> Свойства папки. Переходим на закладку «Типы файлов». В списке ищем формат DLL. Если такого нет, то жмем кнопку «Создать» и в поле «Расширение» пишем — DLL. Жмем ОК. Находим созданный нами тип — DLL. Выделяем его и жмем «Дополнительно». Далее «Создать», в поле «Действии» пишем то, что будет отображаться в контекстном меню, например DLL Viewer. Через обзор ищем нашу программку.

Теперь при клике правой кнопкой мыши по файлу формата DLL в меню будет наш DLL Viewer. Выбираем его и смотрим все функции!

Это все, спасибо за внимание!

Delphi: DLL библиотеки

Чтобы создать новую библиотеку DLL в Delphi, выберите команду меню File > New > Other. В панели Items Categories окна New Items выберите узел Delphi Projects, после чего дважды щелкните на элементе Dynamic-link Library в правой панели окна.

Мастер DLL Wizard создает главный файл исходного кода библиотеки DLL, который выглядит практически так же, как и исходный код, сгенерированный для обычного приложения. Единственное отличие состоит в том. что этот файл начинается с зарезервированного слова library, а не program.

library Project1; < Important note about DLL memory management: ShareMem must be the first unit in your library's USES clause AND your project's (select Project-View Source) USES clause if your DLL exports any procedures or functions that pass strings as parameters or function results. This applies to all strings passed to and from your DLL--even those that are nested in records and classes. ShareMem is the interface unit to the BORLNDMM.DLL shared memory manager, which must be deployed along with your DLL. To avoid using BORLNDMM.DLL, pass string information using PChar or ShortString parameters. > < Важное замечание относительно управления памятью библиотеки DLL: модуль ShareMem должен быть первым модулем в операторе uses вашей библиотеки и в операторе uses вашего проекта (выберите команду меню Project ->View Source (Проект -> Показать исходный код)), если ваша библиотека DLL экспортирует какие-либо процедуры или функции, передающие строки в качестве параметров или результатов выполнения функций. Это относится ко всем строкам, передаваемым или получаемым из вашей библиотеки DLL, и даже к тем строкам, которые вложены в записи и классы. Модуль ShareMem является модулем интерфейса для администратора общей памяти BORLNDMM.DLL, который вы должны развертывать вместе со своей библиотекой DLL. Чтобы не использовать BORLNDMM.DLL, передавайте строковую информацию с помощью параметров PChar или ShortString. > uses SysUtils, Classes; begin end.

Все, что вам нужно сделать сейчас — это добавить подпрограмму перед блоком begin-end, вот и все. После этого вы получите внутреннюю подпрограмму, которую можно будет использовать в библиотеке DLL, но не во внешних приложениях. Если вы хотите вызывать подпрограмму из других приложении и других библиотек DLL, ее потребуетсл экспортировать. Чтобы экспортировать подпрограмму по имени, добавьте ее в список exports. Список exports имеет такой же синтаксис, что и список uses, за исключением того, что в списке exports любой элемент является подпрограммой, а не модулем.

Список exports обычно ставится непосредственно перед блоком begin-end. Взгляните на листинг 1, в котором представлен исходный код простой библиотеки FirstLib.dll, экспортирующей одну функцию.

Листинг 1. Простая библиотека DLL

library FirstLib; function Max3(Num1, Num2, Num3: Integer): Integer; stdcall; begin Result := Num1; if Num2 > Result then Result := Num2; if Num3 > Result then Result := Num3; end; < Экспортируем функцию Max3 >exports Max3; begin end.

Когда вы добавите подпрограмму в список exports, вы тем самым экспортируете подпрограмму по ее имени. Вы можете также экспортировать подпрограмму под другим именем с помощью директивы name или посредством порядкового значения, используя директиву index. Однако применять директиву index не рекомендуется.

Ниже показан пример экспортирования директивы посредством порядкового значения или под другим именем:

exports Max3 name 'MyMax3Function', SaySomething index 1;

Статическая загрузка является самым простым из двух возможных способов загрузки библиотеки DLL. Статическую загрузку называют еще динамическим подключением во время загрузки (load-time dynamic linking), потому что используемые библиотеки DLL автоматически загружаются во время запуска приложения.

Чтобы статически загрузить библиотеку DLL, необходимо скопировать объявление подпрограммы и вызывающее приложение и пометить ее с помощью директивы external, которая сообщает компилятору о том, что подпрограмма находится либо в объектном файле, либо в библиотеке DLL.

Когда вы импортируете подпрограммы из библиотеки DLL, вы должны помечать их директивой external, указывая вслед за ней имя библиотеки DLL, в которой содержится реализация подпрограммы. Далее показан пример импорта функции МахЗ из библиотеки FirstLib.dll:

function Max3(Num1, Num2, Num3: Integer): Integer; stdcall; external 'FirstLib.dll';

При желании можете даже переименовать подпрограмму во время ее импорта. Для этого необходимо объявить подпрограмму под другим именем, а в конце объявления указать первоначальное имя с помощью директивы name:

function Max(Num1, Num2, Num3: Integer): Integer; stdcall; external 'FirstLib.dll' name 'Max3';

Вы можете также импортировать функцию из библиотеки DLL. Для этого нужно создать модуль импорта и написать стандартный заголовок подпрограммы в разделе interface, а ее внешнюю реализацию — в разделе implementation этого модуля. В листинге 2 показан полный код модуль импорта библиотеки FirstLib.dll.

Листинг 2. Модуль импорта библиотеки FirstLib.dll.

unit FirstLibInf; interface function Max3(Num1, Num2, Num3: Integer): Integer; stdcall; implementation const FirstLib = 'FirstLib.dll'; function Max3; external FirstLib; end.

После того как вы создадите библиотеку DLL и ее модуль импорта, протестируйте библиотеку DLL, чтобы убедиться в том. что подпрограмма работает нормально. Поскольку запустить саму библиотеку DLL нельзя, нужно создать тестовое приложение, которое будет обращаться к библиотеке DLL. Быстрее всего сделать это можно, если создать проектную группу, добавив новый проект в текущий проект. Для этого потребуется щелкнуть правой кнопкой мыши на элементе ProjectGroup1 в окне Project Manager (Диспетчер проекта) и выбрать в контекстном меню команду Add New Project, как показано на рис. 1.

Листинг 3. Проверка подпрограммы Max3, импортированной из библиотеки FirstLib.dll.

unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, FirstLibInf, StdCtrls; type TMainForm = class(TForm) Edit1: TEdit; Edit2: TEdit; Edit3: TEdit; Label1: TLabel; Label2: TLabel; Label3: TLabel; Max3Button: TButton; procedure Max3ButtonClick(Sender: TObject); private < Private declarations >public < Public declarations >end; var MainForm: TMainForm; implementation procedure TMainForm.Max3ButtonClick(Sender: TObject); var LargestNumber: Integer; begin LargestNumber := Max3(StrToInt(Edit1.Text), StrToInt(Edit2.Text), StrToInt(Edit3.Text)); MessageDlg(Format('Наибольшее число: %d.', [LargestNumber]), mtInformation, [mbOK], 0); end; end.

Используемая литература: Внутренний мир Borland Delphi 2006. Иван Хладни.

Cоздание и использование dll в Delphi

Динамически подключаемые библиотеки (далее dll — dynamic link library) представляют собой универсальный механизм интегрирования в вашу программу процедур и функций, написанных другими программистами и, в общем случае, на других, чем object pascal, языках программирования.

dll реализуются в виде исполняемых модулей, содержащих готовые к работе процедуры, функции и/или ресурсы. С точки зрения программиста, есть много общего между dll и обычными для object pascal модулями, т. к. в конечном счете и библиотеки, и модули поставляют подпрограммы, избавляющие программиста от написания собственного кода. Но есть и принципиальные отличия. Главным из них является то, что dll не в состоянии поставлять в программу переменные, константы и типы, ведь создатели dll могут использовать не типизированные языки программирования, например, язык ассемблера. В результате dll не могут экспортировать в программу столь необходимые сегодня программисту классы — для этого используются пакеты.
Другим важным отличием является способ связывания экспортируемых подпрограмм с основной программой. Модули связываются с программой на этапе компоновки, т. е. статически. Если загружены две программы, использующие одни и те же модули, в памяти будут два экземпляра одинаковых фрагментов кода. В отличие от этого dll подключаются к программе в момент ее исполнения, т. е. динамически. Если опять же две программы используют одну и ту же dll, в памяти будет лишь один экземпляр разделяемого программами кода. Следует уточнить, что речь идет о физической памяти компьютера. Поскольку каждая программа получает в свое распоряжение виртуальное адресное пространство (подробнее о процессах и памяти говорится в гл. 14), в эти пространства будут отображаться столько образов dll, сколько программ ее используют (см. в главе 11 раздел «Отображение файлов в память»).
Динамическое подключение dll дает им еще одно немаловажное преимущество над модулями: изменение любой dll в большинстве случаев не требует перекомпиляции использующей ее программы.

Для создания dll в object pascal введено зарезервированное слово library, которым должен начинаться текст библиотеки. За словом library следует правильный идентификатор, но в отличие от объявления модуля он не обязан совпадать с именем файла: имя dll определяется именем dll-файла, а не идентификатором, следующим за library.
Структура текста dll повторяет структуру обычной программы с тем исключением, что раздел исполняемых операторов в dll играет ту же роль, что и инициирующая часть модуля: операторы этой части исполняются только один раз в момент загрузки библиотеки в память. Каждое очередное обращение с требованием загрузить библиотеку наращивает на единицу ее счетчик ссылок, но не приводит к выполнению операторов исполняемой части.
В разделе описаний dll могут объявляться типы (в том числе и классы), константы и переменные, но они остаются скрытыми от вызывающей программы и могут использоваться только внутри dll. В разделе описаний помимо стандартных для обычной программы объявлений используется специальный раздел объявления экспортируемых подпрограмм. Этот раздел начинается зарезервированным словом exports, за которым через запятую перечисляются имена экспортируемых подпрограмм, далее по ссылке.

Информация из сборника исходников на pblog.ru

Раздел DLL в Delphi в сборнике исходников и статей на pblog.ru

Пост написан при поддержке Major auto — По ссылке, новые шевроле круз

Похожие статьи

  • Исходник простейшей программы с использованием DLL
  • Прозрачность формы PNG, 2xTCV и др.
  • Медианный фильтр прорисовки изображений через pixels Delphi
  • Адрес пикселя в BitMap
  • Яркость, контраст, превратить изображение в ч/б
  • Вставить TBitMap в RichEdit
  • Статическая и динамическая загрузка класса из библиотеки
  • Вызвать из DLL в EXE процедуру
  • Создание формы командой из DLL
  • Уменьшить Bitmap

Как подключить стороннюю библиотеку .dll к новому проекту в Delphi?

Здравствуйте, у меня есть библиотека написанная на Delphi 7, файл с расширением dll, и файл приложения для работы с этой библиотекой. Задача стоит получить доступ к классам и методам которые описаны в библиотеке, необходимо внести изменения в программу исходников которой у меня нет, а её декомпилирование не дало положительных результатов. Используя штатные средства среды разработки RAD 2010 либо Delphi 7, подключить эту библиотеку к новому проекту при использовании функции «Import Type Library» не получается, выводится «Ошибка при загрузке бибилотеки»(возможно я сделал что-то не правильно). Есть ли иные варианты подключения библиотеки к проекту?

Отслеживать
задан 25 авг 2017 в 4:43
Alexander Shapovalov Alexander Shapovalov
41 3 3 бронзовых знака

Скорее всего вы все сделали правильно, просто эта dll не является ActiveX library и не реализует COM-интерфейсы. Раз так, то доступ к функциональности этой библиотеки доступен вам только через экспортируемые функции. Доступа к классам и методам классов нет. И даже если бы был — нельзя обращаться к ним, поскольку (например) TForm в exe и TForm в dll — это разные классы с одним и тем же именем, отождествлять их опасно. При наличии описания экспортируемых методов обратите внимание, что PChar в D7 = PAnsiChar в D2009 и выше

25 авг 2017 в 5:24

Если сигнатур экспортируемых методов нет и нет доступа к исходникам (пусть не самой dll, а любого приложения, которое эту dll использует) — имхо, библиотеку можно выкинуть.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *