Сбой MATLAB из-за calllib (файл C ++ .h и FORTRAN .dll) - PullRequest
0 голосов
/ 22 января 2019

Я пытаюсь включить внешнюю DLL-библиотеку на основе FORTRAN (скомпилированную с помощью компилятора Intel Fortran) в MATLAB.Поскольку он внешний, я не могу вносить какие-либо изменения в библиотеку времени выполнения библиотеки DLL.В настоящее время я написал сопроводительный заголовочный файл на C ++, чтобы иметь возможность вызывать DLL.При использовании loadlibrary библиотека загружается в MATLAB (без ошибок - одно предупреждение), однако при использовании calllib MATLAB вылетает и не выдает ошибку.

Я думаю, что одна из следующих причин может быть причиной этого, но, поскольку я неопытный в использовании DLL (особенно в C ++), я сам еще не нашел ошибку.

  • Есть также файл .lib, который я получил от поставщика, но я еще не включил его в файл MATLAB или заголовочный файл C ++.
  • FILEA иFILEB переменные - это пути к двум текстовым файлам, которые вводятся в DLL, я думаю, что, возможно, я неправильно включил их в C ++.
  • В файле mHeader (заголовочный файл MATLAB) stdcall - этоупоминается только в закомментированном разделе, а не в разделе кодирования.

Код для файла заголовка на C ++ и моего сценария MATLAB показан ниже:

#ifndef _MYMODEL
#define _MYMODEL
#ifdef __cplusplus
extern "C" {
#endif // _cplusplus
    // Functions and data types defined
     void __stdcall MYFUN(char FILEA[], char FILEB[], int *IDTask, int 
    *nErrorCode, int *ErrorCode, double *Props, double *Out1, double *Out2, 
    double *Out3, double *Out4, double *Out5);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // !_MYMODEL      

MATLAB (r2018b):

%% Input to model
FILEA       = 'PATH\FILEA.txt';
FILEB       = 'PATH\FILEB.txt';
IDTask      = 1; %Multiple tasks possible in the .dll
%% Determine pointers
lpFILEA         = libpointer('cstring', FILEA);
lpFILEB         = libpointer('cstring', FILEB);
lpIDTask        = libpointer('int32Ptr', IDTask);
lpnErrorCode    = libpointer('int32Ptr');
lpErrorCode     = libpointer('int32Ptr');
lpProps         = libpointer('doublePtr');
lpOut1          = libpointer('doublePtr');
lpOut2          = libpointer('doublePtr');
lpOut3          = libpointer('doublePtr');     
lpOut4          = libpointer('doublePtr');
lpOut5          = libpointer('doublePtr');      

%% LoadLibrary
    [notfound, warnings] = loadlibrary('MYMODEL.dll','MYMODEL.h' ,'mfilename', 'mHeader');
%% Call .dll
[~,~, ~, nErrorOut, ErrorCodeOut, PropsOut, Out1_, ~, ~, Out4_, Out5_] ...
    = calllib('MYMODEL', 'MYFUN', lpFILEA, ...
    lpFILEB, lpIDTask, lpnErrorCode, lpErrorCode, lpProps, lpOut1, ...
    lpOut2, lpOut3, lpOut4, lpOut5);

Заранее спасибо за помощь!

1 Ответ

0 голосов
/ 22 января 2019

Я думаю, что ваша проблема в том, что вы передаете NULL-указатели в функцию FORTRAN, которая затем попытается записать на недопустимый адрес. Сначала нужно выделить память для выходов и передать указатели на эту память в вашу функцию. Примерно так:

% Input to model
FILEA       = 'PATH\FILEA.txt';
FILEB       = 'PATH\FILEB.txt';
IDTask      = 1;
% Determine pointers
lpnErrorCode    = libpointer('int32Ptr',0); % !!! You need to know the size of these outputs!
lpErrorCode     = libpointer('int32Ptr',0);
lpProps         = libpointer('doublePtr',zeros(10,1)); 
lpOut1          = libpointer('doublePtr',zeros(4,1));
lpOut2          = libpointer('doublePtr',zeros(8,1));
lpOut3          = libpointer('doublePtr',zeros(2,1));     
lpOut4          = libpointer('doublePtr',zeros(5,1));
lpOut5          = libpointer('doublePtr',zeros(7,1));      

% LoadLibrary
[notfound, warnings] = loadlibrary('MYMODEL.dll','MYMODEL.h' ,'mfilename', 'mHeader');
% Call DLL
calllib('MYMODEL', 'MYFUN', [uint8(FILEA),0], [uint8(FILEB),0], ...
        IDTask, lpnErrorCode, lpErrorCode, lpProps, lpOut1, ...
        lpOut2, lpOut3, lpOut4, lpOut5);
% Get output values
nErrorCode = lpnErrorCode.Value;
clear lpnErrorCode
ErrorCode = lpErrorCode.Value;
clear lpErrorCode
% ... etc.

Для каждого из этих выходов я создал данные, используя функцию zeros. Первые два - скалярные значения (один элемент данных), остальные - массивы разных размеров. Я понятия не имею, чего ожидает ваша функция на Фортране, поэтому я просто придумал несколько размеров. Пожалуйста, проверьте свою функцию, чтобы увидеть, на какие размеры памяти должен указывать каждый указатель.

Обратите внимание, что я также изменил способ передачи входных данных в вашу функцию. MATLAB должен автоматически преобразовывать данные в нужные типы. [uint8(FILEA),0] создает строку c-стиля с нулем в конце из массива MATLAB char FILEA. В C строки должны заканчиваться нулем. Я не знаю, как FORTRAN определяет длину строки, я предполагаю, что она одинакова, так как функция использует интерфейс "C".

...