There's a project I maintain in my free time. There is a high speed, number crunching, command line core written in C/C++. This core reads it's configuration from an xml file. The input and output files are specified in that xml, and the program gives simple feedback about the ongoing computation on the stdout:
- gives error message if needed
- displays the opened/read/written files
- displays an ASCII progress bar consisting of star (*) characters
Although the configuration thorough xml is good, but the scientist users of the tool needed a GUI for it, it is indeed user friendlier to tune the parameters on a GUI than fiddling with an xml.
I was sure, that I would keep the computation core as a stand-alone unit, as it is right now. So the GUI would be really just a user interface. But the question emerges: how will the two programs communicate with each other. There are several types of different IPC communication methods, but the easiest thing is to use the one which is already exists: the standard output.
The GUI needed really just some feedback, so I placed read-only a multi-line editbox onto the Form, where I would feed the stdout of the command line utility. Currently I'm on Windows platform, the computation core project is a Microsoft Visual Studio 2008 C/C++ solution, while the GUI is also an MSVC 2008 solution, but I use C# and Windows Forms.
I also decided that if I went to this straight forward stdout communication way, I still needed to give some feedback on the progress of the computation. Because the command line tool normally displayed only 10 stars, that was not enough for the GUI, so I introduced a new command line switch for the core executable (-g), which meant that computation was started from the GUI (and not manually from the command line). If the core saw that, then it printed not only 10, but 100 stars along the computation procedure, and it printed all of the stars to new lines. That way I got a better resolution progress bar for the GUI.
So I started the computation executable as a separate process from the GUI, but I had the problem that I didn't get proper feedback. I played a lot with the various properties of C#'s Process class, but either I didn't have any feedback, or just some feedback after the computation ended (which could be a long time). I had to attack the problem more times to finally find the problem: it was on the command line tool's side. To be able to receive continuous feedback, I have to turn off the stdout buffering with a special instruction in the core:
setvbuf(stdout, NULL, _IONBF, 0);
I use this only in case of the GUI operation (-g command line switch), because otherwise the tool looks fine.
On the C# side, I have these settings:
computeProcess = new Process();
String computeCommandParams = " -g -q";
// Configure start info
computeProcess.StartInfo.FileName = "Compute.exe";
// Set UseShellExecute to false for stdout redirection.
computeProcess.StartInfo.UseShellExecute = false;
// Redirect the standard output of the sort command.
// This stream is read asynchronously using an event handler.
computeProcess.StartInfo.RedirectStandardOutput = true;
computeProcess.StartInfo.RedirectStandardError = true;
// Set command line arguments
computeProcess.StartInfo.Arguments = computeCommandParams;
// Set our event handler to asynchronously read the sort output.
computeProcess.OutputDataReceived += new DataReceivedEventHandler(ComputeOutputHandler);
computeProcess.ErrorDataReceived += new DataReceivedEventHandler(ComputeErrorHandler);
computeProcess.StartInfo.CreateNoWindow = true;
//computeProcess.StartInfo.ErrorDialog = true;
computeProcess.EnableRaisingEvents = true;
computeProcess.Exited += new EventHandler(ComputeExitedHandler);