Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

Импортирование или обертка вызовов функций DLL

01.01.2007

Импортирование, или 'обертка' вызовов функций 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):

Поиск информации по Интернету показал, что функция BOB должна возвращать логическое значение и требует в качестве аргументов значения типа word и boolean.

Создайте в Delphi новый файл модуля с именем 'UseBob.pas' (File|New и выберите unit)

Следующая строка кода должна располагаться в секции interface нового модуля:

function BOB(Fire: Word; Dances: Boolean): Boolean; stdcall;

Следующая строка кода должна располагаться в секции implementation нового модуля:

function BOB; external 'BLODGE';

Сохраните модуль с именем 'UseBob.pas'.

Необходимо убедиться в том, что UseBob.pas расположен в каталоге текущего проекта, или находится в каталоге, прописанном в путях поиска Delphi.

Добавьте к списку uses модуля нового проекта модуль 'UseBob'. Теперь функция BOB может быть вызвана из нового проекта подобно любой другой стандартной функции.

Во время выполнения приложения BLODGE.DLL должен находится в пути текущих переменных окружения процесса.

Для способа, при котором 'BLODGE.DLL' должна быть загружена явно, требуется дополнительное кодирование. Как было подчеркнуто выше, необходимо знание аргументов функций/процедур (и тип результата в случае функции).

Ниже приведен модуль с реализацией вызова функции BOB, инициализируемый при нажатии на кнопку:

unit UDLLTest;
 
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.

Взято с https://delphiworld.narod.ru