【问题标题】:Attempt to call dll function from matlab causing crash尝试从matlab调用dll函数导致崩溃
【发布时间】:2011-04-25 18:59:19
【问题描述】:

我正在尝试在 MATLAB 中使用第三方外部 DLL(来自 usbmicro),但它不断使 MATLAB 崩溃。这是来自说明从 C 程序中调用函数的语法的文档:

int USBm_About( char *about );

我试过这个 MATLAB 脚本(是的,它很笨拙,我是 MATLAB 菜鸟):

>> loadlibrary('USBm.dll','USBmAPI.h')
>> libfunctions('USBm')
>> s='sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss';
>> st=strcat(s,s,s,s);
>> vp = libpointer('voidPtr',[int8(st) 0]);
>> result=calllib('USBm','USBm_About',vp)

还有这个:

>> loadlibrary('USBm.dll','USBmAPI.h')
>> libfunctions('USBm')
>> s='sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss';
>> st=strcat(s,s,s,s);
>> vp=libpointer('cstring',st);
>> result=calllib('USBm','USBm_About',vp)

在这两种情况下,calllib() 调用都会导致 MATLAB 因分段错误而崩溃。

MATLAB的版本是7.10;操作系统是 Windows Vista。


更新:

这是 libfunctionsview USBm 的截图:

这是头文件:

#ifndef FILE_USBmAPI_h
#define FILE_USBmAPI_h


// Prototypes for this DLL.
// These are the API functions available to the .dll user.


// Discovery routine
extern "C" __declspec(dllexport) int USBm_FindDevices(void);

// Return info about devices
extern "C" __declspec(dllexport) int USBm_NumberOfDevices(void);
extern "C" __declspec(dllexport) int USBm_DeviceValid(unsigned char);
extern "C" __declspec(dllexport) int USBm_DeviceVID(unsigned char);
extern "C" __declspec(dllexport) int USBm_DevicePID(unsigned char);
extern "C" __declspec(dllexport) int USBm_DeviceDID(unsigned char);
extern "C" __declspec(dllexport) int USBm_DeviceFirmwareVer(unsigned char);
extern "C" __declspec(dllexport) int USBm_DeviceMfr(unsigned char, char *);
extern "C" __declspec(dllexport) int USBm_DeviceProd(unsigned char, char *);
extern "C" __declspec(dllexport) int USBm_DeviceSer(unsigned char, char *);

// General USBmicro U4xx device access
extern "C" __declspec(dllexport) int USBm_ReadDevice(unsigned char, unsigned char *);
extern "C" __declspec(dllexport) int USBm_SetReadTimeout(unsigned int);
extern "C" __declspec(dllexport) int USBm_WriteDevice(unsigned char, unsigned char *);
extern "C" __declspec(dllexport) int USBm_CloseDevice(unsigned char);

// DLL string info access
extern "C" __declspec(dllexport) int USBm_RecentError(char *);
extern "C" __declspec(dllexport) int USBm_ClearRecentError(void);
extern "C" __declspec(dllexport) int USBm_DebugString(char *);
extern "C" __declspec(dllexport) int USBm_Copyright(char *);
extern "C" __declspec(dllexport) int USBm_About(char *);
extern "C" __declspec(dllexport) int USBm_Version(char *);



// General U4x1 device functions
// -----------------------------

// Port initialization
extern "C" __declspec(dllexport) int USBm_InitPorts(unsigned char);
extern "C" __declspec(dllexport) int USBm_InitPortsU401(unsigned char);
extern "C" __declspec(dllexport) int USBm_InitPortsU421(unsigned char);
extern "C" __declspec(dllexport) int USBm_InitPortsU451(unsigned char);

// Port/bit reading and writing
extern "C" __declspec(dllexport) int USBm_WriteA(unsigned char, unsigned char);
extern "C" __declspec(dllexport) int USBm_WriteB(unsigned char, unsigned char);
extern "C" __declspec(dllexport) int USBm_WriteABit(unsigned char, unsigned char, unsigned char);
extern "C" __declspec(dllexport) int USBm_WriteBBit(unsigned char, unsigned char, unsigned char);
extern "C" __declspec(dllexport) int USBm_ReadA(unsigned char, unsigned char *);
extern "C" __declspec(dllexport) int USBm_ReadB(unsigned char, unsigned char *);
extern "C" __declspec(dllexport) int USBm_SetBit(unsigned char, unsigned char);
extern "C" __declspec(dllexport) int USBm_ResetBit(unsigned char, unsigned char);

// Port direction
extern "C" __declspec(dllexport) int USBm_DirectionA(unsigned char, unsigned char, unsigned char);
extern "C" __declspec(dllexport) int USBm_DirectionAOut(unsigned char);
extern "C" __declspec(dllexport) int USBm_DirectionAIn(unsigned char);
extern "C" __declspec(dllexport) int USBm_DirectionAInPullup(unsigned char);
extern "C" __declspec(dllexport) int USBm_DirectionB(unsigned char, unsigned char, unsigned char);
extern "C" __declspec(dllexport) int USBm_DirectionBOut(unsigned char);
extern "C" __declspec(dllexport) int USBm_DirectionBIn(unsigned char);
extern "C" __declspec(dllexport) int USBm_DirectionBInPullup(unsigned char);

// Strobbing a byte of data
extern "C" __declspec(dllexport) int USBm_StrobeWrite(unsigned char, unsigned char, unsigned char, unsigned char);
extern "C" __declspec(dllexport) int USBm_StrobeRead(unsigned char, unsigned char *, unsigned char, unsigned char);
extern "C" __declspec(dllexport) int USBm_StrobeWrite2(unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char);
extern "C" __declspec(dllexport) int USBm_StrobeRead2(unsigned char, unsigned char *, unsigned char, unsigned char, unsigned char, unsigned char);
extern "C" __declspec(dllexport) int USBm_StrobeWrites(unsigned char, unsigned char *, unsigned char *);
extern "C" __declspec(dllexport) int USBm_StrobeReads(unsigned char, unsigned char *, unsigned char *);

// Reading pin-change latches
extern "C" __declspec(dllexport) int USBm_ReadLatches(unsigned char, unsigned char *);

// LCD routines
extern "C" __declspec(dllexport) int USBm_InitLCD(unsigned char, unsigned char, unsigned char);
extern "C" __declspec(dllexport) int USBm_LCDCmd(unsigned char, unsigned char);
extern "C" __declspec(dllexport) int USBm_LCDData(unsigned char, unsigned char);

// SPI routines
extern "C" __declspec(dllexport) int USBm_InitSPI(unsigned char, unsigned char);
extern "C" __declspec(dllexport) int USBm_SPIMaster(unsigned char, unsigned char *, unsigned char *);
extern "C" __declspec(dllexport) int USBm_SPISlaveWrite(unsigned char, unsigned char, unsigned char *);
extern "C" __declspec(dllexport) int USBm_SPISlaveRead(unsigned char, unsigned char *, unsigned char *);

// 2-wire routines
extern "C" __declspec(dllexport) int USBm_Wire2Control(unsigned char, unsigned char *);
extern "C" __declspec(dllexport) int USBm_Wire2Data(unsigned char, unsigned char *);

// Stepper routine
extern "C" __declspec(dllexport) int USBm_Stepper(unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char);

// 1-wire routines
extern "C" __declspec(dllexport) int USBm_Reset1Wire(unsigned char, unsigned char *);
extern "C" __declspec(dllexport) int USBm_Write1Wire(unsigned char, unsigned char);
extern "C" __declspec(dllexport) int USBm_Read1Wire(unsigned char, unsigned char *);
extern "C" __declspec(dllexport) int USBm_Write1WireBit(unsigned char, unsigned char);
extern "C" __declspec(dllexport) int USBm_Read1WireBit(unsigned char, unsigned char *);




#endif // multiple inclusion prevention

// End of file
//---------------------------------------------------------------------------

更新:

我尝试改变这一行:

extern "C" __declspec(dllexport) int USBm_About(char *);

到这里:

extern "C" __declspec(dllimport) int USBm_About(char *);

在头文件中,然后重新启动 MATLAB。我再次运行我的代码,MATLAB 仍然崩溃。

【问题讨论】:

  • 如果没有 USBmAPI.h 并且不知道 USBm_About 的参与规则,我们如何才能解决这个问题?
  • 这是在原始帖子中: int USBm_About( char *about );然后我刚刚添加了“libfunctionsview USBm”输出的屏幕截图。如果您需要更多信息,请直接询问。

标签: c matlab dll shared-libraries loadlibrary


【解决方案1】:

我从USBmicro 网站下载了DLL,并尝试通过调用loadlibrary()use it。不幸的是,正如你所说,这使我的 MATLAB 会话崩溃了..

research 之后,我发现这个 DLL 公开其函数的方式与 MATLAB 期望的调用约定(cdecl 与 stdcall)不兼容。

这是我修复头文件的方法:

#ifndef FILE_USBmAPI_h
#define FILE_USBmAPI_h

#ifdef __cplusplus
extern "C" {
#endif

// ...
int __stdcall USBm_About(char *);
int __stdcall USBm_Version(char *);
// ...

#ifdef __cplusplus
}
#endif

#endif

现在您可以调用任何导出的函数。示例:

%# load library and see exported functions signatures
if ~libisloaded('USBm')
    loadlibrary('USBm.dll','USBmAPI.h')
    libfunctions('USBm','-full')
end

%# call the function: `int USBm_About(char *)`
str = repmat(' ',1,100);                           %# allocate buffer
pStr = libpointer('stringPtr',str);                %# pointer to string
[num str2] = calllib('USBm','USBm_About',pStr)
clear pStr

%# unload library
unloadlibrary USBm

注意 MATLAB 给我们的函数的签名:

[int32, cstring] USBm_About(cstring)

有趣的是,它有一个用于此函数的附加输出参数。原因是 MATLAB 并不真正支持按引用传递,尽管您可以创建与 C 指针兼容的 MATLAB 参数。

因此,如果 C 函数在通过引用传递的输入参数中返回数据,MATLAB 将创建额外的输出参数来返回这些值(以及以 PtrPtrPtr 结尾的任何输入参数)。

现在虽然输入参数pStr 类似于指向类型char 的指针,但它不是一个真正的参数,因为它不包含MATLAB 字符数组str 的地址。当函数执行时,它会返回正确的结果,但不会修改 str 中的值(在这种情况下也不会修改 pStr)。

我得到的输出是:

>> num
num =
     0

>> str2
str2 =
 USBm.dll by USBmicro L.L.C. (www.usbmicro.com). Supports: U401, U421

【讨论】:

    【解决方案2】:

    这可能是你的包含文件需要有的标准问题

    extern "C" __declspec(dllexport)
    

    当您正在构建 .dll 但 Matlab(或使用您的 .dll 的任何项目)需要:

    extern "C" __declspec(dllimport)
    

    当你包含它时。

    这就是为什么人们通常有以下宏:

    #ifdef USBMAPIEXPORTS 
    #define USBMAPIDECLSPEC __declspec(dllexport)
    #else
    #define USBMAPIDECLSPEC __declspec(dllimport)
    #endif
    

    然后在标题中的函数上编写:

    extern "C" USBMAPIDECLSPEC int USBm_FindDevices(void);    
    

    并且您需要在构建 .dll 时定义 USBMAPIEXPORTS(但在 Matlab 中使用时不需要)。

    请注意,这不是 Matlab 的问题。 This is the standard way to use a .dll. 你试过了吗?

    【讨论】:

    • DLL 来自第三方。我没有来源。因此,从您所看到的情况来看,当前形式的 dll 不适用于 matlab?
    • 在我看来,无论谁给你包含文件,都没有做对。我会将包含文件USBmAPI.h 修改为另一个文件(首先进行备份),以便每当您看到extern "C" __declspec(dllexport) 时将其更改为extern "C" __declspec(dllimport)。 (或者,您可以使用定义我在上面编写的预处理器块,然后编写extern "C" USBMAPIDECLSPEC。如果这样做,请确保不要定义USBMAPIEXPORTS。)
    • 我还会告诉您的 .dll 和 .h 文件的提供者,以便将来按照我在原始回复中所说的那样做。它们应该是在构建时定义 USBMAPIEXPORTS 的那些。这是标准的,可以省去很多麻烦。需要明确的是,他们正确构建了 .dll,只是没有让您轻松包含。
    • 我尝试用 dllimport 替换所有 dllexports,但仍然得到相同的结果。我还尝试了 USBm_Copyright,这也导致了分段违规。
    • 我看到 OP 也发布在 MATLAB 上 答案:mathworks.com/matlabcentral/answers/…
    猜你喜欢
    • 1970-01-01
    • 2015-12-05
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 2016-04-23
    • 1970-01-01
    • 2022-06-11
    • 1970-01-01
    相关资源
    最近更新 更多