Проблема с dll, созданной в Delphi
При разработке программы предварительно решил реализовать на asm критические по скорости процедуры, функцию вызывающие эти процедуры написать на Delphi (просто Delphi XE7 под рукой), скомпилировать в dll и вызывать из Matlab (в дальнейшем написать всё приложение на Delphi). Так как функция реализованная на Delphi и организованная в виде dll требует много параметров, часть из которых не меняется от вызова к вызову, я решил (по аналогии, как это обычно делается в Borland Pascal и позже) добавить функцию, которая будет задавать значения этих параметров в dll (ParamInit).
Почти минимальный пример, демонстрирующий проблему.
Исходный текст модуля
unit MatlabL;
interface
Type
DoubleMas = array[1..2] of Double;
procedure ParamInit(h, z0: Double) stdcall;
procedure Test(x, y: Double; out res: DoubleMas ) stdcall;
implementation
var
MatlabL_z0, MatlabL_h: Double;
procedure ParamInit;
begin
MatlabL_h := h;
MatlabL_z0 := z0;
end;
procedure Test;
begin
res[1] := x + MatlabL_z0;
res[2] := y + MatlabL_h;
end;
end.
Исходный текст библиотеки
library MatlabLoadTst;
uses
MatlabL;
exports
ParamInit,
Test;
end.
Файл MatlabLoadTst.h для загрузки библиотеки в Matlab
void __stdcall ParamInit(double, double);
void __stdcall Test(double x, double y, double res[2]);
Сценарий Matlab для тестирования
if not(libisloaded('MatlabLoadTst'))
loadlibrary('MatlabLoadTst', 'MatlabLoadTst1');
end
libfunctions('MatlabLoadTst', '-full');
calllib('MatlabLoadTst','ParamInit', 2, 3);
AA=[1, 1];
AA = calllib('MatlabLoadTst','Test', 1.0, 2.0, AA);
disp([AA]);
unloadlibrary('MatlabLoadTst');
Результат выполнения (R2019a)
Код:
Functions in library MatlabLoadTst:
ParamInit(double, double)
Error using calllib
Method was not found.
Error in TstDll (line 7)
AA = calllib('MatlabLoadTst','Test', 1.0, 2.0, AA);
Т.е. в списке функций только
ParamInit. Если закомментировать
ParamInit в файле заголовка и вызов этой функции в сценарии Matlab:
if not(libisloaded('MatlabLoadTst'))
loadlibrary('MatlabLoadTst', 'MatlabLoadTst1');
end
libfunctions('MatlabLoadTst', '-full');
%calllib('MatlabLoadTst','ParamInit', 2, 3);
AA=[1, 1];
AA = calllib('MatlabLoadTst','Test', 1.0, 2.0, AA);
disp([AA]);
unloadlibrary('MatlabLoadTst');
то получим ожидаемый результат выполнения
Код:
Functions in library MatlabLoadTst:
doublePtr Test(double, double, doublePtr)
1 2
Аналогично, если закомментируем
Test в файле заголовка и вызов этой функции в сценарии Matlab
if not(libisloaded('MatlabLoadTst'))
loadlibrary('MatlabLoadTst', 'MatlabLoadTst1');
end
libfunctions('MatlabLoadTst', '-full');
calllib('MatlabLoadTst','ParamInit', 2, 3);
%AA=[1, 1];
%AA = calllib('MatlabLoadTst','Test', 1.0, 2.0, AA);
%disp([AA]);
unloadlibrary('MatlabLoadTst');
то опять получим ожидаемый результат выполнения
Код:
Functions in library MatlabLoadTst:
ParamInit(double, double)
Из раздела “Limitations to Shared Library Support” руководства MATLAB External Interfaces R2015
Цитата:
MATLAB Supports C Library Routines
The MATLAB shared library interface supports C library routines only. Most professionally written libraries designed to be used by multiple languages and platforms work fine. Many homegrown libraries or libraries that have only been tested from C++ have interfaces that are not usable and require modification or an interface layer. In this case, we recommend using MEX-files.
Что об этом известно? Что делать?
(Оффтоп)
Пожалуйста, не предлагать банальности вида:
1) установить компилятор С и скомпилировать в нем;
2) сделать всё в Delphi;
3) Пока проект в отладке (до переписывания всего в Delphi) убрать функцию ParamInit, задавать параметры константами и компилировать заново при изменении значений параметров.
Upd Если изменить в h-файле описание первой функции на
void __stdcall ParamInit(double, double[]);то будет вроде правильно работать
Код:
Functions in library MatlabLoadTst:
doublePtr ParamInit(double, doublePtr)
doublePtr Test(double, double, doublePtr)
3 4
Upd2 Если изменить старый заголовок
PatamInt на правильный
procedure ParamInit(h: Double; var z0: Double) stdcall;, то и результат выполнения будет правильным
Код:
Functions in library MatlabLoadTst:
doublePtr ParamInit(double, doublePtr)
doublePtr Test(double, double, doublePtr)
4 4