Process & WaitForExit & OutputDataReceived
.
.
Maybe it blocks because you're frying the processor? A MessageBox every millisecond is a bit extreme! Try:
while (!p.WaitForExit(2500)) {
There's not much to it. Note that if you hit the Enter key before the process is completed, the thread.Abort() gets called, but the ProcessRunner thread doesn't get interrupted until the process is complete.
class Program
{
public static void Main(string [] args)
{
try
{
if (args.Length > 0)
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("This is a test");
Thread.Sleep(1000);
}
}
else
{
ProcessRunner pr = new ProcessRunner();
Thread thread = new Thread(new ThreadStart(pr.Go));
thread.Start();
Console.ReadLine();
thread.Abort();
thread.Join();
}
}
catch (Exception e)
{
Console.WriteLine("Unexpected Exception:" + e.ToString());
}
}
}class ProcessRunner
{
private void OnTick( object obj,DataReceivedEventArgs args)
{
System.Console.WriteLine("Received: {0}", args.Data);
System.Console.WriteLine(Thread.CurrentThread.Name);
}
public string Cmd
{
get { return cmd; }
set { cmd = value; }
}
public void Go()
{
try
{
System.Console.WriteLine("Started...");
proc = new Process();
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.OutputDataReceived += new DataReceivedEventHandler(OnTick);
proc.StartInfo.FileName = @"Test.exe";
proc.StartInfo.Arguments = @"someargs";
proc.StartInfo.CreateNoWindow = true;
proc.Start();
proc.BeginOutputReadLine();
proc.WaitForExit(200);
System.Console.WriteLine("WaitForExit returned");
Thread.Sleep(2000);
proc.Close();
}
catch (Exception)
{
Console.WriteLine("Exception caught, rethrowing");
Thread.Sleep(2000);
throw;
}
}
private string cmd;
private Process proc;
}
When executed with no parameters, it spawns a process and executes itself with a parameter. I then captures the output of the spawned process and writes it to the Console.
When executed with at least one parameter, it loops ten times spitting "this is a test" out to the Console once a second.
//some irrelevant code removed
if (!Main.batchonly)
{
//setup the xmlput process
Process xmlput = new Process();
ProcessStartInfo xmlputstartinfo = new ProcessStartInfo
((string)Registry.GetValue(Main.key1, "UtilDir", "Not found") + @"\xmlput.exe");
// Saves a bit of typing as it is repeated in other places
Main.xmlutilsetup(xmlput, xmlputstartinfo, arguments);
//set up and show transfer status headlines, calculate progress bar increment
la_ProcessStatus.Text = "Sending Clip " + clip.Sourcedir + " to " + Qsystem;
la_clargs.Text = "xmlput " + arguments;
pb_clip.Value = 1;
pb_clip.Minimum = 1;
pb_clip.Maximum = int.Parse(clip.Duration) + 1;
//set up event handlers for the process end and output
xmlput.EnableRaisingEvents = true;
xmlput.OutputDataReceived += new DataReceivedEventHandler(xmlput_OutputDataReceived);
xmlput.Exited += new EventHandler(xmlput_Exited);
// run the process and start watching for output
xmlput.Start();
xmlput.BeginOutputReadLine();
}
}
Here's all the event handlers
//Event handler for process exit - simply close form
//BeginInvoke avoids cross thread exceptions
void xmlput_Exited(object sender, EventArgs e)
{
this.BeginInvoke(new labelupdate(closeform));
}
//actual method called by above delegate when the process has ended
public void closeform()
{
this.Close();
}
//Event handler for redirected process output
//Asynchronously gets lines of output from Qxmlput
//Begin.Invoke avoids cross thread exceptions on label and progress bar update
private void xmlput_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if(!String.IsNullOrEmpty(e.Data))
{
processoutput = e.Data;
//look for the framenum line ignore everything else
//when found it means another frame has been transferred
//so update the progress bar and label
//begininvoke required to avoid cross thread errors
if (processoutput.Contains("<FRA"))
{
processmessage = processoutput;
la_ProcessComms.BeginInvoke(new labelupdate(updatecomms));
}
else if (processoutput.StartsWith("<ERROR>"))
{
TransferFailed = true;
}
}
}
// Actual method called by above delegate to update form with process output
public void updatecomms()
{
la_ProcessComms.Text = processmessage;
if (pb_clip.Value < pb_clip.Maximum)
{
pb_clip.Value ++;
}
}
//delegate to avoid cross thread errors
//used to update labels and progress bar from process events
public delegate void labelupdate();
//setup processes to redirect output, avoid flashing and with CL arguments
//static public so can be used by other classes
public static void xmlutilsetup(Process xmlutil, ProcessStartInfo xmlutilstartinfo, string xmlutilargs)
{
xmlutil.StartInfo = xmlutilstartinfo;
xmlutilstartinfo.RedirectStandardOutput = true;
xmlutilstartinfo.UseShellExecute = false;
xmlutilstartinfo.CreateNoWindow = true;
xmlutilstartinfo.Arguments = xmlutilargs;
}