2006-08-09 Gonzalo Paniagua Javier <gonzalo@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.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                         int pid=GetPid_internal();
758                         IntPtr proc=GetProcess_internal(pid);
759                         
760                         if(proc==IntPtr.Zero) {
761                                 throw new SystemException("Can't find current process");
762                         }
763
764                         return(new Process(proc, pid));
765                 }
766
767                 public static Process GetProcessById(int processId) {
768                         IntPtr proc=GetProcess_internal(processId);
769                         
770                         if(proc==IntPtr.Zero) {
771                                 throw new ArgumentException("Can't find process with ID " + processId.ToString());
772                         }
773
774                         return(new Process(proc, processId));
775                 }
776
777                 [MonoTODO]
778                 public static Process GetProcessById(int processId, string machineName) {
779                         throw new NotImplementedException();
780                 }
781
782                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
783                 private extern static int[] GetProcesses_internal();
784
785                 public static Process[] GetProcesses() {
786                         int[] pids=GetProcesses_internal();
787                         ArrayList proclist=new ArrayList();
788                         
789                         for(int i=0; i<pids.Length; i++) {
790                                 try {
791                                         proclist.Add(GetProcessById(pids[i]));
792                                 } catch (SystemException) {
793                                         /* The process might exit
794                                          * between
795                                          * GetProcesses_internal and
796                                          * GetProcessById
797                                          */
798                                 }
799                         }
800
801                         return((Process[])proclist.ToArray(typeof(Process)));
802                 }
803
804                 [MonoTODO]
805                 public static Process[] GetProcesses(string machineName) {
806                         throw new NotImplementedException();
807                 }
808
809                 public static Process[] GetProcessesByName(string processName) {
810                         Process[] procs=GetProcesses();
811                         ArrayList proclist=new ArrayList();
812                         
813                         for(int i=0; i<procs.Length; i++) {
814                                 /* Ignore case */
815                                 if(String.Compare(processName,
816                                                   procs[i].ProcessName,
817                                                   true)==0) {
818                                         proclist.Add(procs[i]);
819                                 }
820                         }
821
822                         return((Process[])proclist.ToArray(typeof(Process)));
823                 }
824
825                 [MonoTODO]
826                 public static Process[] GetProcessesByName(string processName, string machineName) {
827                         throw new NotImplementedException();
828                 }
829
830                 public void Kill ()
831                 {
832                         Close (1);
833                 }
834
835                 [MonoTODO]
836                 public static void LeaveDebugMode() {
837                 }
838
839                 [MonoTODO]
840                 public void Refresh() {
841                 }
842
843                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
844                 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
845                                                                    ref ProcInfo proc_info);
846
847                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
848                 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
849                                                                   IntPtr stdin,
850                                                                   IntPtr stdout,
851                                                                   IntPtr stderr,
852                                                                   ref ProcInfo proc_info);
853
854                 private static bool Start_shell (ProcessStartInfo startInfo,
855                                                  Process process)
856                 {
857                         ProcInfo proc_info=new ProcInfo();
858                         bool ret;
859
860                         if (startInfo.RedirectStandardInput ||
861                             startInfo.RedirectStandardOutput ||
862                             startInfo.RedirectStandardError) {
863                                 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
864                         }
865
866                         if (startInfo.HaveEnvVars) {
867                                 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
868                         }
869
870                         ret = ShellExecuteEx_internal (startInfo,
871                                                        ref proc_info);
872                         if (!ret) {
873                                 throw new Win32Exception (-proc_info.pid);
874                         }
875
876                         process.process_handle = proc_info.process_handle;
877                         process.pid = proc_info.pid;
878
879                         process.StartExitCallbackIfNeeded ();
880
881                         return(ret);
882                 }
883
884                 private static bool Start_noshell (ProcessStartInfo startInfo,
885                                                    Process process)
886                 {
887                         if (Path.IsPathRooted (startInfo.FileName) && !File.Exists (startInfo.FileName))
888                                 throw new FileNotFoundException  ("Executable not found: " + startInfo.FileName);
889                         ProcInfo proc_info=new ProcInfo();
890                         IntPtr stdin_rd, stdin_wr;
891                         IntPtr stdout_wr;
892                         IntPtr stderr_wr;
893                         bool ret;
894                         MonoIOError error;
895
896                         if (startInfo.HaveEnvVars) {
897                                 string [] strs = new string [startInfo.EnvironmentVariables.Count];
898                                 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
899                                 proc_info.envKeys = strs;
900
901                                 strs = new string [startInfo.EnvironmentVariables.Count];
902                                 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
903                                 proc_info.envValues = strs;
904                         }
905
906                         if (startInfo.RedirectStandardInput == true) {
907                                 ret = MonoIO.CreatePipe (out stdin_rd,
908                                                          out stdin_wr);
909                                 if (ret == false) {
910                                         throw new IOException ("Error creating standard input pipe");
911                                 }
912                         } else {
913                                 stdin_rd = MonoIO.ConsoleInput;
914                                 /* This is required to stop the
915                                  * &$*£ing stupid compiler moaning
916                                  * that stdin_wr is unassigned, below.
917                                  */
918                                 stdin_wr = (IntPtr)0;
919                         }
920
921                         if (startInfo.RedirectStandardOutput == true) {
922                                 IntPtr out_rd;
923                                 ret = MonoIO.CreatePipe (out out_rd,
924                                                          out stdout_wr);
925
926                                 process.stdout_rd = out_rd;
927                                 if (ret == false) {
928                                         if (startInfo.RedirectStandardInput == true) {
929                                                 MonoIO.Close (stdin_rd, out error);
930                                                 MonoIO.Close (stdin_wr, out error);
931                                         }
932
933                                         throw new IOException ("Error creating standard output pipe");
934                                 }
935                         } else {
936                                 process.stdout_rd = (IntPtr)0;
937                                 stdout_wr = MonoIO.ConsoleOutput;
938                         }
939
940                         if (startInfo.RedirectStandardError == true) {
941                                 IntPtr err_rd;
942                                 ret = MonoIO.CreatePipe (out err_rd,
943                                                          out stderr_wr);
944
945                                 process.stderr_rd = err_rd;
946                                 if (ret == false) {
947                                         if (startInfo.RedirectStandardInput == true) {
948                                                 MonoIO.Close (stdin_rd, out error);
949                                                 MonoIO.Close (stdin_wr, out error);
950                                         }
951                                         if (startInfo.RedirectStandardOutput == true) {
952                                                 MonoIO.Close (process.stdout_rd, out error);
953                                                 MonoIO.Close (stdout_wr, out error);
954                                         }
955                                         
956                                         throw new IOException ("Error creating standard error pipe");
957                                 }
958                         } else {
959                                 process.stderr_rd = (IntPtr)0;
960                                 stderr_wr = MonoIO.ConsoleError;
961                         }
962                         
963                         ret = CreateProcess_internal (startInfo,
964                                                       stdin_rd, stdout_wr, stderr_wr,
965                                                       ref proc_info);
966                         if (!ret) {
967                                 if (startInfo.RedirectStandardInput == true) {
968                                         MonoIO.Close (stdin_rd, out error);
969                                         MonoIO.Close (stdin_wr, out error);
970                                 }
971
972                                 if (startInfo.RedirectStandardOutput == true) {
973                                         MonoIO.Close (process.stdout_rd, out error);
974                                         MonoIO.Close (stdout_wr, out error);
975                                 }
976
977                                 if (startInfo.RedirectStandardError == true) {
978                                         MonoIO.Close (process.stderr_rd, out error);
979                                         MonoIO.Close (stderr_wr, out error);
980                                 }
981
982                                 throw new Win32Exception (-proc_info.pid, 
983                                         "ApplicationName='"+startInfo.FileName+
984                                         "', CommandLine='"+startInfo.Arguments+
985                                         "', CurrentDirectory='"+startInfo.WorkingDirectory+
986                                         "', PATH='"+startInfo.EnvironmentVariables["PATH"]+"'");
987                         }
988
989                         process.process_handle = proc_info.process_handle;
990                         process.pid = proc_info.pid;
991                         
992                         if (startInfo.RedirectStandardInput == true) {
993                                 MonoIO.Close (stdin_rd, out error);
994                                 process.input_stream = new StreamWriter (new FileStream (stdin_wr, FileAccess.Write, true));
995                                 process.input_stream.AutoFlush = true;
996                         }
997
998                         if (startInfo.RedirectStandardOutput == true) {
999                                 MonoIO.Close (stdout_wr, out error);
1000                                 process.output_stream = new StreamReader (new FileStream (process.stdout_rd, FileAccess.Read, true));
1001                         }
1002
1003                         if (startInfo.RedirectStandardError == true) {
1004                                 MonoIO.Close (stderr_wr, out error);
1005                                 process.error_stream = new StreamReader (new FileStream (process.stderr_rd, FileAccess.Read, true));
1006                         }
1007
1008                         process.StartExitCallbackIfNeeded ();
1009
1010                         return(ret);
1011                 }
1012
1013                 private static bool Start_common (ProcessStartInfo startInfo,
1014                                                   Process process)
1015                 {
1016                         if(startInfo.FileName == null ||
1017                            startInfo.FileName == "") {
1018                                 throw new InvalidOperationException("File name has not been set");
1019                         }
1020                         
1021                         if (startInfo.UseShellExecute) {
1022                                 return (Start_shell (startInfo, process));
1023                         } else {
1024                                 return (Start_noshell (startInfo, process));
1025                         }
1026                 }
1027                 
1028                 public bool Start() {
1029                         bool ret;
1030                         
1031                         ret=Start_common(start_info, this);
1032                         
1033                         return(ret);
1034                 }
1035
1036                 public static Process Start(ProcessStartInfo startInfo) {
1037                         Process process=new Process();
1038                         bool ret;
1039
1040                         ret=Start_common(startInfo, process);
1041                         
1042                         if(ret==true) {
1043                                 return(process);
1044                         } else {
1045                                 return(null);
1046                         }
1047                 }
1048
1049                 public static Process Start(string fileName) {
1050                        return Start(new ProcessStartInfo(fileName));
1051                 }
1052
1053                 public static Process Start(string fileName,
1054                                             string arguments) {
1055                        return Start(new ProcessStartInfo(fileName, arguments));
1056                 }
1057
1058                 public override string ToString() {
1059                         return(base.ToString() +
1060                                " (" + this.ProcessName + ")");
1061                 }
1062
1063                 /* Waits up to ms milliseconds for process 'handle' to
1064                  * exit.  ms can be <0 to mean wait forever.
1065                  */
1066                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1067                 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1068
1069                 public void WaitForExit ()
1070                 {
1071                         WaitForExit (-1);
1072                 }
1073
1074                 public bool WaitForExit(int milliseconds) {
1075                         int ms = milliseconds;
1076                         if (ms == int.MaxValue)
1077                                 ms = -1;
1078
1079 #if NET_2_0
1080                         DateTime start = DateTime.UtcNow;
1081                         if (async_output != null && !async_output.IsCompleted) {
1082                                 if (false == async_output.WaitHandle.WaitOne (ms, false))
1083                                         return false; // Timed out
1084
1085                                 if (ms >= 0) {
1086                                         DateTime now = DateTime.UtcNow;
1087                                         ms -= (int) (now - start).TotalMilliseconds;
1088                                         if (ms <= 0)
1089                                                 return false;
1090                                         start = now;
1091                                 }
1092                         }
1093
1094                         if (async_error != null && !async_error.IsCompleted) {
1095                                 if (false == async_error.WaitHandle.WaitOne (ms, false))
1096                                         return false; // Timed out
1097
1098                                 if (ms >= 0) {
1099                                         ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1100                                         if (ms <= 0)
1101                                                 return false;
1102                                 }
1103                         }
1104 #endif
1105                         return WaitForExit_internal (process_handle, ms);
1106                 }
1107
1108                 [MonoTODO]
1109                 public bool WaitForInputIdle() {
1110                         return(false);
1111                 }
1112
1113                 [MonoTODO]
1114                 public bool WaitForInputIdle(int milliseconds) {
1115                         return(false);
1116                 }
1117
1118
1119 #if NET_2_0
1120                 public event DataReceivedEventHandler OutputDataReceived;
1121                 public event DataReceivedEventHandler ErrorDataReceived;
1122
1123                 void OnOutputDataReceived (string str)
1124                 {
1125                         if (OutputDataReceived != null)
1126                                 OutputDataReceived (this, new DataReceivedEventArgs (str));
1127                 }
1128
1129                 void OnErrorDataReceived (string str)
1130                 {
1131                         if (ErrorDataReceived != null)
1132                                 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1133                 }
1134
1135                 [Flags]
1136                 enum AsyncModes {
1137                         NoneYet = 0,
1138                         SyncOutput = 1,
1139                         SyncError = 1 << 1,
1140                         AsyncOutput = 1 << 2,
1141                         AsyncError = 1 << 3
1142                 }
1143
1144                 [StructLayout (LayoutKind.Sequential)]
1145                 sealed class ProcessAsyncReader
1146                 {
1147                         /*
1148                            The following fields match those of SocketAsyncResult.
1149                            This is so that changes needed in the runtime to handle
1150                            asynchronous reads are trivial
1151                         */
1152                         /* DON'T shuffle fields around. DON'T remove fields */
1153                         public object Sock;
1154                         public IntPtr handle;
1155                         public object state;
1156                         public AsyncCallback callback;
1157                         public ManualResetEvent wait_handle;
1158
1159                         public Exception delayedException;
1160
1161                         public object EndPoint;
1162                         byte [] buffer = new byte [4196];
1163                         public int Offset;
1164                         public int Size;
1165                         public int SockFlags;
1166
1167                         public object acc_socket;
1168                         public int total;
1169                         public bool completed_sync;
1170                         bool completed;
1171                         bool err_out; // true -> stdout, false -> stderr
1172                         internal int error;
1173                         public int operation = 6; // MAGIC NUMBER: Maximum in SocketOperation + 1
1174                         public object ares;
1175
1176
1177                         // These fields are not in SocketAsyncResult
1178                         Process process;
1179                         Stream stream;
1180                         StringBuilder sb = new StringBuilder ();
1181                         public AsyncReadHandler ReadHandler;
1182
1183                         public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1184                         {
1185                                 this.process = process;
1186                                 this.handle = handle;
1187                                 stream = new FileStream (handle, FileAccess.Read, false);
1188                                 this.ReadHandler = new AsyncReadHandler (AddInput);
1189                                 this.err_out = err_out;
1190                         }
1191
1192                         public void AddInput ()
1193                         {
1194                                 lock (this) {
1195                                         int nread = stream.Read (buffer, 0, buffer.Length);
1196                                         if (nread == 0) {
1197                                                 completed = true;
1198                                                 if (wait_handle != null)
1199                                                         wait_handle.Set ();
1200                                                 Flush (true);
1201                                                 return;
1202                                         }
1203
1204                                         try {
1205                                                 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1206                                         } catch {
1207                                                 // Just in case the encoding fails...
1208                                                 for (int i = 0; i < nread; i++) {
1209                                                         sb.Append ((char) buffer [i]);
1210                                                 }
1211                                         }
1212
1213                                         Flush (false);
1214                                         ReadHandler.BeginInvoke (null, this);
1215                                 }
1216                         }
1217
1218                         void Flush (bool last)
1219                         {
1220                                 if (sb.Length == 0 ||
1221                                     (err_out && process.output_canceled) ||
1222                                     (!err_out && process.error_canceled))
1223                                         return;
1224
1225                                 string total = sb.ToString ();
1226                                 sb.Length = 0;
1227                                 string [] strs = total.Split ('\n');
1228                                 int len = strs.Length;
1229                                 if (len == 0)
1230                                         return;
1231
1232                                 for (int i = 0; i < len - 1; i++) {
1233                                         if (err_out)
1234                                                 process.OnOutputDataReceived (strs [i]);
1235                                         else
1236                                                 process.OnErrorDataReceived (strs [i]);
1237                                 }
1238
1239                                 string end = strs [len - 1];
1240                                 if (last || end == "") {
1241                                         if (err_out)
1242                                                 process.OnOutputDataReceived (end);
1243                                         else
1244                                                 process.OnErrorDataReceived (end);
1245                                 } else {
1246                                         sb.Append (end);
1247                                 }
1248                         }
1249
1250                         public bool IsCompleted {
1251                                 get { return completed; }
1252                         }
1253
1254                         public WaitHandle WaitHandle {
1255                                 get {
1256                                         lock (this) {
1257                                                 if (wait_handle == null)
1258                                                         wait_handle = new ManualResetEvent (completed);
1259                                                 return wait_handle;
1260                                         }
1261                                 }
1262                         }
1263                 }
1264
1265                 AsyncModes async_mode;
1266                 bool output_canceled;
1267                 bool error_canceled;
1268                 ProcessAsyncReader async_output;
1269                 ProcessAsyncReader async_error;
1270                 delegate void AsyncReadHandler ();
1271
1272                 [ComVisibleAttribute(false)] 
1273                 public void BeginOutputReadLine ()
1274                 {
1275                         if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1276                                 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1277
1278                         if ((async_mode & AsyncModes.SyncOutput) != 0)
1279                                 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1280
1281                         async_mode |= AsyncModes.AsyncOutput;
1282                         output_canceled = false;
1283                         if (async_output == null) {
1284                                 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1285                                 async_output.ReadHandler.BeginInvoke (null, async_output);
1286                         }
1287                 }
1288
1289                 [ComVisibleAttribute(false)] 
1290                 public void CancelOutputRead ()
1291                 {
1292                         if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1293                                 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1294
1295                         if ((async_mode & AsyncModes.SyncOutput) != 0)
1296                                 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1297
1298                         if (async_output == null)
1299                                 throw new InvalidOperationException ("No async operation in progress.");
1300
1301                         output_canceled = true;
1302                 }
1303
1304                 [ComVisibleAttribute(false)] 
1305                 public void BeginErrorReadLine ()
1306                 {
1307                         if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1308                                 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1309
1310                         if ((async_mode & AsyncModes.SyncError) != 0)
1311                                 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1312
1313                         async_mode |= AsyncModes.AsyncError;
1314                         error_canceled = false;
1315                         if (async_error == null) {
1316                                 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1317                                 async_error.ReadHandler.BeginInvoke (null, async_error);
1318                         }
1319                 }
1320
1321                 [ComVisibleAttribute(false)] 
1322                 public void CancelErrorRead ()
1323                 {
1324                         if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1325                                 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1326
1327                         if ((async_mode & AsyncModes.SyncOutput) != 0)
1328                                 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1329
1330                         if (async_error == null)
1331                                 throw new InvalidOperationException ("No async operation in progress.");
1332
1333                         error_canceled = true;
1334                 }
1335 #endif
1336
1337                 [Category ("Behavior")]
1338                 [MonitoringDescription ("Raised when this process exits.")]
1339                 public event EventHandler Exited {
1340                         add {
1341                                 if (process_handle != IntPtr.Zero && HasExited) {
1342                                         value.BeginInvoke (null, null, null, null);
1343                                 } else {
1344                                         exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1345                                         if (exited_event != null)
1346                                                 StartExitCallbackIfNeeded ();
1347                                 }
1348                         }
1349                         remove {
1350                                 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1351                         }
1352                 }
1353
1354                 // Closes the system process handle
1355                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1356                 private extern void Process_free_internal(IntPtr handle);
1357                 
1358                 private bool disposed = false;
1359                 
1360                 protected override void Dispose(bool disposing) {
1361                         // Check to see if Dispose has already been called.
1362                         if(this.disposed == false) {
1363                                 this.disposed=true;
1364                                 // If this is a call to Dispose,
1365                                 // dispose all managed resources.
1366                                 if(disposing) {
1367                                         // Do stuff here
1368                                 }
1369                                 
1370                                 // Release unmanaged resources
1371
1372                                 lock(this) {
1373                                         if(process_handle!=IntPtr.Zero) {
1374                                                 
1375                                                 Process_free_internal(process_handle);
1376                                                 process_handle=IntPtr.Zero;
1377                                         }
1378
1379                                         if (input_stream != null) {
1380                                                 input_stream.Close();
1381                                                 input_stream = null;
1382                                         }
1383
1384                                         if (output_stream != null) {
1385                                                 output_stream.Close();
1386                                                 output_stream = null;
1387                                         }
1388
1389                                         if (error_stream != null) {
1390                                                 error_stream.Close();
1391                                                 error_stream = null;
1392                                         }
1393                                 }
1394                         }
1395                         base.Dispose (disposing);
1396                 }
1397
1398                 ~Process ()
1399                 {
1400                         Dispose (false);
1401                 }
1402
1403                 static void CBOnExit (object state, bool unused)
1404                 {
1405                         Process p = (Process) state;
1406                         p.OnExited ();
1407                 }
1408
1409                 protected void OnExited() 
1410                 {
1411                         if (exited_event == null)
1412                                 return;
1413
1414                         if (synchronizingObject == null) {
1415                                 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1416                                         try {
1417                                                 d (this, EventArgs.Empty);
1418                                         } catch {}
1419                                 }
1420                                 return;
1421                         }
1422                         
1423                         object [] args = new object [] {this, EventArgs.Empty};
1424                         synchronizingObject.BeginInvoke (exited_event, args);
1425                 }
1426
1427                 class ProcessWaitHandle : WaitHandle
1428                 {
1429                         public ProcessWaitHandle (IntPtr handle)
1430                         {
1431                                 Handle = handle;
1432                         }
1433
1434                         protected override void Dispose (bool explicitDisposing)
1435                         {
1436                                 // Do nothing, we don't own the handle and we won't close it.
1437                         }
1438                 }
1439         }
1440 }
1441