独自摸索了一天时间,终于将MATLAB COM组件调用过程弄清楚了,将体会总结一下,以供大家分享。
第一步:编写m文件,测试正确性
编写m文件,m文件必须要有函数function,如:
function [ab1b2b3b4]=textMATLABCOM(z,v)
其中a,b1,b2,b3,b4均为返回值,二维数组。z、v为输入值,二维数组。
function [a b1 b2 b3 b4]=textMATLABCOM(z,v)
z2=zeros(1,0);
z3=zeros(1,0);
v2=zeros(1,0);
v3=zeros(1,0);
z2=z(1,:);
z3=z(2,:);
v2=v(1,:);
v3=v(1,:);
a=z2;
b1=z3;
b2=v2;
b3=v3;
b4=z;
测试文件:
z=[1 2 3 4 5; 6 7 8 9 10];
v=[2 3 4 5 6; 6 7 8 9 3];
[a b1 b2 b3b4]=textMATLABCOM(z,v);
a
b1
b2
b3
b4
MATLAB运行结果:
a = 1 2 3 4 5
b1 = 6 7 8 9 10
b2 = 2 3 4 5 6
b3 = 2 3 4 5 6
b4 = 1 2 3 4 5; 6 7 8 9 10
第二步:编译m文件,生成dll
保存该函数,并调用deploytool工具,然后新建工程,注意:工程类别为MATLAB Builder NE-------》Generic COM Component。工程命名为test,如下图所示。
工程建好之后需要添加m文件,将textMATLABCOM.m添加到test.prj中。
编译工程(注:在初装matlab时,需要运行mbuilder –setup命令,选择编译器为VC),结果显示如下图,则表示编译成功。
在工程文件夹下面生成了两个文件夹:distrib和src,其中distrib中包含dll文件,src中包含h和c文件以及dll文件,这里面的dll文件都在编译过程中由matlab自动进行了注册。
第三步:调用dll文件,实现VC应用
1、 新建一个MFC项目testcom,选择dialog based项。界面为:
2、 通过matlab com组件生成必备的c和h文件
首先打开Tools--->OLE/COMObject Viewer,在左列中选择TypeLiberaries,找到对应的test项,双击打开,可以发现里面对testMATLABCOM函数接口进行定义了,如下图所示。
然后点击保存图标,将文件另存为.h文件以及.c文件,可以在src文件夹中发现如下两个文件:
需要注意的是:1、在安装VC的时候,需要让VC自动注册环境变量,否则无法生成这两个文件,并提示出错。2、在另存为这两个文件的时候,选择的目录最好用盘符根目录,在本例中选择的C盘目录,否则会不提示错误,但是找不到生成的文件的问题!
3、 VC程序调用matlab com的配置
将dll、h、c文件都拷贝到工程目录testcom下面,并将test_1_0.c与test_1_0.h文件添加到工程文件中。同时还要拷贝如下文件:mwcomtypes.h,mwcomutil.dll, mwcomutil.h文件,并将mwcomtypes.h以及mwcomutil.h文件添加到工程。
在stdafx.h中添加如下头文件:
#include <comdef.h>
#include <atlbase.h>
#include "mwcomtypes.h"
#include "test_1_0.h"
#import "mwcomutil.dll"raw_interfaces_only
#include "mwcomutil.h"
其中,mwcomtypes.h位于test工程的src目录下,mwcomutil.h文件位于C:\ProgramFiles\MATLAB\R2009a\extern\include\win32目录下,mwcomutil.dll文件位于C:\Program Files\MATLAB\R2009a\bin\win32目录下。
配置完成之后,VC工程的文件列表如下图所示:
此时,已经完成了对matlabcom组件调用的初步配置,接下来的工作就是编写源代码了。
4、 源代码编写
首先在testcom.cpp文件中的BOOL CTestcomApp::InitInstance()函数中添加如下代码:
if(CoInitialize(NULL)!=0)
{
AfxMessageBox("初始化COM支持库失败!");
exit(1);
}
该代码提供对COM组件的初始化工作。截图如下所示:
然后在testcomDlg.cpp文件中定义ITest变量ite.并在对应的函数体中添加如下代码:
ITest *pTe;
……
//初始化MATLAB COM组件
pTe=NULL;
if(FAILED(CoInitialize(NULL)))
{
AfxMessageBox("不能够初始化Test COM组件!");
}
HRESULThr2=CoCreateInstance(LIBID_test,NULL,CLSCTX_ALL,IID_ITest,(void**)&pTe);
if(FAILED(hr2))
{
AfxMessageBox("不能创建Test COM组件实例!");
}
至此,有关matlabcom的程序代码配置部分已经完成,接下来进行com接口调用工作。
代码如下:
//接口调用部分
doublez[2][5]={ {1,2,3,4,5},{6,7,8,9,10} };
doublev[2][5]={ {2,3,4,5,6},{6,7,8,9,3} };
VARTYPEvt=VT_R8;
SAFEARRAYBOUNDsab[2];
sab[0].cElements=7;
sab[0].lLbound=0;
sab[1].cElements=7;
sab[1].lLbound=0;
SAFEARRAY*pz=SafeArrayCreate(vt,2,sab);
SAFEARRAY*pv=SafeArrayCreate(vt,2,sab);
if(NULL==pz|| NULL==pv )
{
AfxMessageBox("不能创建SAFEARRAY数组!");
return;
}
longDemen[2];
for(longi=0;i<=1;i++)
{
for(longj=0;j<=5;j++)
{
Demen[0]=i;
Demen[1]=j;
HRESULThre=SafeArrayPutElement(pz,Demen,&z[i][j]);
HRESULThre1=SafeArrayPutElement(pv,Demen,&v[i][j]);
if(FAILED(hre)|| FAILED(hre1))
{
AfxMessageBox("数组赋值失败!");
return;
}
}
}
VARIANTzo,vo,a,b1,b2,b3,b4;
VariantInit(&zo);
VariantInit(&vo);
VariantInit(&a);
VariantInit(&b1);
VariantInit(&b2);
VariantInit(&b3);
VariantInit(&b4);
zo.vt=VT_ARRAY|vt;
vo.vt=VT_ARRAY|vt;
zo.parray=pz;
vo.parray=pv;
/*virtual [helpstring][id] HRESULT STDMETHODCALLTYPE textMATLABCOM(
//[in] long nargout,
//[out][in] VARIANT __RPC_FAR *a,
//[out][in] VARIANT __RPC_FAR*b1,
//[out][in] VARIANT __RPC_FAR*b2,
//[out][in] VARIANT __RPC_FAR*b3,
//[out][in] VARIANT __RPC_FAR*b4,
//[in] VARIANT z,
//[in] VARIANT v) = 0;*/
pTe->textMATLABCOM(5,&a,&b1,&b2,&b3,&b4,zo,vo);
//获取数据
CStringstr1="";
CStringstr2="";
for(intj=0;j<5;j++)
{
str1.Format("%f",*((double*)a.parray->pvData+j));
str2+=str1;
str2+=" ";
}
AfxMessageBox(str2);
运行结果为:
正是matlab中变量a的返回值。将代码做如下改变:
//获取数据
CStringstr1="";
CStringstr2="";
for(intj=0;j<5;j++)
{
str1.Format("%f",*((double*)b1.parray->pvData+j));
str2+=str1;
str2+=" ";
}
AfxMessageBox(str2);
运行结果为:
正是matlab中b1的返回值。
后续不再测试,至此,整个调用matlabcom的过程完成!
matlab程序发布过程,将在下面的文章中介绍。