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