我正在尝试在MATLAB中包含基于外部FORTRAN(与Intel Fortran编译器一起编译)的DLL。由于它是外部的,因此我无法对DLL的运行时库进行任何调整。目前,我用C ++编写了一个附带的头文件,以便能够调用DLL。使用loadlibrary
会将库加载到MATLAB中(没有错误-一个警告),但是,使用calllib
时MATLAB崩溃并且不提供错误。
我认为可能是以下原因之一,但是由于我对使用DLL(尤其是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);
在此先感谢您的帮助!
答案 0 :(得分:2)
我认为您的问题是您正在将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
函数创建了数据。前两个是标量值(一个数据元素),其他两个是各种大小的数组。我不知道您的FORTRAN函数在那儿会发生什么,所以我只是编了一些大小。请检查您的函数以查看每个指针应指向的内存大小。
请注意,我还更改了将输入数据传递给函数的方式。 MATLAB应该自动将数据转换为正确的类型。 [uint8(FILEA),0]
从MATLAB char数组FILEA
创建一个零终止的c样式字符串。在C中,字符串必须以零结尾。我不知道FORTRAN如何确定字符串的长度,我猜想是一样的,因为该函数使用“ C”接口。