Date Редакция Категория comp Теги pascal / fortran

Существует два метода для импорта и загрузки функций из библиотек DLL. Первый метод называется неявной (implicit) загрузкой. Он предполагает статическую загрузку DLL при запуске программы. Данный метод обычно используется когда работа приложения полностью зависит от загрузки соответствующей DLL. Второй метод доступа называется "явной" загрузкой, поскольку DLL загружается динамически -- по требованию.

Рассмотрим оба метода на примере импорта из Fortran динамической библиотеки mysubdll.dll, содержащей процедуру

subroutine Add(a,b)
!$ ATTRIBUTES DLLEXPORT, STDCALL :: Add
  real a
  real b
  a=a+b
end subroutine Add

Как создавать динамические библиотеки в Fortran описано здесь. Имейте в виду, что Fortran по умолчанию добавляет в конце имени функции или подпрограммы символ подчеркивания. Поэтому, собрав библиотеку обычным способом, вы должны будете обращаться к подпрограмме add_. Чтобы убрать подчеркивание нужно указать в настройках сборки ключ компилятора -fno-underscoring (Project->Build Settings, вкладка Compiler Settings и на ней -- Other options). Теперь к подпрограмме можно обращаться по ее "родному" имени.

Статическая загрузка

В объявлении процедуры Add нужно указать тип соглашения о вызове (StdCall). Это важно, поскольку у Pascal-я по умолчанию другой тип соглашения. Затем указывается имя внешней библиотеки и (необязательно) имя подключаемой функции (подпрограммы) из этой библиотеки.

program use_subdll;

procedure Add(var x,y: single); StdCall; external 'mysubdll.dll' name 'add';

var
  a,b : single;

begin
  a := 10.0;
  b := 2.0;
  Add(a,b);
  WriteLn('Result is... ', a);
  ReadLn;
end. 

Файл библиотеки mysubdll.dll следует поместить в папку, где будет храниться исполняемый файл.

Результат:

stat.png

Здесь важны два момента:

1. Параметры в Fortran-е передаются по ссылке, а в Pascal -- по ссылке (var) и по значению. Во избежание проблем, передавайте в Pascal-e данные только по ссылке. Дело в том, что при создании динамической библиотеки в Fortran есть возможность задать атрибуты REFERENCE (ссылка) и VALUE (значение) для разных параметров, чтобы потом соответственно указать их в Pascal, но этот способ не всегда работает. Передавать же все данные по ссылке в Pascal-евской процедуре может и не так красиво, зато работает всегда.

2. Обратите внимание на соответствие типов данных. Fortran-овскому 4-хбайтному real соответствует pascal-евский single.

Динамическая загрузка

Привязка к библиотеке производится на этапе выполнения, для чего используются функции LoadLibrary, GetProcedureAddress и FreeLibrary из модуля dynlibs. Можно также воспользоваться соответствующими функциями из модуля windows, но такой подход привяжет нас к одной платформе. Поэтому лучше использовать кроссплатформенный модуль dynlibs.

Последовательность действий:

  1. Объявляем переменную процедурного типа с соответствующими параметрами и типом вызова.
  2. Загружаем библиотеку функцией LoadLibrary.
  3. Находим адрес нужной функции с помощью GetProcedureAddress и присваиваем его нашей переменной.
  4. Вызываем функцию через переменную, когда это нам нужно.
  5. Когда функции данной библиотеки станут не нужны, освобождаем ее функцией FreeLibrary.
program use_subdll;

uses dynlibs;

type
  TMySub = procedure(var x,y: single); StdCall;

var
  MyLib: TLibHandle;
  MySub: TMySub;
  a,b : single;

begin
  a := 10.0;
  b := 2.0;

  MyLib := LoadLibrary('mysubdll.' + SharedSuffix);
  if MyLib = 0 then Exit;
  MySub := TMySub(GetProcedureAddress(MyLib, 'add'));
  if MySub = nil then Exit;

  MySub(a,b);
  WriteLn('Result is... ', a);
  ReadLn;
end.


Комментарии

comments powered by Disqus