Merge pull request #1218 from AndreyAkinshin/master
[mono.git] / mcs / class / System / System.Diagnostics / Process.cs
1 //
2 // System.Diagnostics.Process.cs
3 //
4 // Authors:
5 //      Dick Porter (dick@ximian.com)
6 //      Andreas Nahr (ClassDevelopment@A-SoftTech.com)
7 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 //
9 // (C) 2002 Ximian, Inc.
10 // (C) 2003 Andreas Nahr
11 // (c) 2004,2005,2006 Novell, Inc. (http://www.novell.com)
12 //
13
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34
35 using System.IO;
36 using System.Text;
37 using System.ComponentModel;
38 using System.ComponentModel.Design;
39 using System.Runtime.CompilerServices;
40 using System.Runtime.InteropServices;
41 using System.Runtime.Remoting.Messaging;
42 using System.Security.Permissions;
43 using System.Collections.Generic;
44 using System.Security;
45 using System.Threading;
46 using Microsoft.Win32.SafeHandles;
47
48 namespace System.Diagnostics {
49
50         [DefaultEvent ("Exited"), DefaultProperty ("StartInfo")]
51         [Designer ("System.Diagnostics.Design.ProcessDesigner, " + Consts.AssemblySystem_Design)]
52         [PermissionSet (SecurityAction.LinkDemand, Unrestricted = true)]
53         [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
54         [MonitoringDescription ("Represents a system process")]
55         public class Process : Component 
56         {
57                 [StructLayout(LayoutKind.Sequential)]
58                 private struct ProcInfo 
59                 {
60                         public IntPtr process_handle;
61                         /* If thread_handle is ever needed for
62                          * something, take out the CloseHandle() in
63                          * the Start_internal icall in
64                          * mono/metadata/process.c
65                          */
66                         public IntPtr thread_handle;
67                         public int pid; // Contains -GetLastError () on failure.
68                         public int tid;
69                         public string [] envKeys;
70                         public string [] envValues;
71                         public string UserName;
72                         public string Domain;
73                         public IntPtr Password;
74                         public bool LoadUserProfile;
75                 };
76                 
77                 IntPtr process_handle;
78                 int pid;
79                 bool enableRaisingEvents;
80                 RegisteredWaitHandle exitWaitHandle;
81                 ISynchronizeInvoke synchronizingObject;
82                 EventHandler exited_event;
83                 IntPtr stdout_rd;
84                 IntPtr stderr_rd;
85
86                 object thisLock = new Object ();
87
88                 /* Private constructor called from other methods */
89                 private Process(IntPtr handle, int id) {
90                         process_handle=handle;
91                         pid=id;
92                 }
93                 
94                 public Process ()
95                 {
96                 }
97
98                 [MonoTODO]
99                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
100                 [MonitoringDescription ("Base process priority.")]
101                 public int BasePriority {
102                         get {
103                                 return(0);
104                         }
105                 }
106
107                 void StartExitCallbackIfNeeded ()
108                 {
109                         lock (thisLock) {
110                                 bool start = (exitWaitHandle == null && enableRaisingEvents && exited_event != null);
111                                 if (start && process_handle != IntPtr.Zero) {
112                                         WaitOrTimerCallback cb = new WaitOrTimerCallback (CBOnExit);
113                                         ProcessWaitHandle h = new ProcessWaitHandle (process_handle);
114                                         exitWaitHandle = ThreadPool.RegisterWaitForSingleObject (h, cb, this, -1, true);
115                                 }
116                         }
117                 }
118
119                 void UnregisterExitCallback ()
120                 {
121                         lock (thisLock) {
122                                 if (exitWaitHandle != null) {
123                                         exitWaitHandle.Unregister (null);
124                                         exitWaitHandle = null;
125                                 }
126                         }
127                 }
128
129                 bool IsExitCallbackPending ()
130                 {
131                         lock (thisLock) {
132                                 return exitWaitHandle != null;
133                         }
134                 }
135
136                 [DefaultValue (false), Browsable (false)]
137                 [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
138                 public bool EnableRaisingEvents {
139                         get {
140                                 return enableRaisingEvents;
141                         }
142                         set { 
143                                 bool prev = enableRaisingEvents;
144                                 enableRaisingEvents = value;
145                                 if (enableRaisingEvents && !prev)
146                                         StartExitCallbackIfNeeded ();
147                         }
148
149                 }
150
151                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
152                 private extern static int ExitCode_internal(IntPtr handle);
153
154                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
155                 [MonitoringDescription ("The exit code of the process.")]
156                 public int ExitCode {
157                         get {
158                                 if (process_handle == IntPtr.Zero)
159                                         throw new InvalidOperationException ("Process has not been started.");
160
161                                 int code = ExitCode_internal (process_handle);
162                                 if (code == 259)
163                                         throw new InvalidOperationException ("The process must exit before " +
164                                                                         "getting the requested information.");
165
166                                 return code;
167                         }
168                 }
169
170                 /* Returns the process start time in Windows file
171                  * times (ticks from DateTime(1/1/1601 00:00 GMT))
172                  */
173                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
174                 private extern static long ExitTime_internal(IntPtr handle);
175                 
176                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
177                 [MonitoringDescription ("The exit time of the process.")]
178                 public DateTime ExitTime {
179                         get {
180                                 if (process_handle == IntPtr.Zero)
181                                         throw new InvalidOperationException ("Process has not been started.");
182
183                                 if (!HasExited)
184                                         throw new InvalidOperationException ("The process must exit before " +
185                                                                         "getting the requested information.");
186
187                                 return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
188                         }
189                 }
190
191                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
192                 [MonitoringDescription ("Handle for this process.")]
193                 public IntPtr Handle {
194                         get {
195                                 if (process_handle == IntPtr.Zero)
196                                         throw new InvalidOperationException ("No process is associated with this object.");
197                                 return(process_handle);
198                         }
199                 }
200
201                 [MonoTODO]
202                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
203                 [MonitoringDescription ("Handles for this process.")]
204                 public int HandleCount {
205                         get {
206                                 return(0);
207                         }
208                 }
209
210                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
211                 [MonitoringDescription ("Determines if the process is still running.")]
212                 public bool HasExited {
213                         get {
214                                 if (process_handle == IntPtr.Zero)
215                                         throw new InvalidOperationException ("Process has not been started.");
216                                         
217                                 int exitcode = ExitCode_internal (process_handle);
218
219                                 if(exitcode==259) {
220                                         /* STILL_ACTIVE */
221                                         return(false);
222                                 } else {
223                                         return(true);
224                                 }
225                         }
226                 }
227
228                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
229                 [MonitoringDescription ("Process identifier.")]
230                 public int Id {
231                         get {
232                                 if (pid == 0)
233                                         throw new InvalidOperationException ("Process ID has not been set.");
234
235                                 return(pid);
236                         }
237                 }
238
239                 [MonoTODO]
240                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
241                 [MonitoringDescription ("The name of the computer running the process.")]
242                 public string MachineName {
243                         get {
244                                 return("localhost");
245                         }
246                 }
247
248                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
249                 [MonitoringDescription ("The main module of the process.")]
250                 public ProcessModule MainModule {
251                         get {
252                                 return(this.Modules[0]);
253                         }
254                 }
255
256                 [MonoTODO]
257                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
258                 [MonitoringDescription ("The handle of the main window of the process.")]
259                 public IntPtr MainWindowHandle {
260                         get {
261                                 return((IntPtr)0);
262                         }
263                 }
264
265                 [MonoTODO]
266                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
267                 [MonitoringDescription ("The title of the main window of the process.")]
268                 public string MainWindowTitle {
269                         get {
270                                 return("null");
271                         }
272                 }
273
274                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
275                 private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
276                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
277                 private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);
278
279                 /* LAMESPEC: why is this an IntPtr not a plain int? */
280                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
281                 [MonitoringDescription ("The maximum working set for this process.")]
282                 public IntPtr MaxWorkingSet {
283                         get {
284                                 if(HasExited)
285                                         throw new InvalidOperationException(
286                                                 "The process " + ProcessName +
287                                                 " (ID " + Id + ") has exited");
288                                 
289                                 int min;
290                                 int max;
291                                 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
292                                 if(ok==false) {
293                                         throw new Win32Exception();
294                                 }
295                                 
296                                 return((IntPtr)max);
297                         }
298                         set {
299                                 if(HasExited) {
300                                         throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
301                                 }
302                                 
303                                 bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
304                                 if(ok==false) {
305                                         throw new Win32Exception();
306                                 }
307                         }
308                 }
309
310                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
311                 [MonitoringDescription ("The minimum working set for this process.")]
312                 public IntPtr MinWorkingSet {
313                         get {
314                                 if(HasExited)
315                                         throw new InvalidOperationException(
316                                                 "The process " + ProcessName +
317                                                 " (ID " + Id + ") has exited");
318                                 
319                                 int min;
320                                 int max;
321                                 bool ok= GetWorkingSet_internal (process_handle, out min, out max);
322                                 if(!ok)
323                                         throw new Win32Exception();
324                                 return ((IntPtr) min);
325                         }
326                         set {
327                                 if(HasExited)
328                                         throw new InvalidOperationException(
329                                                 "The process " + ProcessName +
330                                                 " (ID " + Id + ") has exited");
331                                 
332                                 bool ok = SetWorkingSet_internal (process_handle, value.ToInt32(), 0, true);
333                                 if (!ok)
334                                         throw new Win32Exception();
335                         }
336                 }
337
338                 /* Returns the list of process modules.  The main module is
339                  * element 0.
340                  */
341                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
342                 private extern ProcessModule[] GetModules_internal(IntPtr handle);
343
344                 private ProcessModuleCollection module_collection;
345                 
346                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
347                 [MonitoringDescription ("The modules that are loaded as part of this process.")]
348                 public ProcessModuleCollection Modules {
349                         get {
350                                 if (module_collection == null)
351                                         module_collection = new ProcessModuleCollection(
352                                                 GetModules_internal (process_handle));
353                                 return(module_collection);
354                         }
355                 }
356
357                 /* data type is from the MonoProcessData enum in mono-proclib.h in the runtime */
358                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
359                 private extern static long GetProcessData (int pid, int data_type, out int error);
360
361                 [MonoTODO]
362                 [Obsolete ("Use NonpagedSystemMemorySize64")]
363                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
364                 [MonitoringDescription ("The number of bytes that are not pageable.")]
365                 public int NonpagedSystemMemorySize {
366                         get {
367                                 return(0);
368                         }
369                 }
370
371                 [Obsolete ("Use PagedMemorySize64")]
372                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
373                 [MonitoringDescription ("The number of bytes that are paged.")]
374                 public int PagedMemorySize {
375                         get {
376                                 return(int)PagedMemorySize64;
377                         }
378                 }
379
380                 [Obsolete ("Use PagedSystemMemorySize64")]
381                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
382                 [MonitoringDescription ("The amount of paged system memory in bytes.")]
383                 public int PagedSystemMemorySize {
384                         get {
385                                 return(int)PagedMemorySize64;
386                         }
387                 }
388
389                 [MonoTODO]
390                 [Obsolete ("Use PeakPagedMemorySize64")]
391                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
392                 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
393                 public int PeakPagedMemorySize {
394                         get {
395                                 return(0);
396                         }
397                 }
398
399                 [Obsolete ("Use PeakVirtualMemorySize64")]
400                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
401                 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
402                 public int PeakVirtualMemorySize {
403                         get {
404                                 int error;
405                                 return (int)GetProcessData (pid, 8, out error);
406                         }
407                 }
408
409                 [Obsolete ("Use PeakWorkingSet64")]
410                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
411                 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
412                 public int PeakWorkingSet {
413                         get {
414                                 int error;
415                                 return (int)GetProcessData (pid, 5, out error);
416                         }
417                 }
418
419                 [MonoTODO]
420                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
421                 [MonitoringDescription ("The number of bytes that are not pageable.")]
422                 [ComVisible (false)]
423                 public long NonpagedSystemMemorySize64 {
424                         get {
425                                 return(0);
426                         }
427                 }
428
429                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
430                 [MonitoringDescription ("The number of bytes that are paged.")]
431                 [ComVisible (false)]
432                 public long PagedMemorySize64 {
433                         get {
434                                 int error;
435                                 return GetProcessData (pid, 12, out error);
436                         }
437                 }
438
439                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
440                 [MonitoringDescription ("The amount of paged system memory in bytes.")]
441                 [ComVisible (false)]
442                 public long PagedSystemMemorySize64 {
443                         get {
444                                 return PagedMemorySize64;
445                         }
446                 }
447
448                 [MonoTODO]
449                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
450                 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
451                 [ComVisible (false)]
452                 public long PeakPagedMemorySize64 {
453                         get {
454                                 return(0);
455                         }
456                 }
457
458                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
459                 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
460                 [ComVisible (false)]
461                 public long PeakVirtualMemorySize64 {
462                         get {
463                                 int error;
464                                 return GetProcessData (pid, 8, out error);
465                         }
466                 }
467
468                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
469                 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
470                 [ComVisible (false)]
471                 public long PeakWorkingSet64 {
472                         get {
473                                 int error;
474                                 return GetProcessData (pid, 5, out error);
475                         }
476                 }
477
478                 [MonoTODO]
479                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
480                 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
481                 public bool PriorityBoostEnabled {
482                         get {
483                                 return(false);
484                         }
485                         set {
486                         }
487                 }
488
489                 [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
490                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
491                 [MonitoringDescription ("The relative process priority.")]
492                 public ProcessPriorityClass PriorityClass {
493                         get {
494                                 if (process_handle == IntPtr.Zero)
495                                         throw new InvalidOperationException ("Process has not been started.");
496                                 
497                                 int error;
498                                 int prio = GetPriorityClass (process_handle, out error);
499                                 if (prio == 0)
500                                         throw new Win32Exception (error);
501                                 return (ProcessPriorityClass) prio;
502                         }
503                         set {
504                                 if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
505                                         throw new InvalidEnumArgumentException (
506                                                 "value", (int) value,
507                                                 typeof (ProcessPriorityClass));
508
509                                 if (process_handle == IntPtr.Zero)
510                                         throw new InvalidOperationException ("Process has not been started.");
511                                 
512                                 int error;
513                                 if (!SetPriorityClass (process_handle, (int) value, out error)) {
514                                         CheckExited ();
515                                         throw new Win32Exception (error);
516                                 }
517                         }
518                 }
519
520                 void CheckExited () {
521                         if (HasExited)
522                                 throw new InvalidOperationException (String.Format ("Cannot process request because the process ({0}) has exited.", Id));
523                 }
524
525                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
526                 static extern int GetPriorityClass (IntPtr handle, out int error);
527
528                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
529                 static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);
530
531                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
532                 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
533                 [Obsolete ("Use PrivateMemorySize64")]
534                 public int PrivateMemorySize {
535                         get {
536                                 int error;
537                                 return (int)GetProcessData (pid, 6, out error);
538                         }
539                 }
540
541                 [MonoNotSupported ("")]
542                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
543                 [MonitoringDescription ("The session ID for this process.")]
544                 public int SessionId {
545                         get { throw new NotImplementedException (); }
546                 }
547
548                 /* the meaning of type is as follows: 0: user, 1: system, 2: total */
549                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
550                 private extern static long Times (IntPtr handle, int type);
551
552                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
553                 [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
554                 public TimeSpan PrivilegedProcessorTime {
555                         get {
556                                 return new TimeSpan (Times (process_handle, 1));
557                         }
558                 }
559
560                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
561                 private extern static string ProcessName_internal(IntPtr handle);
562                 
563                 private string process_name=null;
564                 
565                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
566                 [MonitoringDescription ("The name of this process.")]
567                 public string ProcessName {
568                         get {
569                                 if(process_name==null) {
570                                         
571                                         if (process_handle == IntPtr.Zero)
572                                                 throw new InvalidOperationException ("No process is associated with this object.");
573                                         
574                                         process_name=ProcessName_internal(process_handle);
575                                         /* If process_name is _still_
576                                          * null, assume the process
577                                          * has exited
578                                          */
579                                         if (process_name == null)
580                                                 throw new InvalidOperationException ("Process has exited, so the requested information is not available.");
581                                         
582                                         /* Strip the suffix (if it
583                                          * exists) simplistically
584                                          * instead of removing any
585                                          * trailing \.???, so we dont
586                                          * get stupid results on sane
587                                          * systems
588                                          */
589                                         if(process_name.EndsWith(".exe") ||
590                                            process_name.EndsWith(".bat") ||
591                                            process_name.EndsWith(".com")) {
592                                                 process_name=process_name.Substring(0, process_name.Length-4);
593                                         }
594                                 }
595                                 return(process_name);
596                         }
597                 }
598
599                 [MonoTODO]
600                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
601                 [MonitoringDescription ("Allowed processor that can be used by this process.")]
602                 public IntPtr ProcessorAffinity {
603                         get {
604                                 return((IntPtr)0);
605                         }
606                         set {
607                         }
608                 }
609
610                 [MonoTODO]
611                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
612                 [MonitoringDescription ("Is this process responsive.")]
613                 public bool Responding {
614                         get {
615                                 return(false);
616                         }
617                 }
618
619                 private StreamReader error_stream=null;
620                 bool error_stream_exposed;
621
622                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
623                 [MonitoringDescription ("The standard error stream of this process.")]
624                 public StreamReader StandardError {
625                         get {
626                                 if (error_stream == null)
627                                         throw new InvalidOperationException("Standard error has not been redirected");
628
629                                 if ((async_mode & AsyncModes.AsyncError) != 0)
630                                         throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
631
632                                 async_mode |= AsyncModes.SyncError;
633
634                                 error_stream_exposed = true;
635                                 return(error_stream);
636                         }
637                 }
638
639                 private StreamWriter input_stream=null;
640                 bool input_stream_exposed;
641                 
642                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
643                 [MonitoringDescription ("The standard input stream of this process.")]
644                 public StreamWriter StandardInput {
645                         get {
646                                 if (input_stream == null)
647                                         throw new InvalidOperationException("Standard input has not been redirected");
648
649                                 input_stream_exposed = true;
650                                 return(input_stream);
651                         }
652                 }
653
654                 private StreamReader output_stream=null;
655                 bool output_stream_exposed;
656                 
657                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
658                 [MonitoringDescription ("The standard output stream of this process.")]
659                 public StreamReader StandardOutput {
660                         get {
661                                 if (output_stream == null)
662                                         throw new InvalidOperationException("Standard output has not been redirected");
663
664                                 if ((async_mode & AsyncModes.AsyncOutput) != 0)
665                                         throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
666
667                                 async_mode |= AsyncModes.SyncOutput;
668
669                                 output_stream_exposed = true;
670                                 return(output_stream);
671                         }
672                 }
673
674                 private ProcessStartInfo start_info=null;
675                 
676                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
677                 [MonitoringDescription ("Information for the start of this process.")]
678                 public ProcessStartInfo StartInfo {
679                         get {
680                                 if (start_info == null)
681                                         start_info = new ProcessStartInfo();
682                                 return start_info;
683                         }
684                         set {
685                                 if (value == null)
686                                         throw new ArgumentNullException("value");
687                                 start_info = value;
688                         }
689                 }
690
691                 /* Returns the process start time in Windows file
692                  * times (ticks from DateTime(1/1/1601 00:00 GMT))
693                  */
694                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
695                 private extern static long StartTime_internal(IntPtr handle);
696                 
697                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
698                 [MonitoringDescription ("The time this process started.")]
699                 public DateTime StartTime {
700                         get {
701                                 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
702                         }
703                 }
704
705                 [DefaultValue (null), Browsable (false)]
706                 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
707                 public ISynchronizeInvoke SynchronizingObject {
708                         get { return synchronizingObject; }
709                         set { synchronizingObject = value; }
710                 }
711
712                 [MonoTODO]
713                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
714                 [MonitoringDescription ("The number of threads of this process.")]
715                 public ProcessThreadCollection Threads {
716                         get {
717                                 // This'll return a correctly-sized array of empty ProcessThreads for now.
718                                 int error;
719                                 return new ProcessThreadCollection(new ProcessThread[GetProcessData (pid, 0, out error)]);
720                         }
721                 }
722
723                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
724                 [MonitoringDescription ("The total CPU time spent for this process.")]
725                 public TimeSpan TotalProcessorTime {
726                         get {
727                                 return new TimeSpan (Times (process_handle, 2));
728                         }
729                 }
730
731                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
732                 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
733                 public TimeSpan UserProcessorTime {
734                         get {
735                                 return new TimeSpan (Times (process_handle, 0));
736                         }
737                 }
738
739                 [Obsolete ("Use VirtualMemorySize64")]
740                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
741                 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
742                 public int VirtualMemorySize {
743                         get {
744                                 int error;
745                                 return (int)GetProcessData (pid, 7, out error);
746                         }
747                 }
748
749                 [Obsolete ("Use WorkingSet64")]
750                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
751                 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
752                 public int WorkingSet {
753                         get {
754                                 int error;
755                                 return (int)GetProcessData (pid, 4, out error);
756                         }
757                 }
758
759                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
760                 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
761                 [ComVisible (false)]
762                 public long PrivateMemorySize64 {
763                         get {
764                                 int error;
765                                 return GetProcessData (pid, 6, out error);
766                         }
767                 }
768
769                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
770                 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
771                 [ComVisible (false)]
772                 public long VirtualMemorySize64 {
773                         get {
774                                 int error;
775                                 return GetProcessData (pid, 7, out error);
776                         }
777                 }
778
779                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
780                 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
781                 [ComVisible (false)]
782                 public long WorkingSet64 {
783                         get {
784                                 int error;
785                                 return GetProcessData (pid, 4, out error);
786                         }
787                 }
788
789                 public void Close()
790                 {
791                         Dispose (true);
792                 }
793
794                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
795                 extern static bool Kill_internal (IntPtr handle, int signo);
796
797                 /* int kill -> 1 KILL, 2 CloseMainWindow */
798                 bool Close (int signo)
799                 {
800                         if (process_handle == IntPtr.Zero)
801                                 throw new SystemException ("No process to kill.");
802
803                         int exitcode = ExitCode_internal (process_handle);
804                         if (exitcode != 259)
805                                 throw new InvalidOperationException ("The process already finished.");
806
807                         return Kill_internal (process_handle, signo);
808                 }
809
810                 public bool CloseMainWindow ()
811                 {
812                         return Close (2);
813                 }
814
815                 [MonoTODO]
816                 public static void EnterDebugMode() {
817                 }
818
819                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
820                 private extern static IntPtr GetProcess_internal(int pid);
821                 
822                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
823                 private extern static int GetPid_internal();
824
825                 public static Process GetCurrentProcess()
826                 {
827                         int pid = GetPid_internal();
828                         IntPtr proc = GetProcess_internal(pid);
829                         
830                         if (proc == IntPtr.Zero)
831                                 throw new SystemException("Can't find current process");
832
833                         return (new Process (proc, pid));
834                 }
835
836                 public static Process GetProcessById(int processId)
837                 {
838                         IntPtr proc = GetProcess_internal(processId);
839                         
840                         if (proc == IntPtr.Zero)
841                                 throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
842
843                         return (new Process (proc, processId));
844                 }
845
846                 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
847                 public static Process GetProcessById(int processId, string machineName) {
848                         if (machineName == null)
849                                 throw new ArgumentNullException ("machineName");
850
851                         if (!IsLocalMachine (machineName))
852                                 throw new NotImplementedException ();
853
854                         return GetProcessById (processId);
855                 }
856
857                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
858                 private extern static int[] GetProcesses_internal();
859
860                 public static Process[] GetProcesses ()
861                 {
862                         int [] pids = GetProcesses_internal ();
863                         if (pids == null)
864                                 return new Process [0];
865
866                         var proclist = new List<Process> (pids.Length);
867                         for (int i = 0; i < pids.Length; i++) {
868                                 try {
869                                         proclist.Add (GetProcessById (pids [i]));
870                                 } catch (SystemException) {
871                                         /* The process might exit
872                                          * between
873                                          * GetProcesses_internal and
874                                          * GetProcessById
875                                          */
876                                 }
877                         }
878
879                         return proclist.ToArray ();
880                 }
881
882                 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
883                 public static Process[] GetProcesses(string machineName) {
884                         if (machineName == null)
885                                 throw new ArgumentNullException ("machineName");
886
887                         if (!IsLocalMachine (machineName))
888                                 throw new NotImplementedException ();
889
890                         return GetProcesses ();
891                 }
892
893                 public static Process[] GetProcessesByName(string processName)
894                 {
895                         int [] pids = GetProcesses_internal ();
896                         if (pids == null)
897                                 return new Process [0];
898                         
899                         var proclist = new List<Process> (pids.Length);
900                         for (int i = 0; i < pids.Length; i++) {
901                                 try {
902                                         Process p = GetProcessById (pids [i]);
903                                         if (String.Compare (processName, p.ProcessName, true) == 0)
904                                                 proclist.Add (p);
905                                 } catch (SystemException) {
906                                         /* The process might exit
907                                          * between
908                                          * GetProcesses_internal and
909                                          * GetProcessById
910                                          */
911                                 }
912                         }
913
914                         return proclist.ToArray ();
915                 }
916
917                 [MonoTODO]
918                 public static Process[] GetProcessesByName(string processName, string machineName) {
919                         throw new NotImplementedException();
920                 }
921
922                 public void Kill ()
923                 {
924                         Close (1);
925                 }
926
927                 [MonoTODO]
928                 public static void LeaveDebugMode() {
929                 }
930
931                 public void Refresh ()
932                 {
933                         // FIXME: should refresh any cached data we might have about
934                         // the process (currently we have none).
935                 }
936
937                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
938                 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
939                                                                    ref ProcInfo proc_info);
940
941                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
942                 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
943                                                                   IntPtr stdin,
944                                                                   IntPtr stdout,
945                                                                   IntPtr stderr,
946                                                                   ref ProcInfo proc_info);
947
948                 private static bool Start_shell (ProcessStartInfo startInfo, Process process)
949                 {
950                         ProcInfo proc_info=new ProcInfo();
951                         bool ret;
952
953                         if (startInfo.RedirectStandardInput ||
954                             startInfo.RedirectStandardOutput ||
955                             startInfo.RedirectStandardError) {
956                                 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
957                         }
958
959                         if (startInfo.HaveEnvVars)
960                                 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
961
962                         FillUserInfo (startInfo, ref proc_info);
963                         try {
964                                 ret = ShellExecuteEx_internal (startInfo,
965                                                                ref proc_info);
966                         } finally {
967                                 if (proc_info.Password != IntPtr.Zero)
968                                         Marshal.ZeroFreeBSTR (proc_info.Password);
969                                 proc_info.Password = IntPtr.Zero;
970                         }
971                         if (!ret) {
972                                 throw new Win32Exception (-proc_info.pid);
973                         }
974
975                         process.process_handle = proc_info.process_handle;
976                         process.pid = proc_info.pid;
977                         process.StartExitCallbackIfNeeded ();
978                         return(ret);
979                 }
980
981                 //
982                 // Creates a pipe with read and write descriptors
983                 //
984                 static void CreatePipe (out IntPtr read, out IntPtr write, bool writeDirection)
985                 {
986                         //
987                         // Creates read/write pipe from parent -> child perspective
988                         // a child process uses same descriptors after fork. That's
989                         // 4 descriptors in total where only 2. One in child, one in parent
990                         // should be active and the other 2 closed. Which ones depends on
991                         // comunication direction
992                         //
993                         // parent  -------->  child   (parent can write, child can read)
994                         //
995                         // read: closed       read: used
996                         // write: used        write: closed
997                         //
998                         //
999                         // parent  <--------  child   (parent can read, child can write)
1000                         //
1001                         // read: used         read: closed
1002                         // write: closed      write: used
1003                         //
1004                         // It can still be tricky for predefined descriptiors http://unixwiz.net/techtips/remap-pipe-fds.html
1005                         //
1006                         var ret = MonoIO.CreatePipe (out read, out write);
1007                         if (!ret)
1008                                 throw new IOException ("Error creating process pipe");
1009
1010                         if (IsWindows) {
1011                                 const int DUPLICATE_SAME_ACCESS = 0x00000002;
1012                                 var tmp = writeDirection ? write : read;
1013
1014                                 ret = MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, tmp,
1015                                         Process.GetCurrentProcess ().Handle, out tmp, 0, 0, DUPLICATE_SAME_ACCESS);
1016                                 if (!ret)
1017                                         return;
1018
1019                                 MonoIOError error;
1020                                 if (writeDirection) {
1021                                         MonoIO.Close (write, out error);
1022                                         write = tmp;
1023                                 } else {
1024                                         MonoIO.Close (read, out error);
1025                                         read = tmp;
1026                                 }
1027                         }
1028                 }
1029
1030                 static bool Start_noshell (ProcessStartInfo startInfo, Process process)
1031                 {
1032                         var proc_info = new ProcInfo ();
1033
1034                         if (startInfo.HaveEnvVars) {
1035                                 string [] strs = new string [startInfo.EnvironmentVariables.Count];
1036                                 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
1037                                 proc_info.envKeys = strs;
1038
1039                                 strs = new string [startInfo.EnvironmentVariables.Count];
1040                                 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
1041                                 proc_info.envValues = strs;
1042                         }
1043
1044                         MonoIOError error;
1045                         IntPtr stdin_read = IntPtr.Zero, stdin_write = IntPtr.Zero;
1046                         IntPtr stdout_read = IntPtr.Zero, stdout_write = IntPtr.Zero;
1047                         IntPtr stderr_read = IntPtr.Zero, stderr_write = IntPtr.Zero;
1048
1049                         try {
1050                                 if (startInfo.RedirectStandardInput) {
1051                                         CreatePipe (out stdin_read, out stdin_write, true);
1052                                 } else {
1053                                         stdin_read = MonoIO.ConsoleInput;
1054                                         stdin_write = IntPtr.Zero;
1055                                 }
1056
1057                                 if (startInfo.RedirectStandardOutput) {
1058                                         CreatePipe (out stdout_read, out stdout_write, false);
1059                                         process.stdout_rd = stdout_read;
1060                                 } else {
1061                                         process.stdout_rd = IntPtr.Zero;
1062                                         stdout_write = MonoIO.ConsoleOutput;
1063                                 }
1064
1065                                 if (startInfo.RedirectStandardError) {
1066                                         CreatePipe (out stderr_read, out stderr_write, false);
1067                                         process.stderr_rd  = stderr_read;
1068                                 } else {
1069                                         process.stderr_rd = IntPtr.Zero;
1070                                         stderr_write = MonoIO.ConsoleError;
1071                                 }
1072
1073                                 FillUserInfo (startInfo, ref proc_info);
1074
1075                                 //
1076                                 // FIXME: For redirected pipes we need to send descriptors of
1077                                 // stdin_write, stdout_read, stderr_read to child process and
1078                                 // close them there (fork makes exact copy of parent's descriptors)
1079                                 //
1080                                 if (!CreateProcess_internal (startInfo, stdin_read, stdout_write, stderr_write, ref proc_info)) {
1081                                         throw new Win32Exception (-proc_info.pid, 
1082                                         "ApplicationName='" + startInfo.FileName +
1083                                         "', CommandLine='" + startInfo.Arguments +
1084                                         "', CurrentDirectory='" + startInfo.WorkingDirectory +
1085                                         "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
1086                                 }
1087                         } catch {
1088                                 if (startInfo.RedirectStandardInput) {
1089                                         if (stdin_read != IntPtr.Zero)
1090                                                 MonoIO.Close (stdin_read, out error);
1091                                         if (stdin_write != IntPtr.Zero)
1092                                                 MonoIO.Close (stdin_write, out error);
1093                                 }
1094
1095                                 if (startInfo.RedirectStandardOutput) {
1096                                         if (stdout_read != IntPtr.Zero)
1097                                                 MonoIO.Close (stdout_read, out error);
1098                                         if (stdout_write != IntPtr.Zero)
1099                                                 MonoIO.Close (stdout_write, out error);
1100                                 }
1101
1102                                 if (startInfo.RedirectStandardError) {
1103                                         if (stderr_read != IntPtr.Zero)
1104                                                 MonoIO.Close (stderr_read, out error);
1105                                         if (stderr_write != IntPtr.Zero)
1106                                                 MonoIO.Close (stderr_write, out error);
1107                                 }
1108
1109                                 throw;
1110                         } finally {
1111                                 if (proc_info.Password != IntPtr.Zero) {
1112                                         Marshal.ZeroFreeBSTR (proc_info.Password);
1113                                         proc_info.Password = IntPtr.Zero;
1114                                 }
1115                         }
1116
1117                         process.process_handle = proc_info.process_handle;
1118                         process.pid = proc_info.pid;
1119                         
1120                         if (startInfo.RedirectStandardInput) {
1121                                 //
1122                                 // FIXME: The descriptor needs to be closed but due to wapi io-layer
1123                                 // not coping with duplicated descriptors any StandardInput write fails
1124                                 //
1125                                 // MonoIO.Close (stdin_read, out error);
1126
1127 #if MOBILE
1128                                 var stdinEncoding = Encoding.Default;
1129 #else
1130                                 var stdinEncoding = Console.InputEncoding;
1131 #endif
1132                                 process.input_stream = new StreamWriter (new FileStream (new SafeFileHandle (stdin_write, false), FileAccess.Write, 8192, false), stdinEncoding) {
1133                                         AutoFlush = true
1134                                 };
1135                         }
1136
1137                         if (startInfo.RedirectStandardOutput) {
1138                                 MonoIO.Close (stdout_write, out error);
1139
1140                                 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1141
1142                                 process.output_stream = new StreamReader (new FileStream (new SafeFileHandle (stdout_read, false), FileAccess.Read, 8192, false), stdoutEncoding, true, 8192);
1143                         }
1144
1145                         if (startInfo.RedirectStandardError) {
1146                                 MonoIO.Close (stderr_write, out error);
1147
1148                                 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1149
1150                                 process.error_stream = new StreamReader (new FileStream (new SafeFileHandle (stderr_read, false), FileAccess.Read, 8192, false), stderrEncoding, true, 8192);
1151                         }
1152
1153                         process.StartExitCallbackIfNeeded ();
1154
1155                         return true;
1156                 }
1157
1158                 // Note that ProcInfo.Password must be freed.
1159                 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1160                 {
1161                         if (startInfo.UserName.Length != 0) {
1162                                 proc_info.UserName = startInfo.UserName;
1163                                 proc_info.Domain = startInfo.Domain;
1164                                 if (startInfo.Password != null)
1165                                         proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1166                                 else
1167                                         proc_info.Password = IntPtr.Zero;
1168                                 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1169                         }
1170                 }
1171
1172                 private static bool Start_common (ProcessStartInfo startInfo,
1173                                                   Process process)
1174                 {
1175                         if (startInfo.FileName.Length == 0)
1176                                 throw new InvalidOperationException("File name has not been set");
1177                         
1178                         if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1179                                 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1180                         if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1181                                 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1182                         
1183                         if (startInfo.UseShellExecute) {
1184                                 if (startInfo.UserName.Length != 0)
1185                                         throw new InvalidOperationException ("UseShellExecute must be false if an explicit UserName is specified when starting a process");
1186                                 return (Start_shell (startInfo, process));
1187                         } else {
1188                                 return (Start_noshell (startInfo, process));
1189                         }
1190                 }
1191                 
1192                 public bool Start ()
1193                 {
1194                         if (process_handle != IntPtr.Zero) {
1195                                 Process_free_internal (process_handle);
1196                                 process_handle = IntPtr.Zero;
1197                         }
1198                         return Start_common(start_info, this);
1199                 }
1200
1201                 public static Process Start (ProcessStartInfo startInfo)
1202                 {
1203                         if (startInfo == null)
1204                                 throw new ArgumentNullException ("startInfo");
1205
1206                         Process process = new Process();
1207                         process.StartInfo = startInfo;
1208                         if (Start_common(startInfo, process) && process.process_handle != IntPtr.Zero)
1209                                 return process;
1210                         return null;
1211                 }
1212
1213                 public static Process Start (string fileName)
1214                 {
1215                         return Start (new ProcessStartInfo (fileName));
1216                 }
1217
1218                 public static Process Start(string fileName, string arguments)
1219                 {
1220                         return Start (new ProcessStartInfo (fileName, arguments));
1221                 }
1222
1223                 public static Process Start(string fileName, string username, SecureString password, string domain) {
1224                         return Start(fileName, null, username, password, domain);
1225                 }
1226
1227                 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1228                         ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1229                         psi.UserName = username;
1230                         psi.Password = password;
1231                         psi.Domain = domain;
1232                         psi.UseShellExecute = false;
1233                         return Start(psi);
1234                 }
1235
1236                 public override string ToString()
1237                 {
1238                         return(base.ToString() + " (" + this.ProcessName + ")");
1239                 }
1240
1241                 /* Waits up to ms milliseconds for process 'handle' to
1242                  * exit.  ms can be <0 to mean wait forever.
1243                  */
1244                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1245                 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1246
1247                 public void WaitForExit ()
1248                 {
1249                         WaitForExit (-1);
1250                 }
1251
1252                 public bool WaitForExit(int milliseconds) {
1253                         int ms = milliseconds;
1254                         if (ms == int.MaxValue)
1255                                 ms = -1;
1256
1257                         if (process_handle == IntPtr.Zero)
1258                                 throw new InvalidOperationException ("No process is associated with this object.");
1259
1260
1261                         DateTime start = DateTime.UtcNow;
1262                         if (async_output != null && !async_output.IsCompleted) {
1263                                 if (false == async_output.WaitHandle.WaitOne (ms, false))
1264                                         return false; // Timed out
1265
1266                                 if (ms >= 0) {
1267                                         DateTime now = DateTime.UtcNow;
1268                                         ms -= (int) (now - start).TotalMilliseconds;
1269                                         if (ms <= 0)
1270                                                 return false;
1271                                         start = now;
1272                                 }
1273                         }
1274
1275                         if (async_error != null && !async_error.IsCompleted) {
1276                                 if (false == async_error.WaitHandle.WaitOne (ms, false))
1277                                         return false; // Timed out
1278
1279                                 if (ms >= 0) {
1280                                         ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1281                                         if (ms <= 0)
1282                                                 return false;
1283                                 }
1284                         }
1285
1286                         bool exited = WaitForExit_internal (process_handle, ms);
1287
1288                         if (exited)
1289                                 OnExited ();
1290
1291                         return exited;
1292                 }
1293
1294                 /* Waits up to ms milliseconds for process 'handle' to 
1295                  * wait for input.  ms can be <0 to mean wait forever.
1296                  */
1297                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1298                 private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
1299
1300                 // The internal call is only implemented properly on Windows.
1301                 [MonoTODO]
1302                 public bool WaitForInputIdle() {
1303                         return WaitForInputIdle (-1);
1304                 }
1305
1306                 // The internal call is only implemented properly on Windows.
1307                 [MonoTODO]
1308                 public bool WaitForInputIdle(int milliseconds) {
1309                         return WaitForInputIdle_internal (process_handle, milliseconds);
1310                 }
1311
1312                 private static bool IsLocalMachine (string machineName)
1313                 {
1314                         if (machineName == "." || machineName.Length == 0)
1315                                 return true;
1316
1317                         return (string.Compare (machineName, Environment.MachineName, true) == 0);
1318                 }
1319
1320                 [Browsable (true)]
1321                 [MonitoringDescription ("Raised when it receives output data")]
1322                 public event DataReceivedEventHandler OutputDataReceived;
1323                 [Browsable (true)]
1324                 [MonitoringDescription ("Raised when it receives error data")]
1325                 public event DataReceivedEventHandler ErrorDataReceived;
1326
1327                 void OnOutputDataReceived (string str)
1328                 {
1329                         if (OutputDataReceived != null)
1330                                 OutputDataReceived (this, new DataReceivedEventArgs (str));
1331                 }
1332
1333                 void OnErrorDataReceived (string str)
1334                 {
1335                         if (ErrorDataReceived != null)
1336                                 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1337                 }
1338
1339                 [Flags]
1340                 enum AsyncModes {
1341                         NoneYet = 0,
1342                         SyncOutput = 1,
1343                         SyncError = 1 << 1,
1344                         AsyncOutput = 1 << 2,
1345                         AsyncError = 1 << 3
1346                 }
1347
1348                 [StructLayout (LayoutKind.Sequential)]
1349                 sealed class ProcessAsyncReader : IThreadPoolWorkItem
1350                 {
1351                         /*
1352                            The following fields match those of SocketAsyncResult.
1353                            This is so that changes needed in the runtime to handle
1354                            asynchronous reads are trivial
1355                            Keep this in sync with SocketAsyncResult in 
1356                            ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
1357                            in metadata/socket-io.h.
1358                         */
1359                         /* DON'T shuffle fields around. DON'T remove fields */
1360                         public object Sock;
1361                         public IntPtr handle;
1362                         public object state;
1363                         public AsyncCallback callback;
1364                         public ManualResetEvent wait_handle;
1365
1366                         public Exception delayedException;
1367
1368                         public object EndPoint;
1369                         byte [] buffer = new byte [4196];
1370                         public int Offset;
1371                         public int Size;
1372                         public int SockFlags;
1373
1374                         public object AcceptSocket;
1375                         public object[] Addresses;
1376                         public int port;
1377                         public object Buffers;          // Reserve this slot in older profiles
1378                         public bool ReuseSocket;        // Disconnect
1379                         public object acc_socket;
1380                         public int total;
1381                         public bool completed_sync;
1382                         bool completed;
1383                         bool err_out; // true -> stdout, false -> stderr
1384                         internal int error;
1385                         public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1386                         public AsyncResult async_result;
1387                         public int EndCalled;
1388
1389                         // These fields are not in SocketAsyncResult
1390                         Process process;
1391                         Stream stream;
1392                         StringBuilder sb = new StringBuilder ();
1393                         public AsyncReadHandler ReadHandler;
1394
1395                         public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1396                         {
1397                                 this.process = process;
1398                                 this.handle = handle;
1399                                 stream = new FileStream (handle, FileAccess.Read, false);
1400                                 this.ReadHandler = new AsyncReadHandler (AddInput);
1401                                 this.err_out = err_out;
1402                         }
1403
1404                         public void AddInput ()
1405                         {
1406                                 lock (this) {
1407                                         int nread = stream.Read (buffer, 0, buffer.Length);
1408                                         if (nread == 0) {
1409                                                 completed = true;
1410                                                 if (wait_handle != null)
1411                                                         wait_handle.Set ();
1412                                                 FlushLast ();
1413                                                 return;
1414                                         }
1415
1416                                         try {
1417                                                 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1418                                         } catch {
1419                                                 // Just in case the encoding fails...
1420                                                 for (int i = 0; i < nread; i++) {
1421                                                         sb.Append ((char) buffer [i]);
1422                                                 }
1423                                         }
1424
1425                                         Flush (false);
1426                                         ReadHandler.BeginInvoke (null, this);
1427                                 }
1428                         }
1429
1430                         void FlushLast ()
1431                         {
1432                                 Flush (true);
1433                                 if (err_out) {
1434                                         process.OnOutputDataReceived (null);
1435                                 } else {
1436                                         process.OnErrorDataReceived (null);
1437                                 }
1438                         }
1439                         
1440                         void Flush (bool last)
1441                         {
1442                                 if (sb.Length == 0 ||
1443                                     (err_out && process.output_canceled) ||
1444                                     (!err_out && process.error_canceled))
1445                                         return;
1446
1447                                 string total = sb.ToString ();
1448                                 sb.Length = 0;
1449                                 string [] strs = total.Split ('\n');
1450                                 int len = strs.Length;
1451                                 if (len == 0)
1452                                         return;
1453
1454                                 for (int i = 0; i < len - 1; i++) {
1455                                         if (err_out)
1456                                                 process.OnOutputDataReceived (strs [i]);
1457                                         else
1458                                                 process.OnErrorDataReceived (strs [i]);
1459                                 }
1460
1461                                 string end = strs [len - 1];
1462                                 if (last || (len == 1 && end == "")) {
1463                                         if (err_out) {
1464                                                 process.OnOutputDataReceived (end);
1465                                         } else {
1466                                                 process.OnErrorDataReceived (end);
1467                                         }
1468                                 } else {
1469                                         sb.Append (end);
1470                                 }
1471                         }
1472
1473                         public bool IsCompleted {
1474                                 get { return completed; }
1475                         }
1476
1477                         public WaitHandle WaitHandle {
1478                                 get {
1479                                         lock (this) {
1480                                                 if (wait_handle == null)
1481                                                         wait_handle = new ManualResetEvent (completed);
1482                                                 return wait_handle;
1483                                         }
1484                                 }
1485                         }
1486
1487                         public void Close () {
1488                                 RemoveFromIOThreadPool (handle);
1489                                 stream.Close ();
1490                         }
1491
1492                         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1493                         extern static void RemoveFromIOThreadPool (IntPtr handle);
1494
1495                         void IThreadPoolWorkItem.ExecuteWorkItem()
1496                         {
1497                                 async_result.Invoke ();
1498                         }
1499
1500                         void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae)
1501                         {
1502                         }
1503                 }
1504
1505                 AsyncModes async_mode;
1506                 bool output_canceled;
1507                 bool error_canceled;
1508                 ProcessAsyncReader async_output;
1509                 ProcessAsyncReader async_error;
1510                 delegate void AsyncReadHandler ();
1511
1512                 [ComVisibleAttribute(false)] 
1513                 public void BeginOutputReadLine ()
1514                 {
1515                         if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1516                                 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1517
1518                         if ((async_mode & AsyncModes.SyncOutput) != 0)
1519                                 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1520
1521                         async_mode |= AsyncModes.AsyncOutput;
1522                         output_canceled = false;
1523                         if (async_output == null) {
1524                                 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1525                                 async_output.ReadHandler.BeginInvoke (null, async_output);
1526                         }
1527                 }
1528
1529                 [ComVisibleAttribute(false)] 
1530                 public void CancelOutputRead ()
1531                 {
1532                         if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1533                                 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1534
1535                         if ((async_mode & AsyncModes.SyncOutput) != 0)
1536                                 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1537
1538                         if (async_output == null)
1539                                 throw new InvalidOperationException ("No async operation in progress.");
1540
1541                         output_canceled = true;
1542                 }
1543
1544                 [ComVisibleAttribute(false)] 
1545                 public void BeginErrorReadLine ()
1546                 {
1547                         if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1548                                 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1549
1550                         if ((async_mode & AsyncModes.SyncError) != 0)
1551                                 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1552
1553                         async_mode |= AsyncModes.AsyncError;
1554                         error_canceled = false;
1555                         if (async_error == null) {
1556                                 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1557                                 async_error.ReadHandler.BeginInvoke (null, async_error);
1558                         }
1559                 }
1560
1561                 [ComVisibleAttribute(false)] 
1562                 public void CancelErrorRead ()
1563                 {
1564                         if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1565                                 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1566
1567                         if ((async_mode & AsyncModes.SyncOutput) != 0)
1568                                 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1569
1570                         if (async_error == null)
1571                                 throw new InvalidOperationException ("No async operation in progress.");
1572
1573                         error_canceled = true;
1574                 }
1575
1576                 [Category ("Behavior")]
1577                 [MonitoringDescription ("Raised when this process exits.")]
1578                 public event EventHandler Exited {
1579                         add {
1580                                 if (process_handle != IntPtr.Zero && HasExited) {
1581                                         value.BeginInvoke (null, null, null, null);
1582                                 } else {
1583                                         exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1584                                         if (exited_event != null)
1585                                                 StartExitCallbackIfNeeded ();
1586                                 }
1587                         }
1588                         remove {
1589                                 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1590                         }
1591                 }
1592
1593                 // Closes the system process handle
1594                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1595                 private extern void Process_free_internal(IntPtr handle);
1596                 
1597                 private bool disposed = false;
1598                 
1599                 protected override void Dispose(bool disposing) {
1600                         // Check to see if Dispose has already been called.
1601                         if(this.disposed == false) {
1602                                 this.disposed=true;
1603                                 // If this is a call to Dispose,
1604                                 // dispose all managed resources.
1605                                 if(disposing) {
1606                                         // Do stuff here
1607                                         lock (thisLock) {
1608                                                 /* These have open FileStreams on the pipes we are about to close */
1609                                                 if (async_output != null)
1610                                                         async_output.Close ();
1611                                                 if (async_error != null)
1612                                                         async_error.Close ();
1613
1614                                                 if (input_stream != null) {
1615                                                         if (!input_stream_exposed)
1616                                                                 input_stream.Close ();
1617                                                         input_stream = null;
1618                                                 }
1619                                                 if (output_stream != null) {
1620                                                         if (!output_stream_exposed)
1621                                                                 output_stream.Close ();
1622                                                         output_stream = null;
1623                                                 }
1624                                                 if (error_stream != null) {
1625                                                         if (!error_stream_exposed)
1626                                                                 error_stream.Close ();
1627                                                         error_stream = null;
1628                                                 }
1629                                         }
1630                                 }
1631                                 
1632                                 // Release unmanaged resources
1633
1634                                 lock (thisLock) {
1635                                         if(process_handle!=IntPtr.Zero) {
1636                                                 Process_free_internal(process_handle);
1637                                                 process_handle=IntPtr.Zero;
1638                                         }
1639                                 }
1640                         }
1641                         base.Dispose (disposing);
1642                 }
1643
1644                 ~Process ()
1645                 {
1646                         Dispose (false);
1647                 }
1648
1649                 static void CBOnExit (object state, bool unused)
1650                 {
1651                         Process p = (Process) state;
1652
1653                         if (!p.IsExitCallbackPending ())
1654                                 return;
1655
1656                         if (!p.HasExited) {
1657                                 p.UnregisterExitCallback ();
1658                                 p.StartExitCallbackIfNeeded ();
1659                                 return;
1660                         }
1661
1662                         p.OnExited ();
1663                 }
1664
1665                 int on_exited_called = 0;
1666
1667                 protected void OnExited() 
1668                 {
1669                         if (exited_event == null)
1670                                 return;
1671
1672                         if (on_exited_called != 0 || Interlocked.CompareExchange (ref on_exited_called, 1, 0) != 0)
1673                                 return;
1674
1675                         UnregisterExitCallback ();
1676
1677                         if (synchronizingObject == null) {
1678                                 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1679                                         try {
1680                                                 d (this, EventArgs.Empty);
1681                                         } catch {}
1682                                 }
1683                                 return;
1684                         }
1685                         
1686                         object [] args = new object [] {this, EventArgs.Empty};
1687                         synchronizingObject.BeginInvoke (exited_event, args);
1688                 }
1689
1690                 static bool IsWindows
1691                 {
1692                         get
1693                         {
1694                                 PlatformID platform = Environment.OSVersion.Platform;
1695                                 if (platform == PlatformID.Win32S ||
1696                                         platform == PlatformID.Win32Windows ||
1697                                         platform == PlatformID.Win32NT ||
1698                                         platform == PlatformID.WinCE) {
1699                                         return true;
1700                                 }
1701                                 return false;
1702                         }
1703                 }
1704
1705                 class ProcessWaitHandle : WaitHandle
1706                 {
1707                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
1708                         private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1709                         
1710                         public ProcessWaitHandle (IntPtr handle)
1711                         {
1712                                 // Need to keep a reference to this handle,
1713                                 // in case the Process object is collected
1714                                 Handle = ProcessHandle_duplicate (handle);
1715
1716                                 // When the wait handle is disposed, the duplicated handle will be
1717                                 // closed, so no need to override dispose (bug #464628).
1718                         }
1719                 }
1720         }
1721 }
1722