2009-10-12 Zoltan Varga <vargaz@gmail.com>
[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                         ArrayList proclist = new ArrayList ();
860
861                         if (pids == null)
862                                 return new Process [0];
863                         
864                         for (int i = 0; i < pids.Length; i++) {
865                                 try {
866                                         proclist.Add (GetProcessById (pids [i]));
867                                 } catch (SystemException) {
868                                         /* The process might exit
869                                          * between
870                                          * GetProcesses_internal and
871                                          * GetProcessById
872                                          */
873                                 }
874                         }
875
876                         return ((Process []) proclist.ToArray (typeof (Process)));
877                 }
878
879                 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
880                 public static Process[] GetProcesses(string machineName) {
881                         if (machineName == null)
882                                 throw new ArgumentNullException ("machineName");
883
884                         if (!IsLocalMachine (machineName))
885                                 throw new NotImplementedException ();
886
887                         return GetProcesses ();
888                 }
889
890                 public static Process[] GetProcessesByName(string processName)
891                 {
892                         Process [] procs = GetProcesses();
893                         ArrayList proclist = new ArrayList();
894                         
895                         for (int i = 0; i < procs.Length; i++) {
896                                 /* Ignore case */
897                                 if (String.Compare (processName,
898                                                     procs [i].ProcessName,
899                                                     true) == 0) {
900                                         proclist.Add (procs [i]);
901                                 }
902                         }
903
904                         return ((Process[]) proclist.ToArray (typeof(Process)));
905                 }
906
907                 [MonoTODO]
908                 public static Process[] GetProcessesByName(string processName, string machineName) {
909                         throw new NotImplementedException();
910                 }
911
912                 public void Kill ()
913                 {
914                         Close (1);
915                 }
916
917                 [MonoTODO]
918                 public static void LeaveDebugMode() {
919                 }
920
921                 public void Refresh ()
922                 {
923                         // FIXME: should refresh any cached data we might have about
924                         // the process (currently we have none).
925                 }
926
927                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
928                 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
929                                                                    ref ProcInfo proc_info);
930
931                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
932                 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
933                                                                   IntPtr stdin,
934                                                                   IntPtr stdout,
935                                                                   IntPtr stderr,
936                                                                   ref ProcInfo proc_info);
937
938                 private static bool Start_shell (ProcessStartInfo startInfo,
939                                                  Process process)
940                 {
941                         ProcInfo proc_info=new ProcInfo();
942                         bool ret;
943
944                         if (startInfo.RedirectStandardInput ||
945                             startInfo.RedirectStandardOutput ||
946                             startInfo.RedirectStandardError) {
947                                 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
948                         }
949
950                         if (startInfo.HaveEnvVars)
951                                 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
952
953                         FillUserInfo (startInfo, ref proc_info);
954                         try {
955                                 ret = ShellExecuteEx_internal (startInfo,
956                                                                ref proc_info);
957                         } finally {
958                                 if (proc_info.Password != IntPtr.Zero)
959                                         Marshal.FreeBSTR (proc_info.Password);
960                                 proc_info.Password = IntPtr.Zero;
961                         }
962                         if (!ret) {
963                                 throw new Win32Exception (-proc_info.pid);
964                         }
965
966                         process.process_handle = proc_info.process_handle;
967                         process.pid = proc_info.pid;
968
969                         process.StartExitCallbackIfNeeded ();
970
971                         return(ret);
972                 }
973
974                 private static bool Start_noshell (ProcessStartInfo startInfo,
975                                                    Process process)
976                 {
977                         ProcInfo proc_info=new ProcInfo();
978                         IntPtr stdin_rd = IntPtr.Zero, stdin_wr = IntPtr.Zero;
979                         IntPtr stdout_wr;
980                         IntPtr stderr_wr;
981                         bool ret;
982                         MonoIOError error;
983
984                         if (startInfo.HaveEnvVars) {
985                                 string [] strs = new string [startInfo.EnvironmentVariables.Count];
986                                 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
987                                 proc_info.envKeys = strs;
988
989                                 strs = new string [startInfo.EnvironmentVariables.Count];
990                                 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
991                                 proc_info.envValues = strs;
992                         }
993
994                         if (startInfo.RedirectStandardInput == true) {
995                                 if (IsWindows) {
996                                         int DUPLICATE_SAME_ACCESS = 0x00000002;
997                                         IntPtr stdin_wr_tmp;
998
999                                         ret = MonoIO.CreatePipe (out stdin_rd,
1000                                                                          out stdin_wr_tmp);
1001                                         if (ret) {
1002                                                 ret = MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, stdin_wr_tmp,
1003                                                 Process.GetCurrentProcess ().Handle, out stdin_wr, 0, 0, DUPLICATE_SAME_ACCESS);
1004                                                 MonoIO.Close (stdin_wr_tmp, out error);
1005                                         }
1006                                 }
1007                                 else
1008                                 {
1009                                         ret = MonoIO.CreatePipe (out stdin_rd,
1010                                                                          out stdin_wr);
1011                                 }
1012                                 if (ret == false) {
1013                                         throw new IOException ("Error creating standard input pipe");
1014                                 }
1015                         } else {
1016                                 stdin_rd = MonoIO.ConsoleInput;
1017                                 /* This is required to stop the
1018                                  * &$*£ing stupid compiler moaning
1019                                  * that stdin_wr is unassigned, below.
1020                                  */
1021                                 stdin_wr = (IntPtr)0;
1022                         }
1023
1024                         if (startInfo.RedirectStandardOutput == true) {
1025                                 IntPtr out_rd = IntPtr.Zero;
1026                                 if (IsWindows) {
1027                                         IntPtr out_rd_tmp;
1028                                         int DUPLICATE_SAME_ACCESS = 0x00000002;
1029
1030                                         ret = MonoIO.CreatePipe (out out_rd_tmp,
1031                                                                          out stdout_wr);
1032                                         if (ret) {
1033                                                 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, out_rd_tmp,
1034                                                 Process.GetCurrentProcess ().Handle, out out_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1035                                                 MonoIO.Close (out_rd_tmp, out error);
1036                                         }
1037                                 }
1038                                 else {
1039                                         ret = MonoIO.CreatePipe (out out_rd,
1040                                                                          out stdout_wr);
1041                                 }
1042
1043                                 process.stdout_rd = out_rd;
1044                                 if (ret == false) {
1045                                         if (startInfo.RedirectStandardInput == true) {
1046                                                 MonoIO.Close (stdin_rd, out error);
1047                                                 MonoIO.Close (stdin_wr, out error);
1048                                         }
1049
1050                                         throw new IOException ("Error creating standard output pipe");
1051                                 }
1052                         } else {
1053                                 process.stdout_rd = (IntPtr)0;
1054                                 stdout_wr = MonoIO.ConsoleOutput;
1055                         }
1056
1057                         if (startInfo.RedirectStandardError == true) {
1058                                 IntPtr err_rd = IntPtr.Zero;
1059                                 if (IsWindows) {
1060                                         IntPtr err_rd_tmp;
1061                                         int DUPLICATE_SAME_ACCESS = 0x00000002;
1062
1063                                         ret = MonoIO.CreatePipe (out err_rd_tmp,
1064                                                                          out stderr_wr);
1065                                         if (ret) {
1066                                                 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, err_rd_tmp,
1067                                                 Process.GetCurrentProcess ().Handle, out err_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1068                                                 MonoIO.Close (err_rd_tmp, out error);
1069                                         }
1070                                 }
1071                                 else {
1072                                         ret = MonoIO.CreatePipe (out err_rd,
1073                                                                          out stderr_wr);
1074                                 }
1075
1076                                 process.stderr_rd = err_rd;
1077                                 if (ret == false) {
1078                                         if (startInfo.RedirectStandardInput == true) {
1079                                                 MonoIO.Close (stdin_rd, out error);
1080                                                 MonoIO.Close (stdin_wr, out error);
1081                                         }
1082                                         if (startInfo.RedirectStandardOutput == true) {
1083                                                 MonoIO.Close (process.stdout_rd, out error);
1084                                                 MonoIO.Close (stdout_wr, out error);
1085                                         }
1086                                         
1087                                         throw new IOException ("Error creating standard error pipe");
1088                                 }
1089                         } else {
1090                                 process.stderr_rd = (IntPtr)0;
1091                                 stderr_wr = MonoIO.ConsoleError;
1092                         }
1093
1094                         FillUserInfo (startInfo, ref proc_info);
1095                         try {
1096                                 ret = CreateProcess_internal (startInfo,
1097                                                               stdin_rd, stdout_wr, stderr_wr,
1098                                                               ref proc_info);
1099                         } finally {
1100                                 if (proc_info.Password != IntPtr.Zero)
1101                                         Marshal.FreeBSTR (proc_info.Password);
1102                                 proc_info.Password = IntPtr.Zero;
1103                         }
1104                         if (!ret) {
1105                                 if (startInfo.RedirectStandardInput == true) {
1106                                         MonoIO.Close (stdin_rd, out error);
1107                                         MonoIO.Close (stdin_wr, out error);
1108                                 }
1109
1110                                 if (startInfo.RedirectStandardOutput == true) {
1111                                         MonoIO.Close (process.stdout_rd, out error);
1112                                         MonoIO.Close (stdout_wr, out error);
1113                                 }
1114
1115                                 if (startInfo.RedirectStandardError == true) {
1116                                         MonoIO.Close (process.stderr_rd, out error);
1117                                         MonoIO.Close (stderr_wr, out error);
1118                                 }
1119
1120                                 throw new Win32Exception (-proc_info.pid,
1121                                         "ApplicationName='" + startInfo.FileName +
1122                                         "', CommandLine='" + startInfo.Arguments +
1123                                         "', CurrentDirectory='" + startInfo.WorkingDirectory + "'");
1124                         }
1125
1126                         process.process_handle = proc_info.process_handle;
1127                         process.pid = proc_info.pid;
1128                         
1129                         if (startInfo.RedirectStandardInput == true) {
1130                                 MonoIO.Close (stdin_rd, out error);
1131                                 process.input_stream = new StreamWriter (new MonoSyncFileStream (stdin_wr, FileAccess.Write, true, 8192), Console.Out.Encoding);
1132                                 process.input_stream.AutoFlush = true;
1133                         }
1134
1135 #if NET_2_0
1136                         Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1137                         Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1138 #else
1139                         Encoding stdoutEncoding = Console.Out.Encoding;
1140                         Encoding stderrEncoding = stdoutEncoding;
1141 #endif
1142
1143                         if (startInfo.RedirectStandardOutput == true) {
1144                                 MonoIO.Close (stdout_wr, out error);
1145                                 process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding, true, 8192);
1146                         }
1147
1148                         if (startInfo.RedirectStandardError == true) {
1149                                 MonoIO.Close (stderr_wr, out error);
1150                                 process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding, true, 8192);
1151                         }
1152
1153                         process.StartExitCallbackIfNeeded ();
1154
1155                         return(ret);
1156                 }
1157
1158                 // Note that ProcInfo.Password must be freed.
1159                 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1160                 {
1161 #if NET_2_0
1162                         if (startInfo.UserName != null) {
1163                                 proc_info.UserName = startInfo.UserName;
1164                                 proc_info.Domain = startInfo.Domain;
1165                                 if (startInfo.Password != null)
1166                                         proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1167                                 else
1168                                         proc_info.Password = IntPtr.Zero;
1169                                 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1170                         }
1171 #endif
1172                 }
1173
1174                 private static bool Start_common (ProcessStartInfo startInfo,
1175                                                   Process process)
1176                 {
1177                         if (startInfo.FileName == null || startInfo.FileName.Length == 0)
1178                                 throw new InvalidOperationException("File name has not been set");
1179                         
1180 #if NET_2_0
1181                         if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1182                                 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1183                         if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1184                                 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1185 #endif
1186                         
1187                         if (startInfo.UseShellExecute) {
1188 #if NET_2_0
1189                                 if (!String.IsNullOrEmpty (startInfo.UserName))
1190                                         throw new InvalidOperationException ("UserShellExecute must be false if an explicit UserName is specified when starting a process");
1191 #endif
1192                                 return (Start_shell (startInfo, process));
1193                         } else {
1194                                 return (Start_noshell (startInfo, process));
1195                         }
1196                 }
1197                 
1198                 public bool Start ()
1199                 {
1200                         if (process_handle != IntPtr.Zero) {
1201                                 Process_free_internal (process_handle);
1202                                 process_handle = IntPtr.Zero;
1203                         }
1204                         return Start_common(start_info, this);
1205                 }
1206
1207                 public static Process Start (ProcessStartInfo startInfo)
1208                 {
1209                         if (startInfo == null)
1210                                 throw new ArgumentNullException ("startInfo");
1211
1212                         Process process=new Process();
1213                         process.StartInfo = startInfo;
1214                         if (Start_common(startInfo, process))
1215                                 return process;
1216                         return null;
1217                 }
1218
1219                 public static Process Start (string fileName)
1220                 {
1221                         return Start (new ProcessStartInfo (fileName));
1222                 }
1223
1224                 public static Process Start(string fileName, string arguments)
1225                 {
1226                         return Start (new ProcessStartInfo (fileName, arguments));
1227                 }
1228
1229 #if NET_2_0
1230                 public static Process Start(string fileName, string username, SecureString password, string domain) {
1231                         return Start(fileName, null, username, password, domain);
1232                 }
1233
1234                 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1235                         ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1236                         psi.UserName = username;
1237                         psi.Password = password;
1238                         psi.Domain = domain;
1239                         psi.UseShellExecute = false;
1240                         return Start(psi);
1241                 }
1242 #endif
1243
1244                 public override string ToString()
1245                 {
1246                         return(base.ToString() + " (" + this.ProcessName + ")");
1247                 }
1248
1249                 /* Waits up to ms milliseconds for process 'handle' to
1250                  * exit.  ms can be <0 to mean wait forever.
1251                  */
1252                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1253                 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1254
1255                 public void WaitForExit ()
1256                 {
1257                         WaitForExit (-1);
1258                 }
1259
1260                 public bool WaitForExit(int milliseconds) {
1261                         int ms = milliseconds;
1262                         if (ms == int.MaxValue)
1263                                 ms = -1;
1264
1265 #if NET_2_0
1266                         DateTime start = DateTime.UtcNow;
1267                         if (async_output != null && !async_output.IsCompleted) {
1268                                 if (false == async_output.WaitHandle.WaitOne (ms, false))
1269                                         return false; // Timed out
1270
1271                                 if (ms >= 0) {
1272                                         DateTime now = DateTime.UtcNow;
1273                                         ms -= (int) (now - start).TotalMilliseconds;
1274                                         if (ms <= 0)
1275                                                 return false;
1276                                         start = now;
1277                                 }
1278                         }
1279
1280                         if (async_error != null && !async_error.IsCompleted) {
1281                                 if (false == async_error.WaitHandle.WaitOne (ms, false))
1282                                         return false; // Timed out
1283
1284                                 if (ms >= 0) {
1285                                         ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1286                                         if (ms <= 0)
1287                                                 return false;
1288                                 }
1289                         }
1290 #endif
1291                         return WaitForExit_internal (process_handle, ms);
1292                 }
1293
1294                 /* Waits up to ms milliseconds for process 'handle' to 
1295                  * wait for input.  ms can be <0 to mean wait forever.
1296                  */
1297                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1298                 private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
1299
1300                 // The internal call is only implemented properly on Windows.
1301                 [MonoTODO]
1302                 public bool WaitForInputIdle() {
1303                         return WaitForInputIdle (-1);
1304                 }
1305
1306                 // The internal call is only implemented properly on Windows.
1307                 [MonoTODO]
1308                 public bool WaitForInputIdle(int milliseconds) {
1309                         return WaitForInputIdle_internal (process_handle, milliseconds);
1310                 }
1311
1312                 private static bool IsLocalMachine (string machineName)
1313                 {
1314                         if (machineName == "." || machineName.Length == 0)
1315                                 return true;
1316
1317                         return (string.Compare (machineName, Environment.MachineName, true) == 0);
1318                 }
1319
1320 #if NET_2_0
1321                 [Browsable (true)]
1322                 [MonitoringDescription ("Raised when it receives output data")]
1323                 public event DataReceivedEventHandler OutputDataReceived;
1324                 [Browsable (true)]
1325                 [MonitoringDescription ("Raised when it receives error data")]
1326                 public event DataReceivedEventHandler ErrorDataReceived;
1327
1328                 void OnOutputDataReceived (string str)
1329                 {
1330                         if (OutputDataReceived != null)
1331                                 OutputDataReceived (this, new DataReceivedEventArgs (str));
1332                 }
1333
1334                 void OnErrorDataReceived (string str)
1335                 {
1336                         if (ErrorDataReceived != null)
1337                                 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1338                 }
1339
1340                 [Flags]
1341                 enum AsyncModes {
1342                         NoneYet = 0,
1343                         SyncOutput = 1,
1344                         SyncError = 1 << 1,
1345                         AsyncOutput = 1 << 2,
1346                         AsyncError = 1 << 3
1347                 }
1348
1349                 [StructLayout (LayoutKind.Sequential)]
1350                 sealed class ProcessAsyncReader
1351                 {
1352                         /*
1353                            The following fields match those of SocketAsyncResult.
1354                            This is so that changes needed in the runtime to handle
1355                            asynchronous reads are trivial
1356                            Keep this in sync with SocketAsyncResult in 
1357                            ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
1358                            in metadata/socket-io.h.
1359                         */
1360                         /* DON'T shuffle fields around. DON'T remove fields */
1361                         public object Sock;
1362                         public IntPtr handle;
1363                         public object state;
1364                         public AsyncCallback callback;
1365                         public ManualResetEvent wait_handle;
1366
1367                         public Exception delayedException;
1368
1369                         public object EndPoint;
1370                         byte [] buffer = new byte [4196];
1371                         public int Offset;
1372                         public int Size;
1373                         public int SockFlags;
1374
1375                         public object AcceptSocket;
1376                         public object[] Addresses;
1377                         public int port;
1378                         public object Buffers;          // Reserve this slot in older profiles
1379                         public bool ReuseSocket;        // Disconnect
1380                         public object acc_socket;
1381                         public int total;
1382                         public bool completed_sync;
1383                         bool completed;
1384                         bool err_out; // true -> stdout, false -> stderr
1385                         internal int error;
1386                         public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1387                         public object ares;
1388                         public int EndCalled;
1389
1390                         // These fields are not in SocketAsyncResult
1391                         Process process;
1392                         Stream stream;
1393                         StringBuilder sb = new StringBuilder ();
1394                         public AsyncReadHandler ReadHandler;
1395
1396                         public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1397                         {
1398                                 this.process = process;
1399                                 this.handle = handle;
1400                                 stream = new FileStream (handle, FileAccess.Read, false);
1401                                 this.ReadHandler = new AsyncReadHandler (AddInput);
1402                                 this.err_out = err_out;
1403                         }
1404
1405                         public void AddInput ()
1406                         {
1407                                 lock (this) {
1408                                         int nread = stream.Read (buffer, 0, buffer.Length);
1409                                         if (nread == 0) {
1410                                                 completed = true;
1411                                                 if (wait_handle != null)
1412                                                         wait_handle.Set ();
1413                                                 FlushLast ();
1414                                                 return;
1415                                         }
1416
1417                                         try {
1418                                                 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1419                                         } catch {
1420                                                 // Just in case the encoding fails...
1421                                                 for (int i = 0; i < nread; i++) {
1422                                                         sb.Append ((char) buffer [i]);
1423                                                 }
1424                                         }
1425
1426                                         Flush (false);
1427                                         ReadHandler.BeginInvoke (null, this);
1428                                 }
1429                         }
1430
1431                         void FlushLast ()
1432                         {
1433                                 Flush (true);
1434                                 if (err_out) {
1435                                         process.OnOutputDataReceived (null);
1436                                 } else {
1437                                         process.OnErrorDataReceived (null);
1438                                 }
1439                         }
1440                         
1441                         void Flush (bool last)
1442                         {
1443                                 if (sb.Length == 0 ||
1444                                     (err_out && process.output_canceled) ||
1445                                     (!err_out && process.error_canceled))
1446                                         return;
1447
1448                                 string total = sb.ToString ();
1449                                 sb.Length = 0;
1450                                 string [] strs = total.Split ('\n');
1451                                 int len = strs.Length;
1452                                 if (len == 0)
1453                                         return;
1454
1455                                 for (int i = 0; i < len - 1; i++) {
1456                                         if (err_out)
1457                                                 process.OnOutputDataReceived (strs [i]);
1458                                         else
1459                                                 process.OnErrorDataReceived (strs [i]);
1460                                 }
1461
1462                                 string end = strs [len - 1];
1463                                 if (last || (len == 1 && end == "")) {
1464                                         if (err_out) {
1465                                                 process.OnOutputDataReceived (end);
1466                                         } else {
1467                                                 process.OnErrorDataReceived (end);
1468                                         }
1469                                 } else {
1470                                         sb.Append (end);
1471                                 }
1472                         }
1473
1474                         public bool IsCompleted {
1475                                 get { return completed; }
1476                         }
1477
1478                         public WaitHandle WaitHandle {
1479                                 get {
1480                                         lock (this) {
1481                                                 if (wait_handle == null)
1482                                                         wait_handle = new ManualResetEvent (completed);
1483                                                 return wait_handle;
1484                                         }
1485                                 }
1486                         }
1487
1488                         public void Close () {
1489                                 stream.Close ();
1490                         }
1491                 }
1492
1493                 AsyncModes async_mode;
1494                 bool output_canceled;
1495                 bool error_canceled;
1496                 ProcessAsyncReader async_output;
1497                 ProcessAsyncReader async_error;
1498                 delegate void AsyncReadHandler ();
1499
1500                 [ComVisibleAttribute(false)] 
1501                 public void BeginOutputReadLine ()
1502                 {
1503                         if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1504                                 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1505
1506                         if ((async_mode & AsyncModes.SyncOutput) != 0)
1507                                 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1508
1509                         async_mode |= AsyncModes.AsyncOutput;
1510                         output_canceled = false;
1511                         if (async_output == null) {
1512                                 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1513                                 async_output.ReadHandler.BeginInvoke (null, async_output);
1514                         }
1515                 }
1516
1517                 [ComVisibleAttribute(false)] 
1518                 public void CancelOutputRead ()
1519                 {
1520                         if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1521                                 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1522
1523                         if ((async_mode & AsyncModes.SyncOutput) != 0)
1524                                 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1525
1526                         if (async_output == null)
1527                                 throw new InvalidOperationException ("No async operation in progress.");
1528
1529                         output_canceled = true;
1530                 }
1531
1532                 [ComVisibleAttribute(false)] 
1533                 public void BeginErrorReadLine ()
1534                 {
1535                         if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1536                                 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1537
1538                         if ((async_mode & AsyncModes.SyncError) != 0)
1539                                 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1540
1541                         async_mode |= AsyncModes.AsyncError;
1542                         error_canceled = false;
1543                         if (async_error == null) {
1544                                 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1545                                 async_error.ReadHandler.BeginInvoke (null, async_error);
1546                         }
1547                 }
1548
1549                 [ComVisibleAttribute(false)] 
1550                 public void CancelErrorRead ()
1551                 {
1552                         if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1553                                 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1554
1555                         if ((async_mode & AsyncModes.SyncOutput) != 0)
1556                                 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1557
1558                         if (async_error == null)
1559                                 throw new InvalidOperationException ("No async operation in progress.");
1560
1561                         error_canceled = true;
1562                 }
1563 #endif
1564
1565                 [Category ("Behavior")]
1566                 [MonitoringDescription ("Raised when this process exits.")]
1567                 public event EventHandler Exited {
1568                         add {
1569                                 if (process_handle != IntPtr.Zero && HasExited) {
1570                                         value.BeginInvoke (null, null, null, null);
1571                                 } else {
1572                                         exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1573                                         if (exited_event != null)
1574                                                 StartExitCallbackIfNeeded ();
1575                                 }
1576                         }
1577                         remove {
1578                                 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1579                         }
1580                 }
1581
1582                 // Closes the system process handle
1583                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1584                 private extern void Process_free_internal(IntPtr handle);
1585                 
1586                 private bool disposed = false;
1587                 
1588                 protected override void Dispose(bool disposing) {
1589                         // Check to see if Dispose has already been called.
1590                         if(this.disposed == false) {
1591                                 this.disposed=true;
1592                                 // If this is a call to Dispose,
1593                                 // dispose all managed resources.
1594                                 if(disposing) {
1595                                         // Do stuff here
1596                                         lock (this) {
1597                                                 /* These have open FileStreams on the pipes we are about to close */
1598                                                 if (async_output != null)
1599                                                         async_output.Close ();
1600                                                 if (async_error != null)
1601                                                         async_error.Close ();
1602                                         }
1603                                 }
1604                                 
1605                                 // Release unmanaged resources
1606
1607                                 lock(this) {
1608                                         if(process_handle!=IntPtr.Zero) {
1609                                                 Process_free_internal(process_handle);
1610                                                 process_handle=IntPtr.Zero;
1611                                         }
1612
1613                                         if (input_stream != null) {
1614                                                 input_stream.Close();
1615                                                 input_stream = null;
1616                                         }
1617
1618                                         if (output_stream != null) {
1619                                                 output_stream.Close();
1620                                                 output_stream = null;
1621                                         }
1622
1623                                         if (error_stream != null) {
1624                                                 error_stream.Close();
1625                                                 error_stream = null;
1626                                         }
1627                                 }
1628                         }
1629                         base.Dispose (disposing);
1630                 }
1631
1632                 ~Process ()
1633                 {
1634                         Dispose (false);
1635                 }
1636
1637                 static void CBOnExit (object state, bool unused)
1638                 {
1639                         Process p = (Process) state;
1640                         p.OnExited ();
1641                 }
1642
1643                 protected void OnExited() 
1644                 {
1645                         if (exited_event == null)
1646                                 return;
1647
1648                         if (synchronizingObject == null) {
1649                                 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1650                                         try {
1651                                                 d (this, EventArgs.Empty);
1652                                         } catch {}
1653                                 }
1654                                 return;
1655                         }
1656                         
1657                         object [] args = new object [] {this, EventArgs.Empty};
1658                         synchronizingObject.BeginInvoke (exited_event, args);
1659                 }
1660
1661                 static bool IsWindows
1662                 {
1663                         get
1664                         {
1665                                 PlatformID platform = Environment.OSVersion.Platform;
1666                                 if (platform == PlatformID.Win32S ||
1667                                         platform == PlatformID.Win32Windows ||
1668                                         platform == PlatformID.Win32NT ||
1669                                         platform == PlatformID.WinCE) {
1670                                         return true;
1671                                 }
1672                                 return false;
1673                         }
1674                 }
1675
1676                 class ProcessWaitHandle : WaitHandle
1677                 {
1678                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
1679                         private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1680                         
1681                         public ProcessWaitHandle (IntPtr handle)
1682                         {
1683                                 // Need to keep a reference to this handle,
1684                                 // in case the Process object is collected
1685                                 Handle = ProcessHandle_duplicate (handle);
1686
1687                                 // When the wait handle is disposed, the duplicated handle will be
1688                                 // closed, so no need to override dispose (bug #464628).
1689                         }
1690                 }
1691         }
1692 }
1693