用C#应用程序控制Matlab实例
背景 我有几个Matlab脚本可以创建与用户的交互会话(有点像游戏),我想创建一个C#GUI作为前端来启动这些脚本,而不是手动在Matlab的命令窗口中键入。原因是这些脚本被分成不同的目录,需要设置多个输入参数,如果用户相同,其中许多参数是相同的 问题描述 我的主要问题是如何与Matlab实例通信?我对来回传递数据不感兴趣;相反,我想向Matlab发送一个命令,让它完成它的任务。例如:用C#应用程序控制Matlab实例,c#,matlab,C#,Matlab,背景 我有几个Matlab脚本可以创建与用户的交互会话(有点像游戏),我想创建一个C#GUI作为前端来启动这些脚本,而不是手动在Matlab的命令窗口中键入。原因是这些脚本被分成不同的目录,需要设置多个输入参数,如果用户相同,其中许多参数是相同的 问题描述 我的主要问题是如何与Matlab实例通信?我对来回传递数据不感兴趣;相反,我想向Matlab发送一个命令,让它完成它的任务。例如: cd('D:\Script1\'); fnScript1(0, true, 'default') %comma
cd('D:\Script1\'); fnScript1(0, true, 'default') %command for Matlab to execute
我计划的方法是:
- 我不想每次执行脚本时都创建新的Matlab实例;我只想重用已经存在的同一个实例
- 我不想将Matlab代码集成到我的C#项目中,因为它正在做一些复杂的事情,包括直接在屏幕上绘制东西,将数据写入并行端口等等
- 我不确定我是否想用COM来做这件事,因为我根本没有使用COM的经验,也不知道从哪里开始。此外,使用COM(或DDE)传递单个字符串似乎有些过分
- 我只有一个基本的许可证,没有访问奇特工具箱的权限
enableservice('AutomationServer', true);
请注意,如果您选择通过COM创建Matlab实例,而不是附加到现有实例,则无需执行此操作,因为默认情况下它处于启用状态
方法1:附加到正在运行的Matlab实例,如果不存在,则创建一个
此方法将为您获得一个COM参考,以运行第一个Matlab实例;如果没有找到,它将创建一个新的Matlab实例
//The desktop progID only supports single-instance operation
Type MatlabType = Type.GetTypeFromProgID("Matlab.Desktop.Application");
MLApp.MLApp matlab = (MLApp.MLApp)Activator.CreateInstance(MatlabType);
//check that we have a valid instance
if (matlab == default(MLApp.MLApp))
{
MessageBox.Show("Matlab com object is null", "Error");
return;
}
//make Matlab do something (give focus to command window)
try
{
matlab.Execute("commandwindow");
}
catch (System.Runtime.InteropServices.COMException ex)
{
//something went wrong with the COM call
//such as Matlab getting killed and is no longer running
MessageBox.Show(ex.Message, ex.GetType().ToString());
}
注意,上面提到的特权问题在这里起作用。如果您的Matlab实例是提升运行的,而您的程序不是,那么此方法将无法找到提升的实例并尝试创建非提升的实例。这可能是有问题的,因为Matlab的许可证管理器可以拒绝尝试并抛出许可证错误消息,其副作用是永久挂起应用程序
方法2:连接到正在运行的实例,如果不存在则失败
与方法1不同,如果找不到新的Matlab实例,则该方法不会尝试创建新的Matlab实例
using System.Runtime.InteropServices;
try
{
MLApp.MLApp matlab =
(MLApp.MLApp)Marshal.GetActiveObject("Matlab.Desktop.Application");
}
catch (System.Runtime.InteropServices.COMException ex)
{
//this happens if no Matlab instances were running
MessageBox.Show(ex.Message, ex.GetType().ToString());
}
使用Matlab com对象
告诉Matlab做某事的最简单方法是调用COM对象的.Execute()
方法,不过这有一个问题。由于COM接口是为Matlab和应用程序之间的双向通信而设计的,因此通常显示在Matlab命令窗口中的任何内容都会被重定向到返回值.Execute()
。如果希望输出显示在Matlab的命令窗口中,则必须手动将命令发送到Matlab。以下是一种方法:
//this won't work, you won't see anything in Matlab
matlab.Execute(@"fprintf('Hello World')");
//copy the command to clipboard instead
Clipboard.SetText(@"fprintf('Hello World')");
//give Matlab's command window (global) focus
matlab.Execute("commandwindow");
System.Threading.Thread.Sleep(100);
//paste the command and run it
SendKeys.Send("^v{ENTER}");
请注意,这不是防弹的,可能会发生很多事情:
- 剪贴板正在被其他应用程序使用,无法写入
- 剪贴板内容在您有机会粘贴之前已更改
- 你还没来得及发送钥匙,Matlab就失去了焦点
输出重定向问题确实困扰着我,因为COM接口没有禁用它的选项。现在我依靠的是相当脆弱的复制/粘贴命令的方法,但这是我能想到的最好的方法。查看基于文件的命令/数据交换模型。。。。以下是您的选项@Yvon File-based将不起作用。我正在尝试使用GUI来启动脚本;如果我这样做,我仍然需要在Matlab中手动执行命令。你可以使用C#启动一个Matlab“守护进程”,它运行
while
循环,然后