VC++与MATLAB接口编程方法与实现

VC++与MATLAB接口编程方法与实现

摘 要 本文简介了VC++和MATLAB特点,探讨了MATLAB与VC++接口编程的三种 方法,并详细论述了MCC和COM组件接口编程的方法和实现过程。 研究表明:采用VC++和MATLAB 接口编程方法降低了编程难度,较好地发挥了两者各自的优势。
    关键词 MATLAB;VC++;MCC;COM;接口编程
    MATLAB是美国MathWorks公司研制开发的一种 科学 计算软件,它将高性能的数值计算、符号计算和可视化集成在一起,并提供了大量的内置函数以及功能丰富的工具箱,使用方便,编程效率高。然而,MATLAB是一种解释性语言,运行效率低,不适合作为通用的编程平台。
    VC++是Microsoft公司推出的一个基于 Windows平台的可视化的集成开发环境,在运行速度、功能性以及 应用程序界面开发方面功能强大,但在数值计算和图形绘制方面,VC++并不具备太多优势。因此,采用MATLAB进行核心程序的开发,用VC++制作出友好的程序界面,然后将两者结合起来,可以较大地提高编程效率。
1 VC++与MATLAB接口方法概述1.1 MATLAB引擎方式
    MATLAB引擎采用客户机/服务器(Client/Server) 的方式,提供了一组MATAB API函数,通过调用这些函数实现以用程序进程之间的数据传递。在运用中,让VC++程序作为前端客户机,它向MATLAB引擎传递命令和数据,并从MATLAB引擎接受数据信息,实现动态通讯。
1.2 MATLAB编译器(MCC)
    MCC是MATLAB中经过优化的编译器。使用MCC,用户可以将MATLAB数学库、图形库和界面的MATLAB程序转化为独立于MATLAB的EXE应用程序和DLL动态连接库,在VC中编写程序界面并加载调用动态连接库,实现两者之间的连接。
1.3 COM组件
    组件对象模型(简称MCR)是以组件为发布单元的对象模型。它提供一种可以共享二进制代码的 工业标准,允许任何符合标准的程序访问,所以COM作为不同语言之间的协作开发是非常方便的。MATLAB的COM编译器是在MATLAB6.5中才开始提供的一个新工具,从MATLAB7.0起,这个产品改名为MATLAB Builder for COM。基于COM的混合编程方法也是Mathworks公司推荐使用的方法。

    以上三种方法中,采用MATLAB引擎方式,应用程序整体性能好,MATLAB引擎支持功能全面,但需要MATLAB后台运行,不能脱离MALAB环境。而 MCC方法和COM组件方法均可以脱离MATLAB环境,应用程序运行效率高,利于软件的开发,本文将重点论述MCC和COM组件方法。

[我在书上看到还有一种方法:就是在vc中生成matlab可以调用的DLL程序:专用的接口函数mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs *prhs[]),的方式]

[有关mex的初探

(一下内容来自网友博客http://hi.baidu.com/wangyantsing/blog/item/c1cecfbf1333a20918d81f2f.html

感谢)

在matlab的自带编辑器中输入如下代码,并保存为fact.c,存在系统工作目录中。
#include "mex.h"

void mexFunction (
        int nlhs,mxArray *plhs[],
        int nrhs,const mxArray *prhs[]
    )
{
    double n,j,*p;
    int i;
    
    n=mxGetScalar(prhs[0]);
    plhs[0]=mxCreateDoubleMatrix(1,1,mxREAL);
    p=mxGetPr(plhs[0]);

    j=1.0;
    for(i=n;i>1;i--)
    j=j*i;
    *p=j;
}

    这仅仅是一个求阶乘的简单的例子。

    然后,我在matlab中输入>>mex fact.c    
    
    如果没有错误,一切都将十分正常,然后,我输入
    >>y=fact(5)    
    将输出y=
            120
]

[今天又在网上看到用matcom]

[  MATCOM转化法

  MATCOM是MathWorks公司开发的为MATLAB中的M文件进行高效解释和调试的集成开发环境。MATCOM编译M文件,先将M文件按照与MATCOM的cpp库的对应关系,翻译为cpp源代码,然后用C编译器将cpp文件编译成相应的exe或dll文件。

  用MATCOM方式,生成的代码可读性好,支持图形函数,支持M文件编译过程中的文件嵌套情况,可脱离MATLAB环境;缺陷为待编译的M文件不能涉及MATLAB的内部类。


  MATCOM转化法 

  以下介绍均以MATLAB 6.5、MATCOM 4.5、VC++ 6.0和Windows XP为例进行说明。

  MATLAB包括数学函数和工具箱函数,MATCOM已经将一般数学函数进行编译,可以遵循MATCOM语言规则直接在VC++中使用;要使用工具箱函数,则需要在MATCOM下编译MATLAB的M文件。如图1所示。


图1 MATCOM转换法示意图

  1、只使用MATLAB一般数学函数

  将Windows中的系统文件v4501v.dll与ago4501.dll以及MATCOM中的文件matlib.h与v4501.lib加入VC++工程目录,然后在程序中包含文件matlib.h和链接文件v4501.lib。安装MATCOM后,会在安装路径上自动生成文件refguide.pdf,其中所列的函数均可在VC++中直接使用。

  2、使用MATLAB数学函数和工具箱函数

  当所需函数不在refguide.pdf中时,在完成上面步骤后,可利用MATCOM将所需函数的M文件转换为cpp文件或dll文件后加入VC++工程使用。MATCOM使用简单,在此就不仔细陈述转换过程了。特别需要提出的是,在转换过程中若有M文件嵌套情况出现,所有M文件应在同一目录下。

 下面以VC++下调用MATLAB随机函数、噪声函数、通信工具箱中数字调制和解调函数为例,说明MATCOM在工程开发中的应用。

  (1)使用MATCOM将MATLAB中随机函数randint、噪声函数awgn、数字调制函数dmod和解调函数ddemod的M文件转化为VC++的h文件和cpp文件。

  (2) 建立VC++工程,将所需文件加入工程。

  (3) 遵循MATCOM语言格式,使用随机函数产生随机二元序列,经数字调制后加噪声,再经数字解调函数解调出二元序列。 

  图2为此VC++程序运行时的界面(单色处理后):



图2 VC++仿真程序运行界面

  结束语

  使用MATCOM实现MATLAB和VC++的混合编程,是开发数据处理应用软件的有效途径。此种方法的优势主要如下:

  (1) 提供了MATLAB中的大量成熟函数 。

  (2) 充分发挥出MATLAB强大的数据可视化功能。

  (3) 发挥出强大开发工具VC++的Windows平台优势。

  (4) 程序可脱离MATLAB运行环境。

  综上所述,MATCOM转换法最大限度地利用了上述各种软件的特长,将高难度的算法研究与实际应用结合在一起,达到了程序简洁、编程效率提高和算法更易实现的目的。在开发过程中,已有编程经验的研究人员,只要熟悉MATLAB的函数调用、语法格式,就可以通过调用函数快速地解决问题,不必花费大量的时间与精力研究具体的算法,而是更专注于专业方面的研究。

]

2 MATLAB编译器(MCC)2.1 MATLAB与VC++接口配置
    采用MCC方法需要对MATLAB和VC++接口设置,配置步骤如下:
    1) MATLAB编译器配置
    首先在MATLAB命令提示符下输入mbuild-setup 命令,选择编译器,(需要注意的是必须确保计算机上已经安装了某个版本的VC++,本文选择visual C++6.0)完成编译器设置。
    2) VC++环境设置
    (1)设定头文件和库文件路径。在VC++环境菜单栏中选择Tools->Options->Directories,在“Show directories for”栏中首先选择Include files,然后在“directories”中将<matlab7.0安装目>\Extern\Lib\Win32\ Microsoft \MSVC++60添加进去。再次在“Show directories for”栏中选择Librarys files,再在“directories”中添加<matlab7.0安装目录>\Extern\Include。
    (2)设置编译连接选项。在VC++环境菜单栏中选择Project ->setting,然后选择link选项卡,在object/library modules栏中添加mclmcrrt.lib libtest.lib;选择General选项卡,在Microsoft Foundation Classes栏中选择Use MFC in a Shared Library。
2.2 实例演示
    完成MATLAB和VC++的接口设置以后,就可以实现MATLAB和VC++的接口编程,具体步骤如下:
    1) 编写M函数文件“mypascal.m”
    function m=mypascal(n)
    m=pascal(n);
    m=m';
    示例M函数文件的作用是生成一个n阶的帕斯卡矩阵并返回,Pascal矩阵特点:第一行和第一列的元素均为1,其他位置的元素是前方的元素和上方的元素之和。需要注意的是:由于MATLAB中矩阵存储方式是以矩阵的列为先,也就是数据从第一列开始逐列存储的,而C/C++中矩阵则是以第一行开始逐渐存储的,因此在函数的最后一行对返回矩阵取转置运算,等效于使得计算得到的矩阵数据以行模式存储。
    2) 编译M文件
    在MATLAB命令行输入mcc-B csharedlib:libtest mypascal.m-v命令(或mcc-W lib:libtest-T link:lib mypascal.m)将m文件编译成C共享动态链接库文件。命令执行完毕后,在当前目录中生成C头文件 (libtest .h) 、引入库文件 (libtest.lib) 、ctf(libtest.ctf) 文件、动态链接库文件 (libtest.dll) 、C源文件 (libtest.c)等8个文件。
    3) 创建工程对话框

    运行visual C++创建一个对话框工程,取名为test,接受所有默认的设置。去掉对话框上的静态文本和按钮,增加一个按钮、一个静态文本框、编辑框以及一个List Control,鼠标右键单击List Control,选择Properties,把View改成Report,对话框界面如图1所示。给List Control控件添加ClistCtrl类的对象m_List,给编辑框关联一个整型成员变量m_size,给按钮增加一个消息响应函数。
图 1
    4) 添加编译文件到工程
    将mcc编译生成的“libtest.h”、“libtest.dll”、“libtest.lib”,“libtest.ctf”四个文件复制到工程目录,将libtest.h加入工程,并在对话框程序文件“testDlg.cpp”中添加头文件“libtest.h”。
    5) VC++中调用动态连接库
    ① 在OnInitDialog()函数中添加初始化libtest.dll进程的码:
BOOL CTestDlg::OnInitDialog()
{
     CDialog::OnInitDialog();
     // TODO: Add extra initialization here
     if (!mclInitializeApplication(NULL,0))
     {AfxMessageBox("不能初始化程序!");exit(1);}
     if (!libtestInitialize()) {AfxMessageBox("不能初始化连接库!");exit(1);}
     return TRUE; // return TRUE unless you set the focus to a control
}
    ② 在void CTestDlg::OnCreatebuttom()函数中添加以下代码,实现对mypascal.m的调用,并将计算结果显示在对话框界面中。
void CTestDlg::OnCreatebuttom()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
double data;
data=double(m_size);
mxArray *size; //输入参数
mxArray *out=NULL; //输出参数
//创建mxArray数据对象,双精度标量
size=mxCreateDoubleScalar(data);
//内存复制赋值

memcpy(mxGetPr(size),&data,1*sizeof(double));        

mlfMypascal(1,&out,size);//函数调用 [第一个参数表示输出参数的个数这里有一个]

//结果数据显示

CString strtext;
int i,j;
//清除已显示的数据
m_List.DeleteAllItems();
intncolumn=m_List.GetHeaderCtrl()->
GetItemCount();
for (i=0;i<ncolumn;i++) m_List.DeleteColumn(0);
//设置标题栏
m_List.InsertColumn(0," ");//附空值
m_List.SetColumnWidth(0,60);//设置每栏宽度
for (i=0;i<m_size;i++)
     {
            strtext.Format("Column %d",i+1);
            m_List.InsertColumn(i+1,strtext);
            m_List.SetColumnWidth(i+1,60);
     }
//显示结果数据
for (i=0;i<m_size;i++)
     {
            strtext.Format("Row %d",i+1);
            m_List.InsertItem(i+1,strtext);
            for(j=0;j<m_size;j++)
            {
strtext.Format("%.f",*(mxGetPr(out)+i*m_size+j));
m_List.SetItemText(i,j+1,strtext);
            }
     }
mxDestroyArray(size);//数据内存释放
mxDestroyArray(out);
}
    ③ 利用ClassWizard为对话框添加OnDestroy()函数,并添加以下代码:
void CTestDlg::OnDestroy()
{   CDialog::OnDestroy();
     // TODO: Add your message handler code her
     libtestTerminate();//终止进程
     mclTerminateApplication();//终止MCR
}
    在VC++中编译、运行结果如图2所示,与在MATLAB中运行M文件的结果一样。

图2

6) 独立应用程序的发布

发布独立的应用程序时,需要拷贝以下几个文件到目标机器上:MCRInstaller.exe,这个文件位于<matlab7.0安装目录>\tool-box\compiler\deploy\ win32目录之下,应用程序运行前要先点击运行MCRInstaller.exe文件,按照提示步骤安装好MCR,然后将工程文件的可执行程序(.exe)、共享库(.dll)以及其对应的ctf文件复制到目标 计算机即可独立运行。
3 COM组件3.1 MATLAB里创建COM组件
    使用COM组件 方法首先需要在MATLAB中创建COM组件,步骤如下:
    1) 创建COM组件
    在MATLAB命令窗口输入命令comtool,打开Matlab Builder对话框,它是Matlab builder for com的主要工作环境。点击File->New Project,会弹出一个新工程设置对话框,填入组件名和类名,完成之后点OK,完成新工程的创建。如果选择的工程所在目录并不存在,comtool会提示该目录不存在,并询问是否创建该目录,选择Yes,comtool就会创建工程到该目录。
    2) 添加M文件到组件
    执行完第一步后回到matlab builder界面。点击刚才创建的工程,单击Add files按钮,将M文件添加到新建的组件类中。然后点击Build->COM Object编译当前工程的COM组件,这个步骤不仅编译了COM组件,同时也在计算机上注册了该组件,它可以像其他COM组件一样在VC++中使用。编译完成以后在用户设置的项目目录下将产生两个子文件夹src和distrib,src里包含组件的源代码,distrib里包含供用户最终发布使用的COM组件。
    3) 打包组件及MCR
    编译结束后产生的COM组件只能在当前计算机上使用,为了能够把它发布到其他计算机上使用,还需要其他一些支持文件。另外,COM组件不同于普通的DLL文件,COM组件必须注册后才能在计算机上使用。选择Component->package component命令,comtool将会把发布该组件所需要的所有文件打包到一个和工程同名的可执行文件中。这里可以选择是否在打包文件中包含MCR。MATLAB7.0产生的COM组件必须运行在MCR环境。如果目标计算机上没有安装MCR,那么在打包组件的时候最好选择包含MCR,这样在打包文件中就会包含MCR的安装文件。打包完成后将会在distrib中产生.exe的可执行文件,这是一个可以自解压的压缩文件。其中包含4个文件:_install.bat,dll文件,ctf文件,MCRInstaller.exe。把产生的.exe文件复制到需要发布的计算机上运行。结果将会把这四个文件解压,并执行_install.bat,这是一个DOS批处理文件,查看_install.bat的 内容后可以发现_install.bat将会运行MCRInstaller.exe来安装MCR,并且在系统中注册组件文件。
3.2 实例演示
    这里仍旧采用上例“mypascal.m”文件,按照3.1介绍的步骤创建COM组件,组件名取Tpascal,类名取Tpascalclass。运行visual C++创建一个与上例一样对话框工程,对话框设置也与上例一样。然后在MFC工程中进行如下操作:
    1) 导入DLL文件
    将distrib文件夹里Tpascal_1_0.dll拷贝到工程文件夹,然后用VC++命令#import来把Tpascal_1_0.dll导入工程中,#import命令的作用是从Tpascal_1_0.dll中导入组件中的接口类型定义,具体做法是在stdafx.h里,加入下面两行:
#import "Tpascal_1_0.dll" raw_interfaces_only
using namespace Tpascal;
    2) 为工程对话框添加实 现代
    在对话框按钮消息响应函数中编写调用组件代码:
void CTestDlg::OnCreatebutton()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
CoInitialize(NULL);       //初始化COM
//得到COM对象的CLSID      
CLSID clsid;
HRESULT hr;
hr=CLSIDFromProgID(OLESTR("Tpascal.Tpascalclass.1_0"),&clsid);
//创建一个COM对象的实例
ITpascalclass *pIpascal;
hr=CoCreateInstance(clsid,NULL,CLSCTX_INPROC_ SERVER,__uuidof(ITpascalclass),(LPVOID *) &pIpascal);
if (FAILED(hr))//测试创建是否成功
{ AfxMessageBox("create failed");
return;
}
//初始化VARIANT变量
VARIANT size,out;
VariantInit(&size);
VariantInit(&out);
//创建size,类型为VT_R8,即double型
size.vt=VT_R8;
size.dblVal=(double)m_size;
//创建二维数组out,类型为VT_ARRAY,ARRAY中的元素为double型
out.vt=VT_ARRAY|VT_R8;
SAFEARRAYBOUND bound[2];
//设置第一维数组元素个数、元素索引下界
bound[0].cElements=m_size;
bound[0].lLbound=0;
//设置第二维数组元素个数、元素索引下界
bound[1].cElements=m_size;
bound[1].lLbound=0;     out.parray=SafeArrayCreate(VT_R8,2,bound);
pIpascal->mypascal(1,&out,size); //函数调用
//返回值传递
double *matrix,* pDest;
matrix=new double[m_size*m_size];
SafeArrayAccessData(out.parray,(void**)&pDest);//获得数据指针,访问数据
memcpy(matrix,pDest,m_size*m_size*sizeof(double));// 拷贝数据矩阵
SafeArrayUnaccessData(out.parray);//释放数据指针,取消访问
SafeArrayDestroy(out.parray); //释放数组
//结果数据显示的代码与上例一样,此处省略……
delete []matrix; //释放指针
pIpascal->Release();
if(pIpascal!=NULL)
{
    pIpascal = NULL;
}
VariantClear(&size);//清空变量
VariantClear(&out);
CoUninitialize();//释放COM
}
    在VC++中编译、运行结果与上例一样,也与在MATLAB中运行M文件的结果一致。
    3) 独立程序的发布
    采用COM组件的方法的独立程序的发布,除了需要在目标计算机上运行打包组件产生的可执行文件Tpascal.exe,安装MCRInstaller.exe,并注册Tpascal_1_0.dll以外。还需要将MFC工程的可执行文件.exe拷贝到目标计算机上运行即可实现独立程序的发布。
4 结束语
    在软件开发过程中,为了提高软件的开发效率,接口编程是综合使用多种开发工具技术优势的一种常用手段。本文采用基于MCC和COM组件的VC++与MATLAB接口编程方法,具有实现简单、执行效率高、几乎支持所有的MATLAB函数、易于移植等优点,是解决矩阵处理、计算以及图像处理编程的一种有效途径,可以为 科学 研究和工程技术提供更强的技术支持。本文所有代码在环境为 Windows XP、MATLAB 7.0.1、VC++6.0下均调试通过。
参考文献
[1] 苏金明. MATLAB高级编程[M]. 北京: 电子 工业出版社,2005.215-220
[2] 董维国. 深入浅出MATLAB 7.x混合编程[M].北京: 机械工业出版社,2006.278-285
[3] 张威.MATLAB应用程序集成与发布[M].西安:西安电子 科技大学出版社,2005.186-198

 

转自http://blog.sciencenet.cn/blog-347289-539350.html

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值