views:

361

answers:

2

I finally discovered a way to use command line Matlab from .NET without linking:

  1. Write variables from .NET to a MAT file using David A. Zier's "csmatio" dll.

  2. Read the file from Matlab, process it and save the results to a MAT file:

    var process = new Process()
    {
        StartInfo = new ProcessStartInfo()
        {
            FileName = MatlabExecutableFileName,
            Arguments = "-nodisplay " + 
               "-nojvm " +
               " -r \"somecommands; " + 
               "save FILENAME OUTPUTVARIABLES; " +
               "exit;\""
        }
    };
    process.Start();
    
  3. The worst part: Wait until the process finishes.

    The naive approach:

    process.WaitForExit();
    

    Doesn't work because matlab spawns the main application in a new thread

    Watching for the output file for changes is tricky:

    new FileSystemWatcher(MatlabPath, fileName)
        .WaitForChanged(WatcherChangeTypes.All)
    

    Was not working because of a bug on this class.

    The currently working code is longer:

    using (var watcher = new FileSystemWatcher(MatlabPath, fileName))
    {
        var wait = new EventWaitHandle(false, EventResetMode.AutoReset);
        watcher.EnableRaisingEvents = true;
        watcher.Changed += delegate(object sender, FileSystemEventArgs e)
        {
           wait.Set();
        };
        foreach(var i in Enumerable.Range(0, 2))
        {
            if (!wait.WaitOne(MillissecondsTimeout))
            {
                throw new TimeoutException();
            }
        }
        Thread.Sleep(1000);
    }
    

    But I am concerned about the last line of code. The code block above was written with the intent of avoiding it, but I don't know what else to do. This amount of time will be too much on some computers and too little on others.

SOLUTION

var previousProcesses = Process
    .GetProcessesByName("Matlab")
    .Select(a => a.Id)
    .ToArray();
process.Start();
process.WaitForExit();
var currentProcess = Process
    .GetProcessesByName("Matlab")
    .Where(a => !previousProcesses.Contains(a.Id))
    .First();
currentProcess.WaitForExit();
+1  A: 

Not sure if I completely understand the question (you're essentially trying to detect when the matlab process finishes right?), but couldn't you find matlab's main application process & wait for it to exit? i.e. something like this:

process.WaitForExit();  //only waits for the launcher process to finish
//but now matlab should be running in a new process...
var matlabProcess = Process.GetProcessesByName("whatever process is called");
//assuming only one matlab instance running...
//you'd probably want to write some defensive code here...
matlabProcess[0].WaitForExit();

Seems like that would be simpler than trying to watch it change files & guess when its finished...

Alconja
Perfect! It worked!
Jader Dias
A: 

How about determining the actual process for the separate thread and calling WaitForExit on it? Maybe use the command line program tasklist to get the PID's of all MATLAB processes and filter out the PID of the one you have.

Alternatively, there might be a .NET structure (probably related to process) which could return a child thread of process and wait for it.

Unfortunately, I don't know details, but it's worth a try searching that avenue.

Steven