using System; using System.Diagnostics; using System.IO; using System.Text; using System.Threading; using System.Windows.Forms; using System.Collections; using System.ComponentModel; namespace System.Diagnostics.ProcessCaller { /// /// Delegate used by the events StdOutReceived and StdErrReceived. /// public delegate void DataReceivedHandler(object sender, DataReceivedEventArgs e); /// /// Event Args for above delegate /// public class DataReceivedEventArgs : EventArgs { /// /// The text that was received /// public string Text; /// /// Constructor /// /// The text that was received for this event to be triggered. public DataReceivedEventArgs(string text) { this.Text = text; } } /// /// A class to launch a process (ie. *.exe, *.bat, etc.) and /// return the StandardOutput and StandardError lines during execution. /// /// /// This class was based on the ProcessCaller class by Michael Mayer /// which was released under public domain licensing. /// public class ProcessCaller : AsyncOperation { /// /// The command to run (should be made into a property) /// public string FileName; /// /// The Arguments for the cmd (should be made into a property) /// public string Arguments; /// /// The WorkingDirectory (should be made into a property) /// public string WorkingDirectory; /// /// Fired for every line of stdOut received. /// public event DataReceivedHandler StdOutReceived; /// /// Fired for every line of stdErr received. /// public event DataReceivedHandler StdErrReceived; /// /// Amount of time to sleep on threads while waiting /// for the process to finish. /// public int SleepTime = 500; /// /// The process used to run your task /// private Process process; /// /// Initialises a ProcessCaller with an association to the /// supplied ISynchronizeInvoke. All events raised from this /// object will be delivered via this target. (This might be a /// Control object, so events would be delivered to that Control's /// UI thread.) /// /// An object implementing the /// ISynchronizeInvoke interface. All events will be delivered /// through this target, ensuring that they are delivered to the /// correct thread. public ProcessCaller(ISynchronizeInvoke isi) : base(isi) { } /// /// Launch a process, but do not return until the process has exited. /// That way we can kill the process if a cancel is requested. /// protected override void DoWork() { this.StartProcess(); // Wait for the process to end, or cancel it while (! process.HasExited) { Thread.Sleep(SleepTime); // sleep if (this.CancelRequested) { // Not a very nice way to end a process, // but effective. process.Kill(); this.AcknowledgeCancel(); } } } /// /// This method is generally called by DoWork() /// which is called by the base classs Start() /// protected virtual void StartProcess() { // Start a new process for the cmd process = new Process(); process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.CreateNoWindow = true; process.StartInfo.FileName = FileName; process.StartInfo.Arguments = Arguments; process.StartInfo.WorkingDirectory = WorkingDirectory; process.Start(); // Invoke stdOut and stdErr readers - each // has its own thread to guarantee that they aren't // blocked by, or cause a block to, the actual // process running (or the gui). new MethodInvoker(ReadStdOut).BeginInvoke(null, null); new MethodInvoker(ReadStdErr).BeginInvoke(null, null); } /// /// Handles reading of stdout and firing an event for /// every line read /// protected virtual void ReadStdOut() { string line; while ((line = process.StandardOutput.ReadLine()) != null) this.FireAsync(StdOutReceived, this, new DataReceivedEventArgs(line)); } /// /// Handles reading of stdErr /// protected virtual void ReadStdErr() { string line; while ((line = process.StandardError.ReadLine()) != null) { this.FireAsync(StdErrReceived, this, new DataReceivedEventArgs(line)); } } } }