天天看點

MATLAB調用非MEX類型動态庫

    在matlab指令行下調用現有的動态連接配接庫即Dll檔案,即非MEX檔案。因為DLL的編寫者生成該dll時未必想到以後會被Matlab調用,是以未必會有mexFunction入口。但是這樣的動态連接配接庫占多數,是以知道調用方法還是必要的。

    Matlab加載并調用,關閉Dll通過loadlibrary/calllib/unloadlibrary

    一般在windows下開發DLL程式使用的都是vc++6.0及其後版本。雖然在工程向導裡有生成Dll的步驟,但是,通過那種預設方式生成的Dll接口是針對C++的,Matlab載入該dll後不能直接調用,得生成c語言類型接口。

    比如要建立一個名為MsgBox.dll的動态連接配接庫,其導出唯一的一個接口matMessageBox。用vc++6預設生成的代碼如下:

MsgBox.h檔案

#ifdef MSGBOX_EXPORTS
#define MSGBOX_API __declspec(dllexport)
#else
#define MSGBOX_API __declspec(dllimport)
#endif      

MsgBox.c檔案

#include "MsgBox.h"
#include <windows.h>
BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
        case DLL_PROCESS_ATTACH:
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
    }
    return TRUE;
}

MSGBOX_API unsigned int matMessageBox(char* caption,char* contain,unsigned int type)
{
    ::MessageBox(NULL,caption,contain,type);
    return 0;
}      

編譯後生成的Dll檔案用Dependency打開

MATLAB調用非MEX類型動态庫

導出的函數名很明顯是c++風格的。看下這種接口是否能被加載(把頭檔案和dll拷到matlab工作目錄下):

MATLAB調用非MEX類型動态庫

看來是加載了,不能調用指定函數是以失敗了。

那怎樣生成C語言接口的DLL?

很簡單,聲明函數時,加上extern "C",具體extern "C"的作用是啥還得問隔壁百度

修改後的頭檔案(僅修改頭檔案聲明即可,cpp不用修改)

#ifdef MSGBOX_EXPORTS
#define MSGBOX_API __declspec(dllexport)
#else
#define MSGBOX_API __declspec(dllimport)
#endif

#ifdef __cplusplus
extern "C" {
#endif

MSGBOX_API unsigned int matMessageBox(char*,char*,unsigned int);

#ifdef __cplusplus
}
#endif      

看下這時生成的DLL的接口:

MATLAB調用非MEX類型動态庫

嗯,有點像C風格的接口了,看下調用結果

MATLAB調用非MEX類型動态庫

終于彈出對話框了。

後記,C語言的參數少不了有指針類型,就像這裡的MsgBox封裝了WinAPI MessageBox,該函數第一個參數就是void*類型。如何傳入指針類型參數?可參考Matlab幫助文檔:

External Interfaces-Matlab Interface to Generic DLLS-Data Conversion章節

這裡給出一個簡單例子

還是MsgBox,不過這次要傳入指針參數:

#ifdef MSGBOX_EXPORTS
#define MSGBOX_API __declspec(dllexport)
#else
#define MSGBOX_API __declspec(dllimport)
#endif

#include <windows.h>

#ifdef __cplusplus
extern "C"
{
#endif

MSGBOX_API unsigned int matMessageBox(HANDLE,char*,char*,unsigned int);

#ifdef __cplusplus
}
#endif      
>> loadlibrary('MsgBox.dll','MsgBox.h')
>> hnd=0;
>> hndPtr=libpointer('int32Ptr',hnd)
>> calllib('MsgBox','matMessageBox',hndPtr,'123','456',0)