Управление экземпляром Matlab через приложение C #

1

Задний план

У меня есть несколько скриптов Matlab, которые создают интерактивные сеансы с пользователем (вроде игры), и я хочу создать графический интерфейс С# в качестве front-end, чтобы запускать эти сценарии, а не вручную вводить в командном окне Matlab. Причина этого заключается в том, что эти сценарии разделены на разные каталоги и требуют нескольких входных параметров для настройки, многие из которых идентичны, если пользователь является одним и тем же.

описание проблемы

Главный вопрос, который у меня есть, - как мне взаимодействовать с экземпляром Matlab? Я не заинтересован в передаче данных туда и обратно; Скорее, я хотел бы отправить 1 команду в Matlab и позволить ей сделать что-то. Примером может служить:

cd('D:\Script1\'); fnScript1(0, true, 'default') %command for Matlab to execute

Мой планируемый подход:

  1. Создайте команду на стороне GUI и скопируйте в буфер обмена
  2. Используйте SetForegroundWindow(), чтобы сосредоточиться на Matlab
  3. Дайте фокус командной строке
  4. Вставьте команду из буфера обмена с помощью SendKeys.Send("^ v")
  5. Выполните команду с помощью SendKeys.Send("{ENTER}")

Большая проблема, с которой я сталкиваюсь, заключается в том, что у меня нет хорошего способа сделать шаг 3. Matlab не использует стандартные элементы управления Windows, поэтому я уверен, что что-то вроде UI Automation мне не поможет. Решение, о котором я могу думать, - это получить клиентскую область окна экземпляра Matlab и отправить клик мыши в мертвую точку, так как это находится в позиции по умолчанию в командном окне (конечно, я бы убедился, что на самом деле там).

Тем не менее, я понимаю, что это довольно паршивое решение, поэтому я надеюсь, что кто-то может придумать лучший, желательно без необходимости щелкнуть и предположить, что все будет так, как должно быть. Я искал, и решения по подобным вопросам не очень хорошо подходят для моего случая:

  • Я не хочу создавать новые экземпляры Matlab каждый раз, когда хочу выполнить скрипт; Я просто хочу повторно использовать тот же самый экземпляр, который уже существует.
  • Я не хочу интегрировать код Matlab в мой проект С#, поскольку он делает сложные вещи, связанные с рисованием непосредственно на экране, записывая данные в параллельные порты... и т.д.
  • Я не уверен, хочу ли я использовать COM для этого, поскольку у меня нет опыта работы с COM вообще и не знаю с чего начать. Кроме того, использование COM (или DDE, если на то пошло), чтобы передать одну строку, похоже на overkill
  • Я имею только базовую лицензию и не имею доступа к причудливым инструментариям
  • 0
    См. Модель обмена командами / данными на основе файла stackoverflow.com/q/18781803/3839249
  • 0
    .... и вот ваши варианты mathworks.com/help/matlab/…
Показать ещё 10 комментариев
Теги:

1 ответ

2
Лучший ответ

Я понял способ сделать это через COM, открыв новый экземпляр и присоединив к существующему экземпляру. Одно из предостережений, которое я обнаружил, заключается в том, что ваше приложение должно иметь те же привилегии, что и исполняемый экземпляр Matlab, иначе он не сможет его найти; например, если Matlab работает повышенным, то ваше приложение также должно быть.

Настроить

Чтобы использовать COM-компонент Matlab, вашему проекту необходимо добавить ссылку на него. В визуальной студии это делается через диспетчер ссылок и можно найти в библиотеке типов COM → Тип → Matlab Application (Version 8.2). Номер версии может отличаться.

Кроме того, Matlab по умолчанию не запускается с включенным COM. Вы можете изменить параметры командной строки, переданные в exe, чтобы включить его, но это заставит экземпляр Matlab быть в режиме консоли. Если вы хотите нормальный режим рабочего стола, вам необходимо включить COM после загрузки Matlab. Это можно сделать с помощью скрипта startup.m:

enableservice('AutomationServer', true);

Обратите внимание: если вы решили создать экземпляр Matlab через COM вместо привязки к существующему, вам не нужно это делать, поскольку он включен по умолчанию.

Способ 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, если его не найти.

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 что-то сделать - это вызвать метод .Execute() COM-объекта, который вы получили, однако для этого есть gotcha. Поскольку интерфейс 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 command window (global) focus
matlab.Execute("commandwindow");

System.Threading.Thread.Sleep(100);

//paste the command and run it
SendKeys.Send("^v{ENTER}");

Обратите внимание, что это не пуленепробиваемый, и может произойти ряд вещей:

  • Буфер обмена используется другим приложением и не может быть записан в
  • Содержимое буфера обмена изменилось, прежде чем вы получили возможность вставить его
  • Matlab потерял фокус, прежде чем вы могли отправить ключи

Проблема с перенаправлением вывода на самом деле вызывает ошибку, поскольку интерфейс COM не имеет параметров для ее отключения. Сейчас я полагаюсь на довольно хрупкий метод копирования/вставки команд, но это было лучшее, что я мог придумать.

  • 0
    Для печати в консоль вы не можете создать функцию Matlab, например: function [] = printAndExec(cmd) disp(cmd); evalin('base', cmd); end а затем вызвать эту функцию из C #, используя .Execute ()?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню