Google
 
Back to index
引言
在 VC++ 里通过 dll 来调用 Matlab 的内嵌函数
1. 安装 Matlab 7 和 Visual Studio 2005
2. 让 Visual Studio 2005 找到 Matlab 的库文件和头文件
3. 创建测试工程
4. 疑难杂症
根据自己的 m 文件生成 dll 连接库
1. 编译 m 文件的基本指令
2. 编译例子 m 程序
3. 在 VC++ 里调用 m 程序生成的 DLL
m 文件转为 C 文件的语法
部分参考文献

本文重点讨论 Visual Studio 与 Matlab 的混合编程的问题。

引言

对于数学计算来说,用 Matlab 极其方便,于是,对于这么多用 Matlab 写成的库资源,我们如果不能在 Visual Studio 里使用,就太浪费了。

对于 Visual C++ 5.0 或是 6.0 来说,Matlab 提供了一个插件,可以在 Visual C++ 里直接进行 Matlab 的混合编程。可是对于更高版本的 Visual C++,Matlab 却没有这个插件。

这个时候,我们依然可以在 Visual Studio 里调用 Matlab 写好的程序,一般来讲,有下面三种方法:

1. 通过 mcc 将 Matlab 的 m 文件转化为 cpp、c 文件或 dll 供 VC++ 调用;

2. 通过 Matlab 的 combuilder 将 m 文件做成 COM 组件,供 VC++ 调用;

3. 通过 matcom 工具,不过 Mathworks 公司已经不在出新版本了,而且它的功能可以用第 1 和第 2 种方法代替推荐使用前两种方式。

本文主要介绍一下两大部分的内容:1. 如何用 Visual C++ 调用 Matlab 内置的函数;2. 如何用 Visual C++ 调用用户自己编写的 Matlab 函数。

在 VC++ 里通过 dll 来调用 Matlab 的内嵌函数

现在就用 Matlab 7 和 Visual Studio 2005 来举例,介绍一下如何在 Visual C++ 里调用 Matlab 的函数。

1. 安装 Matlab 7 和 Visual Studio 2005

Matlab 7 的安装没啥好说的,一路安装下去,记得安装完后重启电脑。不过为了方便起见,最好不要把 Matlab 安装到带有空格的路径里。

2. 让 Visual Studio 2005 找到 Matlab 的库文件和头文件

先把 Matlab 为 C++ 准备的头文件添加到 Visual Studio 2005 里:

在 Visual C++ 2005 里通过菜单 Tools ==> Options ==> Projects and Solutions ==> VC++ Directories ,把 Matlab 安装目录下的 extern/include 目录添加到 Include files 里(在我这里是 E:\MATLAB7\extern\include)

添加 Matlab 的头文件
添加 Matlab 的头文件

在同一个窗口里,选择 Library Files,然后把 Matlab 为 C++ 准备的库文件目录添加进去,直接把 Matlab 目录下的 extern/lib/win32/microsoft/msvc70 路径添加进去(根据相应的 VC++ 版本选择版本号,我这里是 E:\MATLAB7\extern\lib\win32\microsoft\msvc70)。

添加 Matlab 库文件
添加 Matlab 库文件

3. 创建测试工程

现在我们可以创建一个工程来测试一下在 VC++ 里能不能调用 Matlab 提供的 dll 文件。

可以创建一个名为 MatlabVSTest 的 console 工程,把 Precompiled 选项激活,然后通过菜单 Project ==> Properties ,在对话框里选择 Linker ==> Input ,把安装目录下的如下几个 lib 库文件添加进去:

E:\MATLAB7\extern\lib\win32\microsoft\msvc70\libmex.lib
E:\MATLAB7\extern\lib\win32\microsoft\msvc70\libmx.lib
E:\MATLAB7\extern\lib\win32\microsoft\msvc70\libeng.lib

然后把下面的代码放到你的程序文件里:

#include "stdafx.h"
#include <stdio.h>
#include <conio.h>
#include <memory.h>
#include <engine.h> //Located in $Matlab$\extern\include
#pragma comment( lib, "Libmx.lib" )
#pragma comment( lib, "libmex.lib" )
#pragma comment( lib, "libeng.lib" )
#define SIZE 50
int _tmain(int argc, _TCHAR* argv[])
{
    double x[SIZE], y1[SIZE], y2[SIZE];
    for (int i=0; i<SIZE; i++)
    {
        x[i]=((double)i)*0.1;
        y1[i]=x[i]*x[i];
        y2[i]=y1[i]*x[i];
    }
    Engine *m_pEngine;
    m_pEngine = engOpen(NULL);
    if (m_pEngine == NULL)
    {
        //Error! Fail to connect to MATLAB engine.
        // The plot function will be disabled!
        printf("Fail to open MATLAB Engine!\n");
        exit(0);
    }
    //Translate data from C++ to Matlab
    mxArray *m_X, *m_Y1, *m_Y2;
    m_X=mxCreateDoubleMatrix(1, SIZE, mxREAL);
    memcpy((void *)mxGetPr(m_X), (void *)x, sizeof(double)*SIZE);
    engPutVariable(m_pEngine, "x", m_X);
    m_Y1=mxCreateDoubleMatrix(1, SIZE, mxREAL);
    memcpy((void *)mxGetPr(m_Y1), (void *)y1, sizeof(double)*SIZE);
    engPutVariable(m_pEngine, "y1", m_Y1);
    m_Y2=mxCreateDoubleMatrix(1, SIZE, mxREAL);
    memcpy((void *)mxGetPr(m_Y2), (void *)y2, sizeof(double)*SIZE);
    engPutVariable(m_pEngine, "y2", m_Y2);
    //Plot by sending command to engine
    engEvalString(m_pEngine, "plot(x, y1, '-', x, y2, ':');");
    engEvalString(m_pEngine, "title('y_1/y_2 vs. x')");
    engEvalString(m_pEngine, "xlabel('x');");
    engEvalString(m_pEngine, "ylabel('y (Unit:10)');");
    printf("Press any key to close the plot...\n");
    getch();
    //Close plot window
    engEvalString(m_pEngine, "close;");
    engClose(m_pEngine);
    printf("Press any key to exit...\n");
    getch();
    return 0;
}

编译和运行上面的代码,看看你是否能得到下面的结果:

运行结果
运行结果

4. 疑难杂症

运行上面的代码,如果出现了如下的错误(如下图所示):

This application has failed to start because libmx.dll was not found. Re-installing the application may fix this problem.
Link Error
Link Error

这个时候,很可能是你安装完 Matlab 后没有重启电脑造成的。

根据自己的 m 文件生成 dll 连接库

很多情况下,我们会在 Matlab 里写一大堆的 m 文件,用以完成我们自己的工作。如果这部分算法是用 Matlab 完成的,我们需要在 C++ 里用到,我们可以直接把这些 m 文件编译成 dll ,从而在 C++ 里直接调用它们。

1. 编译 m 文件的基本指令

从 Matlab 的命令行里直接把 m 文件编译成 DLL ,可以使用下面的命令:

mcc -W lib:liba -T link:lib a0 a1

上面的命令从文件 a0.m 和 a1.m 生成一个名为 liba 的动态链接库。

上面这个命令会生成 mylib.dll, mylib.lib and mylib.h 等几个文件,如果想在 MSVC 里生成 debug 版本的程序,则需要加上 -g 这个参数。更多有关命令 mcc 的帮助可以在 Matlab 里查看 help mcc 来获得。

2. 编译例子 m 程序

我们可以试着用上面的命令来编译下面的程序,程序如下:

function y=MeanFunction(x)
[m,n]=size(x);
k=0;
for i=1:n
    k=k+x(i);
end
y=k/n;

我们用下面的命令来进行编译:

mcc -W lib:MeanFunctionLib -T link:lib MeanFunction.m

该命令会在当前的 work 目录生成 meanfunctionlib.h , meanfunctionlib.c, MeanFunctionLib.dll 和 MeanFunctionLib.lib 等相关文件。

3. 在 VC++ 里调用 m 程序生成的 DLL

我们新建一个 VC++ Console 工程,然后把下面的代码拷进去:

#include "stdafx.h"

#include "matlab.h"

#include "MeanFunctionLib.h"


#pragma comment(lib, "libmx.lib")
#pragma comment(lib, "libmatlb.lib")
#pragma comment(lib, "libmat.lib")
#pragma comment(lib, "libmmfile.lib")
#pragma comment(lib, "MeanFunctionLib.lib")

int main(int argc, char* argv[])
{
    mxArray* result;
    mxArray* x;
    double myArray[5]={10.2, 3, 6.3, 5.4, 5.9};

    x=mxCreateDoubleMatrix(1, 5, mxREAL);
    memcpy(mxGetPr(x), myArray, 5 * sizeof(double));

    MeanFunctionLibInitialize();

    result=mlfMeanfunction(x);

    MeanFunctionLibTerminate();

    mlfPrintMatrix(result);

    mxDestroyArray(x);
    mxDestroyArray(result);

    return 0;
}

m 文件转为 C 文件的语法

前面通过两个例子,简单地说明了如何在 VC++ 里调用 Matlab 内嵌的函数或是自己的函数,现在来详细说一下有关 Matlab 与 C 关联的语法,即如何从 C 语言的角度来解读 Matlab 的函数。

部分参考文献

参考文章出处:

1. http://wibirama.com/dip/wp-content/uploads/2008/11/matlab-and-ms-studio.pdf

2. http://www.codeproject.com/KB/cpp/matlab_cpp.aspx

3. http://www.codeproject.com/KB/DLL/MatlabSharedLib.aspx