湖南继续教育注册:Matlab生成Com组件,vb、vc等的调用! - flider的日志 - 网易博客

来源:百度文库 编辑:中财网 时间:2024/04/27 16:25:15

Matlab生成Com组件,vb、vc等的调用!

学习资料 2010-07-14 15:42:35 阅读215 评论0   字号: 订阅

将m文件做成COM组件。pdf     链接:http://www.docin.com/p-55636205.html

 

第一步:Matlab生成Com组件编译器的配置过程

首先.要把Matlab编译成Com组件提供给.Net使用..需要使用VC++编译环境,对于 7.0版本以上可以支持VC++ 2005对于 7.0以及 7.0版本以下 支持 VC++ 6.0;

首先我的电脑已经安装了 VS.NET 2008,虽然里面也有附加VC++,但是却不能提供给Matlab编译成Com组件.于是我又去下了VC++ 6.0;安装后 经过测试 依然不行;以为Matlab没有识别.可能被VS.NET的相关文件覆盖(因为.net包括c++,所以安装c++的时候,有部分文件是相同的)

 

mbuild -setup     (对matlab编译器配置)

Please choose your compiler for building standalone MATLAB applications:
Would you like mbuild to locate installed compilers [y]/n? y(输入y回车)

Select a compiler:
[1] Lcc C version 2.4 in E:\MATLAB\sys\lcc
[2] Microsoft Visual C/C++ version 6.0 in E:\VC
[0] None
Compiler:2    回车

Please verify your choices:
Compiler: Microsoft Visual C/C++ 6.0
Location: E:\VC

Are these correct?([y]/n):y          回车

Warning: Mbuild requires that the Microsoft Visual C++ 6.0
directories "VC98" and "Common" be located within the same parent directory.
(Expected to find a directory named "Common" in the directory 'E:\VC'.)
Try to update options file: C:\Documents and Settings\jxh\Application Data\MathWorks\MATLAB\R14\compopts.bat
From template:              E:\MATLAB\BIN\WIN32\mbuildopts\msvc60compp.bat
Done . . .
--> "E:\Matlab\bin\win32\mwregsvr E:\Matlab\bin\win32\mwcomutil.dll"
DllRegisterServer in E:\Matlab\bin\win32\mwcomutil.dll succeeded
--> "E:\Matlab\bin\win32\mwregsvr E:\Matlab\bin\win32\mwcommgr.dll"
DllRegisterServer in E:\Matlab\bin\win32\mwcommgr.dll succeeded

Matlab终于和VC关联了...遗憾的是 这个都是跟系统非常相关的 一旦系统重装 这些东西都将失效

第二步:在matlab下做COM组件

首先在Matlab编辑器里编辑m函数文件:启动matlab->File->New->M-file 函数内容如图1:该函数无输入输出参数,文件保存为huatu.m。


图1 m函数huatu.m

在matlab下建立COM组件,步骤如下:
1、在matlab command window 输入如下命令:
>> comtool
出现com编辑界面,如图2:


图2 com组件编辑界面

2、新建工程:File->New Project…,如图3。

图2 com组件属性设置

3、设置组件属性,在"Component name"项中填写组件名称"component",这时候会自动生成类"component",在"Class name"项中填写类名称"huatu",如图4,

图4 com组件属性设置1

为了便于区分,选中"Classes"中的"component",点击“remove”按钮,将类component移除,再点击"Add>>"添加新类huatu,结果如图5。点击"OK",接下来出现一个对话框,选择"Yes".

图5 com组件属性设置2

4. 添加文件:选中左边工作区的"huatu",点击Project->Add File…,选择已经编辑好的函数文件huatu.m,如图6。需要注意的是m文件必须是m函数,否则会报错,如果是m脚本文件的话,只需要改为无输入输出参数的m函数即可。

                                             图6 添加m文件

5、生成 com组件:点击Build->COM Object…,结果如图7。

                图7  大功告成界面

com组件已经由matlab做好,默认的保存位置为:matlab安装位置\work\component。
第三步:vb、vc等的调用

这一部分讲vb,c#.net下怎么实现调用上一部分我们生成的comtest_1_0.dll(matlab下做的com组件),记得一定先要对mwcomutil.dll进行注册(怎么注册参看上一部分)

  1.vb下实现调用

  打开或新建一个vb工程,点project-Reference,在弹出来的窗口中找到comtest 1.0 Type Library,将前面的复选框选上,点击ok,此时便将此com组件添加到工程里面去了,此时你可以用对象浏览器看到comtest下有个sgltest类,这个类里面有两个方法im_test,split2rgb,还有个MWFlags成员(这个成员是自动生成的),vb下测试代码如下:

  测试huatu方法的代码(不带参数的函数调用):

  Dim st As huatu
  Set st = New huatu

  Call st.huatu

  测试split2rgb方法的代码(带参数的函数调用):

  Dim st As sgltest

  Set st = New sgltest

  Dim h As Variant, w As Variant, r As Variant, g As Variant, b As Variant, filename As Variant

  filename = "c:\\1.jpg"

  Call st.split2rgb(5, h, w, r, g, b, filename)

  可见matlab下函数的输入输出参数在com组件里全是variant型的变量,测试大获成功,结果就跟matlab下运行的一摸一样,爽

  2.c#.net下实现调用

  打开或新建一个c#项目(我采用的是vs.net编辑器),选中右边的解决方案资源管理器中的引用,点鼠标右键,选添加引用,在弹出来的窗口中选com,然后也找到comtest_1_0.dll,点选择,然后确定就可,此时此com组件也添加到工程里面去了,同样我们可以选择对象浏览器来看comtest及下面的sgltest类,c#测试项目如下:

  测试im_test方法的代码:

  comtest.sgltestClass st=new comtest.sgltestClass();

  st.im_test();

  测试split2rgb方法的代码:

  comtest.sgltestClass st=new comtest.sgltestClass();

  object h=null,w=null,r=null,g=null,b=null;

  object filename="c:\\1.jpg";

  st.split2rgb(5,ref h,ref w,ref r,ref g,ref b,filename);

  可见输入参数是ref object型的,而输出参数是object型的,测试同样大获成功,与matlab下运行的结果一摸一样,爽呆了。

  3.vc下调用

  这一部分讲vc下实现调用第一部分我们生成的comtest_1_0.dll,同样要记得先对mwcomutil.dll进行注册(怎么注册参看第一部分),vb和.net下实现对com组件的调用很简单,而vc下实现这一步我可是摸索了好几天(主要是vc用的不好)

  (1).先做一些准备工作,用ole viewer工具

  开始--程序--Microsoft visual studio6.0--Microsoft visual studio6.0 Tools--OLE viewer(这个工具也可以通过在vc下点Tools--OLE/COM Object Viewer来打开,在Ole viewer工具里,在右边选择Type libraries,将他展开,找到comtest 1.0 Type Library,选中它,点鼠标右键,选view,便又弹出一窗口,点工具栏上的save按钮,分别将他保存为comtest_1_0.h,comtest_1_0.c(也可以存为comtest_1_0.Idl接口文件),我们就可以通过这两个文件实现对comtest_1_0.dll调用

  (2).vc下调用

  新建或打开一个vc工程,注意,此时不用对编译器进行任何设置(而用mcc生成的dll我们么设置一大堆,我这儿只设置了Precompiled headers,选Automatic use of precompiled headers,写上stdafx.h),将comtest_1_0.h和comtest_1_0.c加入工程,并复制一个comtest_1_0.dll到工程目录下,由于comtest_1_0.dll还要用到mwcomutil.dll,所以将/extern/include/下的mwcomutil.h也加入工程

  (将这两个文件拷贝入工程路径下,如果设置了library path,可以不加)

  此时可以通过classView看到多出了_IID、IMWUtil,Isgltest类,Isgltest就是我们在matlab下建起来的sgltest类

  vc下代码如下

  //这几个是引入dll和头文件

  #import "mwcomutil.dll"

  #import "comtest_1_0.DLL"

  #include "mwcomutil.h"

  #include "comtest_1_0.h"

  #include "comutil.h" //此文件是用来处理由char *向VARIANT类型的转换

  测试im_test方法的代码:

  if(FAILED(CoInitialize(NULL))) //初始化调用com

  {

  AfxMessageBox("unable to initialize COM");

  }

  Isgltest *st=NULL;

  //创建一个com组件,CLSID_sgltest和IID_Isgltest可以从comtest_1_0.h和comtest_1_0.c里找到

  HRESULT hr=CoCreateInstance(CLSID_sgltest,NULL,CLSCTX_ALL,IID_Isgltest,(void **)&st);

  if(SUCCEEDED(hr))

  {

  st->im_test();

  AfxMessageBox("succeed");

  st->Release();

  }

  else

  {

  AfxMessageBox("unsucceed");

  }

  如果你的vc工程是console project的话,上述的AfxMessageBox可改成printf或cout,

  测试split2rgb方法的代码(类型转换我参照visual c的精华区也转换成功了)

  if(FAILED(CoInitialize(NULL)))

  {

  AfxMessageBox("unable to initialize COM");

  }

  Isgltest *st=NULL;

  HRESULT hr=CoCreateInstance(CLSID_sgltest,NULL,CLSCTX_ALL,IID_Isgltest,(void **)&st);

  VARIANT m,n,r,g,b,filename;

  VariantInit(&m);

  VariantInit(&n);

  VariantInit(&r);

  VariantInit(&g);

  VariantInit(&b);

  VariantInit(&filename);

  filename.vt=VT_BSTR;

  filename.bstrVal=_com_util::ConvertStringToBSTR("C:\\1.jpg");

  if(SUCCEEDED(hr))

  {

  st->split2rgb(5,m,n,r,g,b,filename);

  st->Release();

  AfxMessageBox("succeed");

  }

  else

  {

  AfxMessageBox("unsucceed");

 }

  同样,运行结果与matlab下的结果一摸一样,记得我们的im_test里面可是使用了imshow阿,以前用mcc生成的程序中用它可是有错哦,爽呆了。

  关于VC下用com组件及其类型的转变请参看msdn及其Visual C的精华区。

第4步:.打包:

    combuilder系列可以结尾了

  在matlab下的workspace里打comtool,点file-open project将我们先前建好的comtest.cbl工程文件打开,再点

  component--package component就实现了打包,此时到comtest\distrib文件夹里看,生成的comtest.exe就是打包后的解压程序,双击它会解压出一些文件,再点击解压出来的_install.bat就可以实现安装(按他的步骤去做就行了)

  最后:优缺点评注

  这几天用这个combuilder在vc下调用成功时,优点如下:

  1.做出来的是com,通用的,任何编译器只要支持com,就可以实现调用,想c++ builder,Delphi等的,我想只要按照调用com组件去做,也能成功的

  2.支持imshow等一些原来混编用不了的函数,对图形库的支持也比以前强(这些还需各位大侠共同测试)

  3.实现方法简单,没有像以前混编还要设置一大堆东东

  4.能够在matlab下写自己的类,并为自己的类编写成员、方法和事件,管理工程也方

  便(这个有点像vc、vb下管理工程一样)

  用的太爽了,一下子还不知道怎么写缺点了,^0^,我想缺点还需大家一起用来找出

  我这儿说一个缺点,感觉它的参数全是VARIANT型的,不怎么方便

  后期补充:

  补充:

(1)vc中的数组和com中的VARIANT变量的相互转换

  用一个例子说明一下,

  首先用matlab的m文件描述一下例子中com组件的功能:

  function y=hehe(x)

  y=x*2;

  把该文件保存为hehe.m

  用combuilder中建立工程comparatest,加入类paratest,

  然后加入文件hehe.m,再build成为com组件。

  下面是vc中的代码:

  #include "stdafx.h"

  #include "stdio.h"

  #import "mwcomutil.dll"

  #import "comtest2_1_0.DLL"

  #include "mwcomutil.h"

  #include "comtest2_1_0.h"

  #include "comutil.h"

  int main(int argc, char* argv[])

  {

  double a[4]={1,2,3,4};

  int i=4;

  if(FAILED(CoInitialize(NULL))) //初始化调用com

  {

  printf("unable to initialize COM");

  }

  VARIANT x,y;

  VariantInit(&x);

  VariantInit(&y);

  x.vt=VT_R8|VT_ARRAY;//声明x的类型为VT_ARRAY,

  //Array中的元素为double型

  SAFEARRAYBOUND rgsabound[1];

  rgsabound[0].cElements=4;//元素的个数

  rgsabound[0].lLbound=0; //矩阵索引的下界

  x.parray=SafeArrayCreate(VT_R8,1,rgsabound);//该函数新建

  //一个SafeArray,并把这个SafeArray的描述

  //符的指针传给x.parray。

  x.parray->pvData=http://blog.soso.com/qz.q/a;

  Iparatest *st=NULL;

  //创建一个com组件,CLSID_paratest和IID_Iparatest可以从

  //comparatest2_1_0.h和comparatest2_1_0.c里找到

  HRESULT hr=CoCreateInstance(CLSID_paratest,NULL,CLSCTX_ALL,

  IID_Iparatest,(void **)&st);

  if(SUCCEEDED(hr))

  {

  st->hehe(1,&y,x);

  memcpy(a,y.parray->pvData,4*sizeof(double));

  //当matlab文件中返回的矩阵y是实数行的时候,com组件

  //把得到的y的值存放再y.parray->pvData所指向的内存区域。

  printf("%f\n%f\n%f\n%f\n",a[0],a[1],a[2],a[3]);

  printf("succeed");

  st->Release();

  }

  else

  {

  printf("unsucceed");

  }

  return 0;

  }

  上面的方法解决了实矩阵参数在com组件和vc之间的传递,应该也能用到其他

  类型的矩阵,比如字符和整型的矩阵。但是如果com组件是由matlab combuilder

  编译m文件得到的,而且m文件所返回的矩阵是复数型的,就不行了。因为好像

  这时返回的矩阵并不是如上所述保存在y.parray中,至于到底保存在什么地方

  就有待于大牛们把它找出来了,反正俺琢磨了一整天也没有一点头绪:(

  (2).vb,.net中的数组和com中的VARIANT变量的相互转换

  vb和.net变量的相互转换也很简单,下面举例简单说一下:

  在我们前面的sgltest里面增加一个函数叫y=paratest(x),x,y为输入输出,都为矩阵

  1.vb下:

  Dim st As sgltest

  Set st = New sgltest

  Dim x(2) As Variant, y As Variant

  x(0) = 3#

  x(1) = 5#

  x(2) = 6#

  Call st.paratest(1, y, x)

  y(1,0),y(1,1),y(1,2)就是输出的数组

  2..net下:

  comtest.sgltestClass st=new comtest.sgltestClass();

  object y=null;

  object[] x;

  x=new Object[3];

  x[0]=2.0;

  x[1]=3.0;

  x[2]=4.0;

  pt.para_test(1,ref y,x);

  y[0,0],y[0,1],y[0,2]就是输出的数组

  实例: Matlab与VC混合编程 (用idl或dll来调用com组件)

  这儿再提供一种通过Idl或dll来调用com组件的方法(不用生成*.h和*.c文件)

  其实这种方法比通过生成.h和.c文件来调用要简单一些:),还用精华区的例子

  1.通过ole/com object生成idl文件,将此idl文件加入工程,点菜单build-complie

  comtest_1_0.tlb,生成tlb文件

  2.打开classwizard,点右边的add class-from a type library class,选中刚生成的

  comtest_1_0.tlb(应该在debug\目录下),其实这儿也可以直接选择用matlab的combuilder

  生成的comtest_1_0.dll(这样就省去了第一步),后面将出现生成class的一些对话框,照

  提示去做就可以了,这样就生成了comtest_1_0.h和comtest_1_0.cpp,多了一个Isgltest

  类:)

  3.测试代码如下:

  头文件中只需添加:

  #include "comtest_1_0.h"

  测试代码:

  Isgltest st;

  AfxOleInit();

  if(st.CreateDispatch(_T("comtest.sgltest")))

  {

  st.im_test();

  AfxMessageBox("Haha,Succeeded");

  st.ReleaseDispatch();

  }

  else

  AfxMessageBox("UnSucceeded");

  上述代码的具体意义参看msdn,我也是刚刚摸索到:)

  4.combuilder与vc混编中复数类型的输出(By LPCTSTR)

  今天瞎捣鼓了一下,在前辈们的基础上解决了这个问题;)

  调用com的方法和前面的几位略有不同,个人感觉比他们的简单、正规一点 ;)

  step 1 建立m文件,build成com

  m文件写的很简单

  function cplx = getcplx()

  cplx = 1+2i

  方便后面看代码,写出我建立com工程时组建名称:AMyCom 类:MyTst

  step 2 导出必要的头文件

  1.打开OLE viewer (vc6.0菜单:tools--〉OLE/COM Object Viewer

  2.OLE viewer 菜单:file-->view TypeLib

  3.打开combuilder生成的dll:AMycom_1_0.dll

  4.File-->save as 选择生成 .h文件

  5.将生成的头文件拷到vc工程路径下

  6.重复以上步骤生成mwcomutil.dll的头文件

  step 3 vc下的简单测试源代码如下:

  #include

  #include "stdio.h"

  #include "mwcomutil.h"

  #include "Amycom_1_0.h"

  void main()

  {

  CoInitialize(NULL); //初始化com

  //创建Com实例

  CLSID CLSID_MyTst;

  CLSIDFromProgID(L"AMyCom.MyTst.1_0",&CLSID_MyTst);

  //这里的ProgID可以在combiulder的component->component info里面看到

  //或者搜索注册表得到

  IID IID_IMyTst = __uuidof(IMyTst);

  IMyTst* pMyTst = NULL;

  CoCreateInstance(CLSID_MyTst,NULL,CLSCTX_ALL,IID_IMyTst,(void**) &pMyTst

  );

  ////////

  VARIANT r[5];

  for (int i=0; i<5; i++)

  {

  VariantInit(&r);

  }

  pMyTst->getcplx(1,&r[0]); //调用函数接口

  IMWComplex* pTemp = (IMWComplex*)r[0].pdispVal;//复数类型的接口

  pTemp->get_Real(&r[1]);

  pTemp->get_Imag(&r[2]);

  double dr = r[1].dblVal; //获取实部

  double img = r[2].dblVal; //获取虚部

  printf("real : %f\nimg : %f\n",dr,img); //

  getchar();

  CoUninitialize();

  return;

  }

  个人感觉matlab的一部分比较复杂的数据类型都做成了com组建封装在mwcomutil.dll中,当

  用OLE viewer打开该文件时可以看到好多接口,其中包括IWMComplex即复数类型的接口,co

  m参数的传递通过VARIANT类型来实现,可以在MSDN上查到详尽的用法