1 // created on 12/18/2004 at 16:28
3 using System.Threading;
4 using System.Diagnostics;
6 namespace Microsoft.Build.Utilities
8 internal delegate void ProcessEventHandler(object sender, string message);
10 internal class ProcessWrapper : Process, IProcessAsyncOperation
12 private Thread captureOutputThread;
13 private Thread captureErrorThread;
14 ManualResetEvent endEventOut = new ManualResetEvent (false);
15 ManualResetEvent endEventErr = new ManualResetEvent (false);
17 object lockObj = new object ();
19 public ProcessWrapper ()
23 public new void Start ()
28 captureOutputThread = new Thread (new ThreadStart(CaptureOutput));
29 captureOutputThread.IsBackground = true;
30 captureOutputThread.Start ();
32 if (ErrorStreamChanged != null) {
33 captureErrorThread = new Thread (new ThreadStart(CaptureError));
34 captureErrorThread.IsBackground = true;
35 captureErrorThread.Start ();
41 public void WaitForOutput (int milliseconds)
44 WaitForExit (milliseconds);
45 WaitHandle.WaitAll (new WaitHandle[] {endEventOut});
48 public void WaitForOutput ()
53 private void CaptureOutput ()
56 if (OutputStreamChanged != null) {
57 char[] buffer = new char [1024];
59 while ((nr = StandardOutput.Read (buffer, 0, buffer.Length)) > 0) {
60 if (OutputStreamChanged != null)
61 OutputStreamChanged (this, new string (buffer, 0, nr));
64 } catch (ThreadAbortException) {
65 // There is no need to keep propagating the abort exception
68 // WORKAROUND for "Bug 410743 - wapi leak in System.Diagnostic.Process"
69 // Process leaks when an exit event is registered
70 WaitHandle.WaitAll (new WaitHandle[] {endEventErr});
72 OnExited (this, EventArgs.Empty);
74 //call this AFTER the exit event, or the ProcessWrapper may get disposed and abort this thread
75 if (endEventOut != null)
80 private void CaptureError ()
83 char[] buffer = new char [1024];
85 while ((nr = StandardError.Read (buffer, 0, buffer.Length)) > 0) {
86 if (ErrorStreamChanged != null)
87 ErrorStreamChanged (this, new string (buffer, 0, nr));
94 protected override void Dispose (bool disposing)
97 if (endEventOut == null)
102 ((IAsyncOperation)this).Cancel ();
104 captureOutputThread = captureErrorThread = null;
105 endEventOut.Close ();
106 endEventErr.Close ();
107 endEventOut = endEventErr = null;
109 base.Dispose (disposing);
112 void CheckDisposed ()
114 if (endEventOut == null)
115 throw new ObjectDisposedException ("ProcessWrapper");
118 int IProcessAsyncOperation.ExitCode {
119 get { return ExitCode; }
122 int IProcessAsyncOperation.ProcessId {
126 void IAsyncOperation.Cancel ()
135 if (captureOutputThread != null)
136 captureOutputThread.Abort ();
137 if (captureErrorThread != null)
138 captureErrorThread.Abort ();
140 } catch (Exception ex) {
142 Console.WriteLine (ex.ToString ());
143 //LoggingService.LogError (ex.ToString ());
147 void IAsyncOperation.WaitForCompleted ()
152 void OnExited (object sender, EventArgs args)
163 if (completedEvent != null)
164 completedEvent (this);
172 event OperationHandler IAsyncOperation.Completed {
174 bool raiseNow = false;
179 completedEvent += value;
186 completedEvent -= value;
191 bool IAsyncOperation.Success {
192 get { return done ? ExitCode == 0 : false; }
195 bool IAsyncOperation.SuccessWithWarnings {
196 get { return false; }
199 bool IAsyncOperation.IsCompleted {
203 event OperationHandler completedEvent;
205 public event ProcessEventHandler OutputStreamChanged;
206 public event ProcessEventHandler ErrorStreamChanged;