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