振动理论

我的C++实现之路

基于ole的VC和matlab混合编程方法

原创文档 本文最初发表于VC知识库

运行环境:VC++ 6.0 MATLAB6.5 Windows XP

  此方法的实现是在网上各位前辈的基础上完成的。特别是参考了哈工大振动论坛上的一篇文章,现在,就具体谈一下怎么把一个M文件或MEX文件,做成可以脱离MATLAB环境的COM组件,并且被VC++调用。

1. 首先,设置合适的编译器。在MATLAB命令窗口里敲:>>mbuild –setup,完成编译器的设置。

>>mbuild –setup
Please choose your compiler for building standalone MATLAB applications:
Would you like mbuild to locate installed compilers [y]/n? y
Select a compiler:
[1] Lcc C version 2.4 in D:\MATLAB6P5\sys\lcc
[2] Microsoft Visual C/C++ version 6.0 in C:\Program Files\Microsoft Visual Studio
[0] None
Compiler: 2
Please verify your choices:
Compiler: Microsoft Visual C/C++ 6.0
Location: C:\Program Files\Microsoft Visual Studio
Are these correct?([y]/n): y
The default options file:
"C:\Documents and Settings\lilixin\Application Data\MathWorks\MATLAB\R13\compopts.bat"
is being updated from D:\MATLAB6P5\BIN\WIN32\mbuildopts\msvc60compp.bat...
--> "D:\MATLAB6p5\bin\win32\mwregsvr D:\MATLAB6p5\bin\win32\mwcomutil.dll"
DllRegisterServer in D:\MATLAB6p5\bin\win32\mwcomutil.dll succeeded
--> "D:\MATLAB6p5\bin\win32\mwregsvr D:\MATLAB6p5\bin\win32\mwcommgr.dll"
DllRegisterServer in D:\MATLAB6p5\bin\win32\mwcommgr.dll succeeded
Installing the MATLAB Visual Studio add-in ...
Updated C:\Program Files\Microsoft Visual Studio\common\msdev98\template\MATLABWizard.awx
from D:\MATLAB6P5\BIN\WIN32\MATLABWizard.awx
Updated C:\Program Files\Microsoft Visual Studio\common\msdev98\template\MATLABWizard.hlp
from D:\MATLAB6P5\BIN\WIN32\MATLABWizard.hlp
Updated C:\Program Files\Microsoft Visual Studio\common\msdev98\addins\MATLABAddin.dll
from D:\MATLAB6P5\BIN\WIN32\MATLABAddin.dll
Merged D:\MATLAB6P5\BIN\WIN32\usertype.dat
with C:\Program Files\Microsoft Visual Studio\common\msdev98\bin\usertype.dat 

2. 设置系统路径。我的电脑->属性->高级->环境变量->系统变量->Path选项,增加以下路径:
头文件:
d:\MATLAB6p5\extern\include;
库:
d:\MATLAB6p5\extern\lib\win32\microsoft\msvc60;
DLL:
d:\MATLAB6p5\bin\win32

3. 做一个简单的M函数(只能是函数不能是文件)。文件名和函数名一致。运行并测试此文件的正确性。
function [out]=arraytest(A)
out=det(A);
B=[A(1,1),A(1,2),A(2,1),A(2,2)]%本来是plot(A),刚开始没能把数据传递好,做了个B阵,做测试用的,
%因为com做好了,就没有改了,要不有很多垃圾
plot(B);

4. 在命令窗口敲comtool,出现com组件builder。选择FILE选项->New Project选项。出现以下界面。

Component name选项:设置com组件的名称,注意不要和上面添加的m文件重名。
Class name选项:设置类名称MyArraytest。一般将鼠标点击空白位置,系统会自动生成类名。
Project version选项:版本号。系统默认为1.0,将来要修改或添加其他函数时,可以修改此选项为2.0,3.0等。
Project directory选项:工程所在目录。
Complier options选项:编译器配置选项,全部选中。
最后单击OK。系统会出现对话框,问你是否创立工程目录,你选YES。

5. 单击Project Files->plotclass->M-files,然后选中comtool菜单Project->Add File选项,添加上面写好的plot_test M函数,当然,可以按需要添加更多的M或MEX函数。

6. 单击Build按钮,选中Com Object选项,这时com-builder会帮你自动编译连接该组件,生成所需要的头文件,源文件,接口描述文件,动态连接库文件,等等。在右侧Build Status显示框里给出了编译的过程和信息。在菜单Component->Component Info里有关于接口、类、库的信息。在d:\MATLAB6p5\work\Myarraytest文件夹里,出现了两个子文件夹,distrib和src,这是我们VC中需要用到的文件、库、资源、接口等。在src\plot_idl_i.c中,有关于com类和com接口的GUID。其中CLSID(类的GUID)在VC编程中需要用到。别急,还有一步打包发布。选择Component->Package Component,系统就会自己帮你打包了。打包文件在distrib文件夹中有Myarraytest可执行文件。拷贝d:\MATLAB6p5\work\Myarraytest文件夹下所有文件,在另外一个机器上,双击Myarraytest可执行程序,注册com组件,。你的程序,就可以在其他机器上执行了。

7. 打开VC++编译器,选择文件->新建->工程->MFC(exe)->命名(newoletest)-对话框->完成(曾经做个几个测试程序,没成功,名字可以自己写)。删除确定和取消按钮,新建一个按钮,我直接使用了ok按钮,删除了取消,把ok按钮中原来的程序删掉了。

8. 打开类向导,在 Add Class选项内,选中From a typed library,进入d:\MATLAB6p5\work\Myarraytest\src文件夹,选中myarraytest_idl.tlb文件,点击打开,OK。这时一个COM类便加入进来了,查看一下为IMyarraytest类。

9. 下面就是OLE调用的基本方法了。首先在 CNewoletestApp类的InitInstance()里添加初始化OLE代码。

BOOL suc=AfxOleInit(); // 初始化OLE

if (suc==FALSE)
{
::AfxMessageBox("初始化OLE失败!");
 }
  其次,在 CNewoletestDlg里包含plot_idl.h头文件;并从d:\MATLAB6p5\work\Myarraytest\src\myarraytest_idl_i.c中拷贝类的GUID并复制到PlotView.h文件类定义的上面。
#include "myarraytest_idl.h"


const CLSID CLSID_Myarraytest = {0x9C4328EF,0xEA57,0x4D84,{0x9C,0x97,0xDE,0x4B,0xAE,0x02,0x21,0x5F}};
class CNewoletestDlg : public CDialog
{
// Construction
public:
IMyarraytest pResponse;
.....
}//double a[7][6];是我做其它测试程序用的。
然后,Onok()函数里添加获得COM指针的函数,代码如下:
plot.CreateDispatch(CLSID_plotclass,NULL); //创立接口

COleDispatchDriver(); //连接(此句可以不写)

pResponse.CreateDispatch(CLSID_Myarraytest,NULL); //创立接口
COleDispatchDriver(); //连接(此句可以不写)
VARIANT x;
VARIANT y;
VariantInit(&x); //初始化
VariantInit(&y);

x.vt=VT_ARRAY|VT_R8; //类型(数组,双精度型)

SAFEARRAYBOUND rgsabound[2];
rgsabound[0].cElements=2; //数组所含元素数
rgsabound[0].lLbound=0; //数组上界
rgsabound[1].cElements=2; //数组所含元素数 rgsabound[1].lLbound=0; //数组上界
//创立数组 x.parray=SafeArrayCreate(VT_R8,2,rgsabound); //创立二维数组
double b[2][2];
b[0][0]=20;
b[0][1]=24;
b[1][0]=12;
b[1][1]=15;
//锁定数组 SafeArrayLock(x.parray);

//数组传递数据 x.parray->pvData=b;

//调用方法 pResponse.arraytest(0,&y,x);
//解锁
SafeArrayUnlock(x.parray);
/*
The most generic MATLAB M-function is function [Y1, Y2, ..., varargout] = foo(X1, X2, ..., varargin) This function maps directly to the following IDL signature.
HRESULT foo([in] long nargout,
[in,out] VARIANT* Y1,
[in,out] VARIANT* Y2,
.
[in,out] VARIANT* varargout,
[in] VARIANT X1, [in] VARIANT X2,
..
[in] VARIANT varargin);
This IDL function definition is generated by producing a function with the same name as the original M-function and an argument list containing all inputs and outputs of the original plus one additional parameter, nargout. (nargout is not produced if you compile an M-function containing no outputs.) When present, the nargout parameter is an [in] parameter of type long.It is always the first argument in the list. This parameter allows correct passage of the MATLAB nargout parameter to the compiled M-code. Following the nargout parameter, the outputs are listed in the order they appear on the left side of the MATLAB function, and are tagged as [in,out], meaning that they are passed in both directions. The function inputs are listed next, appearing in the same order as they do on the right side of the original function. All inputs are tagged as [in] parameters. When present, the optional varargin/varargout parameters are always listed as the last input parameters and the last output parameters. All parameters other than nargout are passed as COM VARIANT types. Data Conversion Rules lists the rules for conversion between MATLAB arrays and COM VARIANTs.
*/
// ::AfxMessageBox("调用结束!"); pResponse.DetachDispatch(); pResponse.ReleaseDispatch();
10. 测试。

本文并没有给出函数调用的返回参数y的后处理,这是本文的一个缺点,我会继续努力,在数据返回这一方面多做些工作。

posted on 2007-05-25 08:16 唯月释怀 阅读(852) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


My Links

Blog Stats

常用链接

留言簿(5)

随笔档案

文章档案

My sohu blog

搜索

最新评论

阅读排行榜

评论排行榜