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