Merge branch 'cecil-light'
[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                         }
1131
1132                         process.process_handle = proc_info.process_handle;
1133                         process.pid = proc_info.pid;
1134                         
1135                         if (startInfo.RedirectStandardInput == true) {
1136                                 MonoIO.Close (stdin_rd, out error);
1137                                 process.input_stream = new StreamWriter (new MonoSyncFileStream (stdin_wr, FileAccess.Write, true, 8192), Console.Out.Encoding);
1138                                 process.input_stream.AutoFlush = true;
1139                         }
1140
1141 #if NET_2_0
1142                         Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1143                         Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1144 #else
1145                         Encoding stdoutEncoding = Console.Out.Encoding;
1146                         Encoding stderrEncoding = stdoutEncoding;
1147 #endif
1148
1149                         if (startInfo.RedirectStandardOutput == true) {
1150                                 MonoIO.Close (stdout_wr, out error);
1151                                 process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding, true, 8192);
1152                         }
1153
1154                         if (startInfo.RedirectStandardError == true) {
1155                                 MonoIO.Close (stderr_wr, out error);
1156                                 process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding, true, 8192);
1157                         }
1158
1159                         process.StartExitCallbackIfNeeded ();
1160
1161                         return(ret);
1162                 }
1163
1164                 // Note that ProcInfo.Password must be freed.
1165                 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1166                 {
1167 #if NET_2_0
1168                         if (startInfo.UserName != null) {
1169                                 proc_info.UserName = startInfo.UserName;
1170                                 proc_info.Domain = startInfo.Domain;
1171                                 if (startInfo.Password != null)
1172                                         proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1173                                 else
1174                                         proc_info.Password = IntPtr.Zero;
1175                                 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1176                         }
1177 #endif
1178                 }
1179
1180                 private static bool Start_common (ProcessStartInfo startInfo,
1181                                                   Process process)
1182                 {
1183                         if (startInfo.FileName == null || startInfo.FileName.Length == 0)
1184                                 throw new InvalidOperationException("File name has not been set");
1185                         
1186 #if NET_2_0
1187                         if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1188                                 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1189                         if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1190                                 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1191 #endif
1192                         
1193                         if (startInfo.UseShellExecute) {
1194 #if NET_2_0
1195                                 if (!String.IsNullOrEmpty (startInfo.UserName))
1196                                         throw new InvalidOperationException ("UserShellExecute must be false if an explicit UserName is specified when starting a process");
1197 #endif
1198                                 return (Start_shell (startInfo, process));
1199                         } else {
1200                                 return (Start_noshell (startInfo, process));
1201                         }
1202                 }
1203                 
1204                 public bool Start ()
1205                 {
1206                         if (process_handle != IntPtr.Zero) {
1207                                 Process_free_internal (process_handle);
1208                                 process_handle = IntPtr.Zero;
1209                         }
1210                         return Start_common(start_info, this);
1211                 }
1212
1213                 public static Process Start (ProcessStartInfo startInfo)
1214                 {
1215                         if (startInfo == null)
1216                                 throw new ArgumentNullException ("startInfo");
1217
1218                         Process process=new Process();
1219                         process.StartInfo = startInfo;
1220                         if (Start_common(startInfo, process))
1221                                 return process;
1222                         return null;
1223                 }
1224
1225                 public static Process Start (string fileName)
1226                 {
1227                         return Start (new ProcessStartInfo (fileName));
1228                 }
1229
1230                 public static Process Start(string fileName, string arguments)
1231                 {
1232                         return Start (new ProcessStartInfo (fileName, arguments));
1233                 }
1234
1235 #if NET_2_0
1236                 public static Process Start(string fileName, string username, SecureString password, string domain) {
1237                         return Start(fileName, null, username, password, domain);
1238                 }
1239
1240                 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1241                         ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1242                         psi.UserName = username;
1243                         psi.Password = password;
1244                         psi.Domain = domain;
1245                         psi.UseShellExecute = false;
1246                         return Start(psi);
1247                 }
1248 #endif
1249
1250                 public override string ToString()
1251                 {
1252                         return(base.ToString() + " (" + this.ProcessName + ")");
1253                 }
1254
1255                 /* Waits up to ms milliseconds for process 'handle' to
1256                  * exit.  ms can be <0 to mean wait forever.
1257                  */
1258                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1259                 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1260
1261                 public void WaitForExit ()
1262                 {
1263                         WaitForExit (-1);
1264                 }
1265
1266                 public bool WaitForExit(int milliseconds) {
1267                         int ms = milliseconds;
1268                         if (ms == int.MaxValue)
1269                                 ms = -1;
1270
1271 #if NET_2_0
1272                         DateTime start = DateTime.UtcNow;
1273                         if (async_output != null && !async_output.IsCompleted) {
1274                                 if (false == async_output.WaitHandle.WaitOne (ms, false))
1275                                         return false; // Timed out
1276
1277                                 if (ms >= 0) {
1278                                         DateTime now = DateTime.UtcNow;
1279                                         ms -= (int) (now - start).TotalMilliseconds;
1280                                         if (ms <= 0)
1281                                                 return false;
1282                                         start = now;
1283                                 }
1284                         }
1285
1286                         if (async_error != null && !async_error.IsCompleted) {
1287                                 if (false == async_error.WaitHandle.WaitOne (ms, false))
1288                                         return false; // Timed out
1289
1290                                 if (ms >= 0) {
1291                                         ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1292                                         if (ms <= 0)
1293                                                 return false;
1294                                 }
1295                         }
1296 #endif
1297                         return WaitForExit_internal (process_handle, ms);
1298                 }
1299
1300                 /* Waits up to ms milliseconds for process 'handle' to 
1301                  * wait for input.  ms can be <0 to mean wait forever.
1302                  */
1303                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1304                 private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
1305
1306                 // The internal call is only implemented properly on Windows.
1307                 [MonoTODO]
1308                 public bool WaitForInputIdle() {
1309                         return WaitForInputIdle (-1);
1310                 }
1311
1312                 // The internal call is only implemented properly on Windows.
1313                 [MonoTODO]
1314                 public bool WaitForInputIdle(int milliseconds) {
1315                         return WaitForInputIdle_internal (process_handle, milliseconds);
1316                 }
1317
1318                 private static bool IsLocalMachine (string machineName)
1319                 {
1320                         if (machineName == "." || machineName.Length == 0)
1321                                 return true;
1322
1323                         return (string.Compare (machineName, Environment.MachineName, true) == 0);
1324                 }
1325
1326 #if NET_2_0
1327                 [Browsable (true)]
1328                 [MonitoringDescription ("Raised when it receives output data")]
1329                 public event DataReceivedEventHandler OutputDataReceived;
1330                 [Browsable (true)]
1331                 [MonitoringDescription ("Raised when it receives error data")]
1332                 public event DataReceivedEventHandler ErrorDataReceived;
1333
1334                 void OnOutputDataReceived (string str)
1335                 {
1336                         if (OutputDataReceived != null)
1337                                 OutputDataReceived (this, new DataReceivedEventArgs (str));
1338                 }
1339
1340                 void OnErrorDataReceived (string str)
1341                 {
1342                         if (ErrorDataReceived != null)
1343                                 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1344                 }
1345
1346                 [Flags]
1347                 enum AsyncModes {
1348                         NoneYet = 0,
1349                         SyncOutput = 1,
1350                         SyncError = 1 << 1,
1351                         AsyncOutput = 1 << 2,
1352                         AsyncError = 1 << 3
1353                 }
1354
1355                 [StructLayout (LayoutKind.Sequential)]
1356                 sealed class ProcessAsyncReader
1357                 {
1358                         /*
1359                            The following fields match those of SocketAsyncResult.
1360                            This is so that changes needed in the runtime to handle
1361                            asynchronous reads are trivial
1362                            Keep this in sync with SocketAsyncResult in 
1363                            ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
1364                            in metadata/socket-io.h.
1365                         */
1366                         /* DON'T shuffle fields around. DON'T remove fields */
1367                         public object Sock;
1368                         public IntPtr handle;
1369                         public object state;
1370                         public AsyncCallback callback;
1371                         public ManualResetEvent wait_handle;
1372
1373                         public Exception delayedException;
1374
1375                         public object EndPoint;
1376                         byte [] buffer = new byte [4196];
1377                         public int Offset;
1378                         public int Size;
1379                         public int SockFlags;
1380
1381                         public object AcceptSocket;
1382                         public object[] Addresses;
1383                         public int port;
1384                         public object Buffers;          // Reserve this slot in older profiles
1385                         public bool ReuseSocket;        // Disconnect
1386                         public object acc_socket;
1387                         public int total;
1388                         public bool completed_sync;
1389                         bool completed;
1390                         bool err_out; // true -> stdout, false -> stderr
1391                         internal int error;
1392                         public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1393                         public object ares;
1394                         public int EndCalled;
1395
1396                         // These fields are not in SocketAsyncResult
1397                         Process process;
1398                         Stream stream;
1399                         StringBuilder sb = new StringBuilder ();
1400                         public AsyncReadHandler ReadHandler;
1401
1402                         public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1403                         {
1404                                 this.process = process;
1405                                 this.handle = handle;
1406                                 stream = new FileStream (handle, FileAccess.Read, false);
1407                                 this.ReadHandler = new AsyncReadHandler (AddInput);
1408                                 this.err_out = err_out;
1409                         }
1410
1411                         public void AddInput ()
1412                         {
1413                                 lock (this) {
1414                                         int nread = stream.Read (buffer, 0, buffer.Length);
1415                                         if (nread == 0) {
1416                                                 completed = true;
1417                                                 if (wait_handle != null)
1418                                                         wait_handle.Set ();
1419                                                 FlushLast ();
1420                                                 return;
1421                                         }
1422
1423                                         try {
1424                                                 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1425                                         } catch {
1426                                                 // Just in case the encoding fails...
1427                                                 for (int i = 0; i < nread; i++) {
1428                                                         sb.Append ((char) buffer [i]);
1429                                                 }
1430                                         }
1431
1432                                         Flush (false);
1433                                         ReadHandler.BeginInvoke (null, this);
1434                                 }
1435                         }
1436
1437                         void FlushLast ()
1438                         {
1439                                 Flush (true);
1440                                 if (err_out) {
1441                                         process.OnOutputDataReceived (null);
1442                                 } else {
1443                                         process.OnErrorDataReceived (null);
1444                                 }
1445                         }
1446                         
1447                         void Flush (bool last)
1448                         {
1449                                 if (sb.Length == 0 ||
1450                                     (err_out && process.output_canceled) ||
1451                                     (!err_out && process.error_canceled))
1452                                         return;
1453
1454                                 string total = sb.ToString ();
1455                                 sb.Length = 0;
1456                                 string [] strs = total.Split ('\n');
1457                                 int len = strs.Length;
1458                                 if (len == 0)
1459                                         return;
1460
1461                                 for (int i = 0; i < len - 1; i++) {
1462                                         if (err_out)
1463                                                 process.OnOutputDataReceived (strs [i]);
1464                                         else
1465                                                 process.OnErrorDataReceived (strs [i]);
1466                                 }
1467
1468                                 string end = strs [len - 1];
1469                                 if (last || (len == 1 && end == "")) {
1470                                         if (err_out) {
1471                                                 process.OnOutputDataReceived (end);
1472                                         } else {
1473                                                 process.OnErrorDataReceived (end);
1474                                         }
1475                                 } else {
1476                                         sb.Append (end);
1477                                 }
1478                         }
1479
1480                         public bool IsCompleted {
1481                                 get { return completed; }
1482                         }
1483
1484                         public WaitHandle WaitHandle {
1485                                 get {
1486                                         lock (this) {
1487                                                 if (wait_handle == null)
1488                                                         wait_handle = new ManualResetEvent (completed);
1489                                                 return wait_handle;
1490                                         }
1491                                 }
1492                         }
1493
1494                         public void Close () {
1495                                 stream.Close ();
1496                         }
1497                 }
1498
1499                 AsyncModes async_mode;
1500                 bool output_canceled;
1501                 bool error_canceled;
1502                 ProcessAsyncReader async_output;
1503                 ProcessAsyncReader async_error;
1504                 delegate void AsyncReadHandler ();
1505
1506                 [ComVisibleAttribute(false)] 
1507                 public void BeginOutputReadLine ()
1508                 {
1509                         if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1510                                 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1511
1512                         if ((async_mode & AsyncModes.SyncOutput) != 0)
1513                                 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1514
1515                         async_mode |= AsyncModes.AsyncOutput;
1516                         output_canceled = false;
1517                         if (async_output == null) {
1518                                 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1519                                 async_output.ReadHandler.BeginInvoke (null, async_output);
1520                         }
1521                 }
1522
1523                 [ComVisibleAttribute(false)] 
1524                 public void CancelOutputRead ()
1525                 {
1526                         if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1527                                 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1528
1529                         if ((async_mode & AsyncModes.SyncOutput) != 0)
1530                                 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1531
1532                         if (async_output == null)
1533                                 throw new InvalidOperationException ("No async operation in progress.");
1534
1535                         output_canceled = true;
1536                 }
1537
1538                 [ComVisibleAttribute(false)] 
1539                 public void BeginErrorReadLine ()
1540                 {
1541                         if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1542                                 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1543
1544                         if ((async_mode & AsyncModes.SyncError) != 0)
1545                                 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1546
1547                         async_mode |= AsyncModes.AsyncError;
1548                         error_canceled = false;
1549                         if (async_error == null) {
1550                                 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1551                                 async_error.ReadHandler.BeginInvoke (null, async_error);
1552                         }
1553                 }
1554
1555                 [ComVisibleAttribute(false)] 
1556                 public void CancelErrorRead ()
1557                 {
1558                         if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1559                                 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1560
1561                         if ((async_mode & AsyncModes.SyncOutput) != 0)
1562                                 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1563
1564                         if (async_error == null)
1565                                 throw new InvalidOperationException ("No async operation in progress.");
1566
1567                         error_canceled = true;
1568                 }
1569 #endif
1570
1571                 [Category ("Behavior")]
1572                 [MonitoringDescription ("Raised when this process exits.")]
1573                 public event EventHandler Exited {
1574                         add {
1575                                 if (process_handle != IntPtr.Zero && HasExited) {
1576                                         value.BeginInvoke (null, null, null, null);
1577                                 } else {
1578                                         exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1579                                         if (exited_event != null)
1580                                                 StartExitCallbackIfNeeded ();
1581                                 }
1582                         }
1583                         remove {
1584                                 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1585                         }
1586                 }
1587
1588                 // Closes the system process handle
1589                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1590                 private extern void Process_free_internal(IntPtr handle);
1591                 
1592                 private bool disposed = false;
1593                 
1594                 protected override void Dispose(bool disposing) {
1595                         // Check to see if Dispose has already been called.
1596                         if(this.disposed == false) {
1597                                 this.disposed=true;
1598                                 // If this is a call to Dispose,
1599                                 // dispose all managed resources.
1600                                 if(disposing) {
1601                                         // Do stuff here
1602                                         lock (this) {
1603                                                 /* These have open FileStreams on the pipes we are about to close */
1604                                                 if (async_output != null)
1605                                                         async_output.Close ();
1606                                                 if (async_error != null)
1607                                                         async_error.Close ();
1608                                         }
1609                                 }
1610                                 
1611                                 // Release unmanaged resources
1612
1613                                 lock(this) {
1614                                         if(process_handle!=IntPtr.Zero) {
1615                                                 Process_free_internal(process_handle);
1616                                                 process_handle=IntPtr.Zero;
1617                                         }
1618
1619                                         if (input_stream != null) {
1620                                                 input_stream.Close();
1621                                                 input_stream = null;
1622                                         }
1623
1624                                         if (output_stream != null) {
1625                                                 output_stream.Close();
1626                                                 output_stream = null;
1627                                         }
1628
1629                                         if (error_stream != null) {
1630                                                 error_stream.Close();
1631                                                 error_stream = null;
1632                                         }
1633                                 }
1634                         }
1635                         base.Dispose (disposing);
1636                 }
1637
1638                 ~Process ()
1639                 {
1640                         Dispose (false);
1641                 }
1642
1643                 static void CBOnExit (object state, bool unused)
1644                 {
1645                         Process p = (Process) state;
1646                         p.already_waiting = false;
1647                         p.OnExited ();
1648                 }
1649
1650                 protected void OnExited() 
1651                 {
1652                         if (exited_event == null)
1653                                 return;
1654
1655                         if (synchronizingObject == null) {
1656                                 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1657                                         try {
1658                                                 d (this, EventArgs.Empty);
1659                                         } catch {}
1660                                 }
1661                                 return;
1662                         }
1663                         
1664                         object [] args = new object [] {this, EventArgs.Empty};
1665                         synchronizingObject.BeginInvoke (exited_event, args);
1666                 }
1667
1668                 static bool IsWindows
1669                 {
1670                         get
1671                         {
1672                                 PlatformID platform = Environment.OSVersion.Platform;
1673                                 if (platform == PlatformID.Win32S ||
1674                                         platform == PlatformID.Win32Windows ||
1675                                         platform == PlatformID.Win32NT ||
1676                                         platform == PlatformID.WinCE) {
1677                                         return true;
1678                                 }
1679                                 return false;
1680                         }
1681                 }
1682
1683                 class ProcessWaitHandle : WaitHandle
1684                 {
1685                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
1686                         private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1687                         
1688                         public ProcessWaitHandle (IntPtr handle)
1689                         {
1690                                 // Need to keep a reference to this handle,
1691                                 // in case the Process object is collected
1692                                 Handle = ProcessHandle_duplicate (handle);
1693
1694                                 // When the wait handle is disposed, the duplicated handle will be
1695                                 // closed, so no need to override dispose (bug #464628).
1696                         }
1697                 }
1698         }
1699 }
1700