Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/276.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用C#应用程序控制Matlab实例_C#_Matlab - Fatal编程技术网

用C#应用程序控制Matlab实例

用C#应用程序控制Matlab实例,c#,matlab,C#,Matlab,背景 我有几个Matlab脚本可以创建与用户的交互会话(有点像游戏),我想创建一个C#GUI作为前端来启动这些脚本,而不是手动在Matlab的命令窗口中键入。原因是这些脚本被分成不同的目录,需要设置多个输入参数,如果用户相同,其中许多参数是相同的 问题描述 我的主要问题是如何与Matlab实例通信?我对来回传递数据不感兴趣;相反,我想向Matlab发送一个命令,让它完成它的任务。例如: cd('D:\Script1\'); fnScript1(0, true, 'default') %comma

背景

我有几个Matlab脚本可以创建与用户的交互会话(有点像游戏),我想创建一个C#GUI作为前端来启动这些脚本,而不是手动在Matlab的命令窗口中键入。原因是这些脚本被分成不同的目录,需要设置多个输入参数,如果用户相同,其中许多参数是相同的

问题描述

我的主要问题是如何与Matlab实例通信?我对来回传递数据不感兴趣;相反,我想向Matlab发送一个命令,让它完成它的任务。例如:

cd('D:\Script1\'); fnScript1(0, true, 'default') %command for Matlab to execute
我计划的方法是:

  • 在GUI端生成命令并复制到剪贴板
  • 使用SetForegroundWindow()将重点放在Matlab上
  • 将焦点放在命令提示符上
  • 使用SendKeys从剪贴板粘贴命令。Send(“^v”)
  • 使用SendKeys.Send({ENTER})执行命令
  • 这种方法的一个大问题是,我没有一个很好的方法来执行步骤3。Matlab不使用标准的Windows控件,所以我很确定UI自动化之类的东西在这里对我没有帮助。我能想到的解决方案是获取Matlab实例的客户端窗口区域,并在死点发送鼠标单击,因为这是在命令窗口的默认位置内(当然我会确保它确实在那里)

    尽管如此,我意识到这是一个相当糟糕的解决方案,所以我希望有人能想出一个更好的解决方案,最好不要点击周围,并假设事情会在它应该的地方。我四处搜索,类似问题的解决方案并不适用于我的案例:

    • 我不想每次执行脚本时都创建新的Matlab实例;我只想重用已经存在的同一个实例
    • 我不想将Matlab代码集成到我的C#项目中,因为它正在做一些复杂的事情,包括直接在屏幕上绘制东西,将数据写入并行端口等等
    • 我不确定我是否想用COM来做这件事,因为我根本没有使用COM的经验,也不知道从哪里开始。此外,使用COM(或DDE)传递单个字符串似乎有些过分
    • 我只有一个基本的许可证,没有访问奇特工具箱的权限

    我找到了一种通过COM实现这一点的方法,既可以打开一个新实例,也可以连接到一个现有实例。我发现的一个警告是,您的应用程序必须具有与正在运行的Matlab实例相同的权限,否则它将无法找到它;例如,如果Matlab正在运行,那么应用程序也必须运行

    设置

    为了使用Matlab的COM组件,您的项目需要添加对它的引用。在visual studio中,这是通过引用管理器完成的,可以在COM->Type Libraries->Matlab Application(Version 8.2)类型库下找到。您的版本号可能不同

    此外,默认情况下,Matlab不会在启用COM的情况下启动。您可以修改传递给exe的命令行参数以启用它,但这将强制Matlab实例处于控制台模式。如果您想要正常桌面模式,则需要在加载Matlab后启用COM。这可以通过startup.m脚本完成,如下所示:

    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
    循环,然后