Delphi - объектно-ориентированный язык программирования, разработанный компанией Borland в 1995 году. Он основан на языке программирования Pascal, но имеет более расширенные возможности и добавлены новые функции.
Delphi является интегрированной средой разработки (IDE), которая позволяет разрабатывать программное обеспечение для различных платформ, включая Windows, macOS, Android и iOS. Delphi достигает многоплатформенности с помощью...
Импортирование, или 'обертка' вызовов функций DLL
Существует два метода для импорта и загрузки функций из Dynamic Link Library (DLL). Первый метод (который широко обсуждается в данном документе), называется "неявной" (Implicit) загрузкой. Неявная загрузка включает в себя статическую загрузку DLL при запуске программы, и получение доступа к функциям через интерфейс объектного Паскаля. Данный метод должен использоваться в случае, если приложение полностью зависит от загрузки DLL для соответствующего функционирования. Другой метод доступа называется "явной" загрузкой, поскольку DLL загружается динамически по требованию. Этот метод требует дополнительного кодирования и должен использоваться, если приложению нужно работать в случае, даже если DLL не смогла правильно загрузиться.
Что такое "обертка" функциональных вызовов?
Обертка функции, или набора функций, состоит из объявлений в секции interface и кода в секции implementation (вместе со связанными константами или типами), которые соответствуют функции, или набору функций, импортируемых из DLL. Обертка является простой декларацией в паскалевском модуле, которая обеспечивает точку входа в DLL. В Delphi обертка представляет собой файл модуля, содержащий код объектного паскаля. Группа разработчиков Delphi уже создала для вас обертку функций и стандартных элементов управления Windows. Но иногда возникает необходимость создания обертки для вызовов функций dll, но это в Delphi не обернуто по случаю сугубой индивидуальности каждой DLL и входящих в нее функций.
Первым, и самым сложным шагом в данном процессе является получение информации о функциях. Один из лучших источников для получения документации об имеющихся (доступных) в DLL функций является World Wide Web. Начать поиск можно с MSDN, а если и там нет информации, то можно обратиться к многочисленным поисковым серверам, которые частенько находят нужную вам информацию. Для получения структуры вызовов функций ищите залоговочные файлы C++ в продуктах типа Borland C++ или MS Visual C++. Соглашения об вызовах и преобразованиях типов обычно способны разрешить конфликты и несовместимость вызовов между C++ и PASCAL. Хороший ресурс по вопросам совместимости между Delphi и C++ расположен на сайте Borland по адресу: http://www.borland.com/delphi/papers/brick.html.
После того, как вы нашли необходимый пример, или документацию об экспортируемых DLL функциях, то следующим шагом будет создание нового модуля. Интерфейс модуля будет содержать константы и типы, необходимые для вызова отдельных функций DLL, и заголовки самих функций. Данные заголовки функций являются объектно-паскалевским интерфейсом, позволяющим другим приложениям Delphi вызывать функции рассматриваемой DLL. Как только секция модуля interface будет завершена, следующей секцией будет implementation. Секция модуля implementation содержит объявления импортируемых внешних функций. Эти заголовки не идентичны тем, которые расположены в секции модуля interface (которые содержат реальные идентификаторы функций плюс другую важную информацию для реализации). Для получения дополнительной информации по этой теме обратитесь к топику "DLLs:accessing procedures and functions" справки помощи по Delphi 3.
Представим себе, что у нас есть функция с именем BOB в DLL с именем 'BLODGE.DLL'. (ниже приведены подробные и необходимые шаги, где подразумевается, что мы будем использовать неявную загрузку DLL):
functionBOB(Fire: Word; Dances: Boolean): Boolean; stdcall
;
functionBOB; external
'BLODGE';
Для способа, при котором 'BLODGE.DLL' должна быть загружена явно, требуется дополнительное кодирование. Как было подчеркнуто выше, необходимо знание аргументов функций/процедур (и тип результата в случае функции).
Ниже приведен модуль с реализацией вызова функции BOB, инициализируемый при нажатии на кнопку:
unitUDLLTest; interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type
TForm1 = class
(TForm) Button1: TButton; procedure
Button1Click(Sender: TObject); private
{ Private declarations } public
{ Public declarations } end
;
{ Вот типы, которые требуются для работы нашей функции bob } TBOB = function(Fire: Word; Dances: Boolean): Boolean; stdcall
; var
Form1: TForm1; implementation
{$R *.DFM} procedure
TForm1.Button1Click(Sender: TObject); var
BOB: TBOB; hDLLInst: THandle; IsAlive, IsDancing: Boolean; Years: Word; begin
{ Загружаем и получаем дескриптор нашего BLODGE.DLL } hDLLInst := LoadLibrary('BLODGE.DLL'); { Если загрузка не была успешной, генерируем свое исключение } if
(hDLLInst <= 0) then
raise
exception.create('[Неудачный вызов LoadLibrary]');
{ Попытаемся получить адрес функции BOB } try@BOB := GetProcAddress(hDLLInst, 'BOB'); if
not
assigned(BOB) then
raise
exception.Create('[Неудачный вызов GetProcAddress]'); Years := 25; IsDancing := True
;
{ Теперь мы можем выполнить функцию BOB } IsAlive := BOB(Years, IsDancing); finally{ Освобождаем дескриптор DLL } FreeLibrary(hDLLInst); end
; end
; end
.