一个基于COM组件的Matlab与C#混合编程实例
2017-12-21 16:23
453 查看
把matlab与其他语言混合使用是一种挺实用的技巧,在前期使用matlab进行算法设计和计算仿真,而在需要编写程序原型的时候把matlab算法模块嵌入到C++或C#的程序里,一方面省的再用C++或C#重写代码,另一方面也可以直接调用matlab里的一些工具箱。
至于混合编程的手段也是多种多样的,最简单的可以调用matlab引擎或将matlab文件打包成动态链接库,不过官方比较推荐的是打包成COM组件,这种方法很适合于算法复杂,涉及很多matlab文件的情况。matlab提供了打包COM的编译器,使用起来也是很方便的。我在图书馆找的相关书籍都是讲matlab和C++混合编程的,说实话用C++写真的挺费劲的,最麻烦的是输入输出是矩阵序列的情况,需要写很多转换和处理的代码;不过如果用C#的话就方便很多了,根本不用管什么类型,.NET框架帮我们处理了。下面是我参考其他资料后自己写的一个matlab与C#混合的程序实例。
函数的输入我用一个矩阵变量来存放三个参数,这是为了后面在C#程序里调用时展示特意这么做的。
在Deployment project对话框中将target选择为Generic COM Component:
点击”Add class”新建一个类,之后再点击“Add files”将写好的M文件添加进去:
然后就可以点击上面的“Build”图标进行编译,旁边那个图标是打包,如果需要把COM组件用在其他没有按照matlab的机器上的话就需要打包了,打包时会将matlab的编译运行时(MCR)包含进去并生成一个安装包,在别的机器上进行安装,不过如果只是在本机测试的话就没必要这么麻烦了。Build的时候要注意这个项目文件的目录不要有中文,不然会出错的。
编译完成后在项目目录中的distrib中已经生成了一个dll文件(这里的名字是DrawSinCOM_1_0.dll),这就是COM组件的生成结果。COM组件使用前是需要在本机上注册的,因为现在是在本机测试,生成过程中已经自动注册好了,所以可以直接调用这个COM对象了。
把DrawSinCOM_1_0.dll复制到debug目录下,在winform程序中添加DrawSinCOM_1_0.dll的引用,在后台就可以初始化COM对象并调用其方法了,相关代码如下:
如果我们查看DrawSin的函数定义,可以看到其输入参数的类型是object,因此我们可以直接将double[]对象直接传进去,不需要管它内部具体怎么转换。运行结果:
FindWindow:查找并返回指定的窗口句柄
SetParent:设定窗口的父窗口
MoveWindow:移动窗口并设定大小
GetWindowLong:获取窗口相关参数
SetWindowLong:设定窗口参数
综合使用这些函数就可以绑定窗口了,相关代码如下:
注意到代码中用Sleep进行了延时,如果不延时,FindWindow方法很可能会返回零从而绑定失败(也许是因为代码执行太快了)。此外我碰到过GetWindowLong调用失败的情况,好像改了项目的.NET版本后又行了。最终的效果:
窗口嵌入了主窗口,还可以方便地进行缩放、导出等功能。
参考文献
1、《精通Matlabb与C/C++混合程序设计》
2、http://www.cnblogs.com/dekevin/p/3583344.html?utm_source=tuicool
3、https://www.cnblogs.com/eniac12/p/4390845.html
4、http://blog.sciencenet.cn/blog-720524-785934.html
至于混合编程的手段也是多种多样的,最简单的可以调用matlab引擎或将matlab文件打包成动态链接库,不过官方比较推荐的是打包成COM组件,这种方法很适合于算法复杂,涉及很多matlab文件的情况。matlab提供了打包COM的编译器,使用起来也是很方便的。我在图书馆找的相关书籍都是讲matlab和C++混合编程的,说实话用C++写真的挺费劲的,最麻烦的是输入输出是矩阵序列的情况,需要写很多转换和处理的代码;不过如果用C#的话就方便很多了,根本不用管什么类型,.NET框架帮我们处理了。下面是我参考其他资料后自己写的一个matlab与C#混合的程序实例。
1 matlab程序编写
先写个matlab程序吧,我用的matlab比较老,2010b,程序的话就写个简单的绘制正弦波形函数,即绘制一个周期的y=Asin(ωt+θ) 波形,A 、ω 和θ 是三个输入参数,具体代码如下:% Paras[1]:Amp % Paras[2]:Omega % Paras[3]:Theta function []=DrawSin(Paras) Amp=Paras(1); Omega=Paras(2); Theta=Paras(3); t=0:(2*pi/Omega/1000):2*pi/Omega; value=Amp*sin(Omega*t+Theta); plot(t,value);
函数的输入我用一个矩阵变量来存放三个参数,这是为了后面在C#程序里调用时展示特意这么做的。
2 生成COM组件
在matlab的”File”菜单里新建一个Deployment project:在Deployment project对话框中将target选择为Generic COM Component:
点击”Add class”新建一个类,之后再点击“Add files”将写好的M文件添加进去:
然后就可以点击上面的“Build”图标进行编译,旁边那个图标是打包,如果需要把COM组件用在其他没有按照matlab的机器上的话就需要打包了,打包时会将matlab的编译运行时(MCR)包含进去并生成一个安装包,在别的机器上进行安装,不过如果只是在本机测试的话就没必要这么麻烦了。Build的时候要注意这个项目文件的目录不要有中文,不然会出错的。
编译完成后在项目目录中的distrib中已经生成了一个dll文件(这里的名字是DrawSinCOM_1_0.dll),这就是COM组件的生成结果。COM组件使用前是需要在本机上注册的,因为现在是在本机测试,生成过程中已经自动注册好了,所以可以直接调用这个COM对象了。
3 C#程序调用
新建一个winform程序:把DrawSinCOM_1_0.dll复制到debug目录下,在winform程序中添加DrawSinCOM_1_0.dll的引用,在后台就可以初始化COM对象并调用其方法了,相关代码如下:
private DrawSinCOM.CDrawSin component;//定义COM组件对象 public Form1() { InitializeComponent(); this.textBox1.Text = "1"; this.textBox2.Text = "10"; this.textBox3.Text = "0"; component = new CDrawSin();//初始化 } private void button1_Click(object sender, EventArgs e) { double[] input = new double[3]; input[0] = Convert.ToDouble(this.textBox1.Text);//读取输入 input[1] = Convert.ToDouble(this.textBox2.Text); input[2] = Convert.ToDouble(this.textBox3.Text); component.DrawSin(input);//调用方法 }
如果我们查看DrawSin的函数定义,可以看到其输入参数的类型是object,因此我们可以直接将double[]对象直接传进去,不需要管它内部具体怎么转换。运行结果:
4 绑定matlab窗口
虽然调用成功了,不过波形窗口是弹出的,这样还是很别扭的,因此需要把这个波形窗口嵌入到C#窗口中。要实现这种“窗口绑架”的效果似乎必须要用Win32 API实现,需要在C#代码中导入user32.dll中的函数。要掌握Win32 API中操作窗口相关的函数还是很费劲的,我在网络上搜罗了这里要用到的主要的几个函数:FindWindow:查找并返回指定的窗口句柄
SetParent:设定窗口的父窗口
MoveWindow:移动窗口并设定大小
GetWindowLong:获取窗口相关参数
SetWindowLong:设定窗口参数
综合使用这些函数就可以绑定窗口了,相关代码如下:
using System.Runtime.InteropServices;//添加命名空间 ... ... //导入Win32函数 [DllImport("user32.dll", EntryPoint = "FindWindow")] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32.dll", EntryPoint = "SetParent")] public static extern int SetParent(IntPtr hWndChild, IntPtr hWndNewParent); [DllImport("user32.dll", EntryPoint = "MoveWindow")] public static extern int MoveWindow(IntPtr hWnd, int x, int y, int nWidth, int nHeight, bool BRePaint); private const int GWL_STYLE = (-16); private const long WS_CAPTION = 0xC00000; private const long WS_MAXIMIZE = 0x01000000L; private const long WS_THICKFRAME = 0x00040000L; private const int SW_HIDE = 0; private const int SW_SHOW = 0; [DllImport("user32.dll", EntryPoint = "SetWindowLong")] private static extern long SetWindowLong(IntPtr hwnd, int nIndex, long newLong); [DllImport("user32.dll", EntryPoint = "GetWindowLong")] public static extern long GetWindowLong(IntPtr hWnd, int nlndex); ... ... private void button1_Click(object sender, EventArgs e) { double[] input = new double[3]; input[0] = Convert.ToDouble(this.textBox1.Text); input[1] = Convert.ToDouble(this.textBox2.Text); input[2] = Convert.ToDouble(this.textBox3.Text); component.DrawSin(input);//调用方法 System.Threading.Thread.Sleep(100); IntPtr handle = FindWindow(null, "figure 1");//获取波形窗口句柄 SetParent(handle, this.panel1.Handle);//把波形窗口的父窗口设为主窗口中的面板 long temp = GetWindowLong(handle, GWL_STYLE);//获取窗口参数 SetWindowLong(handle, GWL_STYLE, temp & (~WS_CAPTION) | WS_MAXIMIZE);//这里是为了去掉窗口边框 MoveWindow(handle, 0, 0, this.panel1.Width, this.panel1.Height, true);//移动、调整窗口 }
注意到代码中用Sleep进行了延时,如果不延时,FindWindow方法很可能会返回零从而绑定失败(也许是因为代码执行太快了)。此外我碰到过GetWindowLong调用失败的情况,好像改了项目的.NET版本后又行了。最终的效果:
窗口嵌入了主窗口,还可以方便地进行缩放、导出等功能。
总结
利用COM技术可以轻松地构建matlab和C#混合编程应用,我个人觉得这种方法很适合在快速搭建软件原型的时候使用,因为省去代码重构的时间了,不过如果是做产品或是对运行速度要求较高的场合,这种方式显然不太合适了。此外,我在试验的时候曾经试图加入多核计算的元素,因为matlab和C#都有并行计算库,不过后来发现混合编程时这是行不通的,我搜到了一个matlab的官方回复,大意是matlab的模块打包中并不支持并行模块,这个回复是很早之前的了,不知道最新版的matlab行不行。参考文献
1、《精通Matlabb与C/C++混合程序设计》
2、http://www.cnblogs.com/dekevin/p/3583344.html?utm_source=tuicool
3、https://www.cnblogs.com/eniac12/p/4390845.html
4、http://blog.sciencenet.cn/blog-720524-785934.html
相关文章推荐
- C#与MATLAB混合编程实例
- 关于matlab与c#混合编程产生的移植问题
- VC与Matlab混合编程之基于MATLAB RTW 的建模仿真
- Matlab和C#混合编程之数组传值
- 【数据挖掘】Matlab与C#混合编程
- 利用C#进行Socket通信编程之二:一个实例
- 关于MATLAB和c#混合编程以及如何打包的
- C#与MATLAB混合编程
- 基于Activex控件的C++、C#混合编程
- Matlab与C#混合编程环境设置
- 基于MATLAB 进行混合编程的接口技术实现
- Matlab C/C++混合编程实例学习
- C#与matlab混合编程
- 做一个实例,搞定MATLAB界面编程
- Matlab混合编程之COM组件(C#篇)
- C#与Matlab混合编程入门教程一:几种混合编程的方法
- Matlab混合编程实例集
- Matlab混合编程实例集
- 【Unity基于C#事件委托机制,最轻松易懂的版本,一个实例解决你的困惑】
- matlab与c#混合编程之图像参数传递