2004-03-22 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 //
8 // (C) 2002 Ximian, Inc.
9 // (C) 2003 Andreas Nahr
10 //
11
12 using System;
13 using System.IO;
14 using System.ComponentModel;
15 using System.ComponentModel.Design;
16 using System.Runtime.CompilerServices;
17 using System.Runtime.InteropServices;
18 using System.Collections;
19 using System.Threading;
20
21 namespace System.Diagnostics {
22         [DefaultEvent ("Exited"), DefaultProperty ("StartInfo")]
23         [Designer ("System.Diagnostics.Design.ProcessDesigner, " + Consts.AssemblySystem_Design, typeof (IDesigner))]
24         public class Process : Component 
25         {
26                 [StructLayout(LayoutKind.Sequential)]
27                 private struct ProcInfo 
28                 {
29                         public IntPtr process_handle;
30                         public IntPtr thread_handle;
31                         public int pid; // Contains -GetLastError () on failure.
32                         public int tid;
33                         public string [] envKeys;
34                         public string [] envValues;
35                         public bool useShellExecute;
36                 };
37                 
38                 IntPtr process_handle;
39                 int pid;
40                 bool enableRaisingEvents;
41                 
42                 /* Private constructor called from other methods */
43                 private Process(IntPtr handle, int id) {
44                         process_handle=handle;
45                         pid=id;
46                 }
47                 
48                 [MonoTODO]
49                 public Process() {
50                 }
51
52                 [MonoTODO]
53                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
54                 [MonitoringDescription ("Base process priority.")]
55                 public int BasePriority {
56                         get {
57                                 return(0);
58                         }
59                 }
60
61                 [MonoTODO]
62                 [DefaultValue (false), Browsable (false)]
63                 [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
64                 public bool EnableRaisingEvents {
65                         get {
66                                 return enableRaisingEvents;
67                         }
68                         set { 
69                                 if (process_handle != IntPtr.Zero)
70                                         throw new InvalidOperationException ("The process is already started.");
71
72                                 enableRaisingEvents = value;
73                         }
74
75                 }
76
77                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
78                 private extern static int ExitCode_internal(IntPtr handle);
79
80                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
81                 [MonitoringDescription ("The exit code of the process.")]
82                 public int ExitCode {
83                         get {
84                                 if (process_handle == IntPtr.Zero)
85                                         throw new InvalidOperationException ("Process has not been started.");
86
87                                 int code = ExitCode_internal (process_handle);
88                                 if (code == 259)
89                                         throw new InvalidOperationException ("The process must exit before " +
90                                                                         "getting the requested information.");
91
92                                 return code;
93                         }
94                 }
95
96                 /* Returns the process start time in Windows file
97                  * times (ticks from DateTime(1/1/1601 00:00 GMT))
98                  */
99                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
100                 private extern static long ExitTime_internal(IntPtr handle);
101                 
102                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
103                 [MonitoringDescription ("The exit time of the process.")]
104                 public DateTime ExitTime {
105                         get {
106                                 if (process_handle == IntPtr.Zero)
107                                         throw new InvalidOperationException ("Process has not been started.");
108
109                                 if (!HasExited)
110                                         throw new InvalidOperationException ("The process must exit before " +
111                                                                         "getting the requested information.");
112
113                                 return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
114                         }
115                 }
116
117                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
118                 [MonitoringDescription ("Handle for this process.")]
119                 public IntPtr Handle {
120                         get {
121                                 return(process_handle);
122                         }
123                 }
124
125                 [MonoTODO]
126                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
127                 [MonitoringDescription ("Handles for this process.")]
128                 public int HandleCount {
129                         get {
130                                 return(0);
131                         }
132                 }
133
134                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
135                 [MonitoringDescription ("Determines if the process is still running.")]
136                 public bool HasExited {
137                         get {
138                                 int exitcode = ExitCode_internal (process_handle);
139
140                                 if(exitcode==259) {
141                                         /* STILL_ACTIVE */
142                                         return(false);
143                                 } else {
144                                         return(true);
145                                 }
146                         }
147                 }
148
149                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
150                 [MonitoringDescription ("Process identifier.")]
151                 public int Id {
152                         get {
153                                 return(pid);
154                         }
155                 }
156
157                 [MonoTODO]
158                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
159                 [MonitoringDescription ("The name of the computer running the process.")]
160                 public string MachineName {
161                         get {
162                                 return("localhost");
163                         }
164                 }
165
166                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
167                 [MonitoringDescription ("The main module of the process.")]
168                 public ProcessModule MainModule {
169                         get {
170                                 return(this.Modules[0]);
171                         }
172                 }
173
174                 [MonoTODO]
175                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
176                 [MonitoringDescription ("The handle of the main window of the process.")]
177                 public IntPtr MainWindowHandle {
178                         get {
179                                 return((IntPtr)0);
180                         }
181                 }
182
183                 [MonoTODO]
184                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
185                 [MonitoringDescription ("The title of the main window of the process.")]
186                 public string MainWindowTitle {
187                         get {
188                                 return("null");
189                         }
190                 }
191
192                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
193                 private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
194                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
195                 private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);
196
197                 /* LAMESPEC: why is this an IntPtr not a plain int? */
198                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
199                 [MonitoringDescription ("The maximum working set for this process.")]
200                 public IntPtr MaxWorkingSet {
201                         get {
202                                 if(HasExited) {
203                                         throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
204                                 }
205                                 
206                                 int min;
207                                 int max;
208                                 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
209                                 if(ok==false) {
210                                         throw new Win32Exception();
211                                 }
212                                 
213                                 return((IntPtr)max);
214                         }
215                         set {
216                                 if(HasExited) {
217                                         throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
218                                 }
219                                 
220                                 bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
221                                 if(ok==false) {
222                                         throw new Win32Exception();
223                                 }
224                         }
225                 }
226
227                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
228                 [MonitoringDescription ("The minimum working set for this process.")]
229                 public IntPtr MinWorkingSet {
230                         get {
231                                 if(HasExited) {
232                                         throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
233                                 }
234                                 
235                                 int min;
236                                 int max;
237                                 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
238                                 if(ok==false) {
239                                         throw new Win32Exception();
240                                 }
241                                 
242                                 return((IntPtr)min);
243                         }
244                         set {
245                                 if(HasExited) {
246                                         throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
247                                 }
248                                 
249                                 bool ok=SetWorkingSet_internal(process_handle, value.ToInt32(), 0, true);
250                                 if(ok==false) {
251                                         throw new Win32Exception();
252                                 }
253                         }
254                 }
255
256                 /* Returns the list of process modules.  The main module is
257                  * element 0.
258                  */
259                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
260                 private extern ProcessModule[] GetModules_internal();
261
262                 private ProcessModuleCollection module_collection;
263                 
264                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
265                 [MonitoringDescription ("The modules that are loaded as part of this process.")]
266                 public ProcessModuleCollection Modules {
267                         get {
268                                 if(module_collection==null) {
269                                         module_collection=new ProcessModuleCollection(GetModules_internal());
270                                 }
271
272                                 return(module_collection);
273                         }
274                 }
275
276                 [MonoTODO]
277                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
278                 [MonitoringDescription ("The number of bytes that are not pageable.")]
279                 public int NonpagedSystemMemorySize {
280                         get {
281                                 return(0);
282                         }
283                 }
284
285                 [MonoTODO]
286                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
287                 [MonitoringDescription ("The number of bytes that are paged.")]
288                 public int PagedMemorySize {
289                         get {
290                                 return(0);
291                         }
292                 }
293
294                 [MonoTODO]
295                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
296                 [MonitoringDescription ("The amount of paged system memory in bytes.")]
297                 public int PagedSystemMemorySize {
298                         get {
299                                 return(0);
300                         }
301                 }
302
303                 [MonoTODO]
304                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
305                 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
306                 public int PeakPagedMemorySize {
307                         get {
308                                 return(0);
309                         }
310                 }
311
312                 [MonoTODO]
313                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
314                 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
315                 public int PeakVirtualMemorySize {
316                         get {
317                                 return(0);
318                         }
319                 }
320
321                 [MonoTODO]
322                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
323                 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
324                 public int PeakWorkingSet {
325                         get {
326                                 return(0);
327                         }
328                 }
329
330                 [MonoTODO]
331                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
332                 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
333                 public bool PriorityBoostEnabled {
334                         get {
335                                 return(false);
336                         }
337                         set {
338                         }
339                 }
340
341                 [MonoTODO]
342                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
343                 [MonitoringDescription ("The relative process priority.")]
344                 public ProcessPriorityClass PriorityClass {
345                         get {
346                                 return(ProcessPriorityClass.Normal);
347                         }
348                         set {
349                         }
350                 }
351
352                 [MonoTODO]
353                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
354                 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
355                 public int PrivateMemorySize {
356                         get {
357                                 return(0);
358                         }
359                 }
360
361                 [MonoTODO]
362                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
363                 [MonitoringDescription ("The amount of processing time spent is the OS core for this process.")]
364                 public TimeSpan PrivilegedProcessorTime {
365                         get {
366                                 return(new TimeSpan(0));
367                         }
368                 }
369
370                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
371                 private extern static string ProcessName_internal(IntPtr handle);
372                 
373                 private string process_name=null;
374                 
375                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
376                 [MonitoringDescription ("The name of this process.")]
377                 public string ProcessName {
378                         get {
379                                 if(process_name==null) {
380                                         process_name=ProcessName_internal(process_handle);
381                                         /* If process_name is _still_
382                                          * null, assume the process
383                                          * has exited
384                                          */
385                                         if(process_name==null) {
386                                                 throw new SystemException("The process has exited");
387                                         }
388                                         
389                                         /* Strip the suffix (if it
390                                          * exists) simplistically
391                                          * instead of removing any
392                                          * trailing \.???, so we dont
393                                          * get stupid results on sane
394                                          * systems
395                                          */
396                                         if(process_name.EndsWith(".exe") ||
397                                            process_name.EndsWith(".bat") ||
398                                            process_name.EndsWith(".com")) {
399                                                 process_name=process_name.Substring(0, process_name.Length-4);
400                                         }
401                                 }
402                                 return(process_name);
403                         }
404                 }
405
406                 [MonoTODO]
407                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
408                 [MonitoringDescription ("Allowed processor that can be used by this process.")]
409                 public IntPtr ProcessorAffinity {
410                         get {
411                                 return((IntPtr)0);
412                         }
413                         set {
414                         }
415                 }
416
417                 [MonoTODO]
418                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
419                 [MonitoringDescription ("Is this process responsive.")]
420                 public bool Responding {
421                         get {
422                                 return(false);
423                         }
424                 }
425
426                 private StreamReader error_stream=null;
427                 
428                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
429                 [MonitoringDescription ("The standard error stream of this process.")]
430                 public StreamReader StandardError {
431                         get {
432                                 return(error_stream);
433                         }
434                 }
435
436                 private StreamWriter input_stream=null;
437                 
438                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
439                 [MonitoringDescription ("The standard input stream of this process.")]
440                 public StreamWriter StandardInput {
441                         get {
442                                 return(input_stream);
443                         }
444                 }
445
446                 private StreamReader output_stream=null;
447                 
448                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
449                 [MonitoringDescription ("The standard output stream of this process.")]
450                 public StreamReader StandardOutput {
451                         get {
452                                 return(output_stream);
453                         }
454                 }
455
456                 private ProcessStartInfo start_info=null;
457                 
458                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
459                 [MonitoringDescription ("Information for the start of this process.")]
460                 public ProcessStartInfo StartInfo {
461                         get {
462                                 if(start_info==null) {
463                                         start_info=new ProcessStartInfo();
464                                 }
465                                 
466                                 return(start_info);
467                         }
468                         set {
469                                 if(value==null) {
470                                         throw new ArgumentException("value is null");
471                                 }
472                                 
473                                 start_info=value;
474                         }
475                 }
476
477                 /* Returns the process start time in Windows file
478                  * times (ticks from DateTime(1/1/1601 00:00 GMT))
479                  */
480                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
481                 private extern static long StartTime_internal(IntPtr handle);
482                 
483                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
484                 [MonitoringDescription ("The time this process started.")]
485                 public DateTime StartTime {
486                         get {
487                                 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
488                         }
489                 }
490
491                 [MonoTODO]
492                 [DefaultValue (null), Browsable (false)]
493                 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
494                 public ISynchronizeInvoke SynchronizingObject {
495                         get {
496                                 return(null);
497                         }
498                         set {
499                         }
500                 }
501
502                 [MonoTODO]
503                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
504                 [MonitoringDescription ("The number of threads of this process.")]
505                 public ProcessThreadCollection Threads {
506                         get {
507                                 return(null);
508                         }
509                 }
510
511                 [MonoTODO]
512                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
513                 [MonitoringDescription ("The total CPU time spent for this process.")]
514                 public TimeSpan TotalProcessorTime {
515                         get {
516                                 return(new TimeSpan(0));
517                         }
518                 }
519
520                 [MonoTODO]
521                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
522                 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
523                 public TimeSpan UserProcessorTime {
524                         get {
525                                 return(new TimeSpan(0));
526                         }
527                 }
528
529                 [MonoTODO]
530                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
531                 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
532                 public int VirtualMemorySize {
533                         get {
534                                 return(0);
535                         }
536                 }
537
538                 [MonoTODO]
539                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
540                 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
541                 public int WorkingSet {
542                         get {
543                                 return(0);
544                         }
545                 }
546
547                 [MonoTODO]
548                 public void Close() {
549                 }
550
551                 [MonoTODO]
552                 public bool CloseMainWindow() {
553                         return(false);
554                 }
555
556                 [MonoTODO]
557                 public static void EnterDebugMode() {
558                 }
559
560                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
561                 private extern static IntPtr GetProcess_internal(int pid);
562                 
563                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
564                 private extern static int GetPid_internal();
565
566                 public static Process GetCurrentProcess() {
567                         int pid=GetPid_internal();
568                         IntPtr proc=GetProcess_internal(pid);
569                         
570                         if(proc==IntPtr.Zero) {
571                                 throw new SystemException("Can't find current process");
572                         }
573
574                         return(new Process(proc, pid));
575                 }
576
577                 public static Process GetProcessById(int processId) {
578                         IntPtr proc=GetProcess_internal(processId);
579                         
580                         if(proc==IntPtr.Zero) {
581                                 throw new ArgumentException("Can't find process with ID " + processId.ToString());
582                         }
583
584                         return(new Process(proc, processId));
585                 }
586
587                 [MonoTODO]
588                 public static Process GetProcessById(int processId, string machineName) {
589                         throw new NotImplementedException();
590                 }
591
592                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
593                 private extern static int[] GetProcesses_internal();
594
595                 public static Process[] GetProcesses() {
596                         int[] pids=GetProcesses_internal();
597                         ArrayList proclist=new ArrayList();
598                         
599                         for(int i=0; i<pids.Length; i++) {
600                                 try {
601                                         proclist.Add(GetProcessById(pids[i]));
602                                 } catch (SystemException) {
603                                         /* The process might exit
604                                          * between
605                                          * GetProcesses_internal and
606                                          * GetProcessById
607                                          */
608                                 }
609                         }
610
611                         return((Process[])proclist.ToArray(typeof(Process)));
612                 }
613
614                 [MonoTODO]
615                 public static Process[] GetProcesses(string machineName) {
616                         throw new NotImplementedException();
617                 }
618
619                 public static Process[] GetProcessesByName(string processName) {
620                         Process[] procs=GetProcesses();
621                         ArrayList proclist=new ArrayList();
622                         
623                         for(int i=0; i<procs.Length; i++) {
624                                 /* Ignore case */
625                                 if(String.Compare(processName,
626                                                   procs[i].ProcessName,
627                                                   true)==0) {
628                                         proclist.Add(procs[i]);
629                                 }
630                         }
631
632                         return((Process[])proclist.ToArray(typeof(Process)));
633                 }
634
635                 [MonoTODO]
636                 public static Process[] GetProcessesByName(string processName, string machineName) {
637                         throw new NotImplementedException();
638                 }
639
640                 [MonoTODO]
641                 public void Kill() {
642                 }
643
644                 [MonoTODO]
645                 public static void LeaveDebugMode() {
646                 }
647
648                 [MonoTODO]
649                 public void Refresh() {
650                 }
651
652                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
653                 private extern static bool Start_internal(string cmd,
654                                                           string dir,
655                                                           IntPtr stdin,
656                                                           IntPtr stdout,
657                                                           IntPtr stderr,
658                                                           ref ProcInfo proc_info);
659
660                 private static bool Start_common(ProcessStartInfo startInfo,
661                                                  Process process) {
662                         ProcInfo proc_info=new ProcInfo();
663                         IntPtr stdin_rd, stdin_wr;
664                         IntPtr stdout_rd, stdout_wr;
665                         IntPtr stderr_rd, stderr_wr;
666                         bool ret;
667                         
668                         if(startInfo.FileName == "") {
669                                 throw new InvalidOperationException("File name has not been set");
670                         }
671                         
672                         proc_info.useShellExecute = startInfo.UseShellExecute;
673                         if (startInfo.HaveEnvVars) {
674                                 if (startInfo.UseShellExecute)
675                                         throw new InvalidOperationException ("UseShellExecute must be false in order " +
676                                                                              "to use environment variables.");
677
678                                 string [] strs = new string [startInfo.EnvironmentVariables.Count];
679                                 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
680                                 proc_info.envKeys = strs;
681
682                                 strs = new string [startInfo.EnvironmentVariables.Count];
683                                 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
684                                 proc_info.envValues = strs;
685                         }
686
687                         if(startInfo.RedirectStandardInput==true) {
688                                 ret=MonoIO.CreatePipe(out stdin_rd,
689                                                       out stdin_wr);
690                         } else {
691                                 stdin_rd=MonoIO.ConsoleInput;
692                                 /* This is required to stop the
693                                  * &$*£ing stupid compiler moaning
694                                  * that stdin_wr is unassigned, below.
695                                  */
696                                 stdin_wr=(IntPtr)0;
697                         }
698
699                         if(startInfo.RedirectStandardOutput==true) {
700                                 ret=MonoIO.CreatePipe(out stdout_rd,
701                                                       out stdout_wr);
702                         } else {
703                                 stdout_rd=(IntPtr)0;
704                                 stdout_wr=MonoIO.ConsoleOutput;
705                         }
706
707                         if(startInfo.RedirectStandardError==true) {
708                                 ret=MonoIO.CreatePipe(out stderr_rd,
709                                                       out stderr_wr);
710                         } else {
711                                 stderr_rd=(IntPtr)0;
712                                 stderr_wr=MonoIO.ConsoleError;
713                         }
714                         
715                         ret=Start_internal(startInfo.FileName + " " +
716                                            startInfo.Arguments,
717                                            startInfo.WorkingDirectory,
718                                            stdin_rd, stdout_wr, stderr_wr,
719                                            ref proc_info);
720
721                         MonoIOError error;
722                         
723                         if (!ret) {
724                                 if (startInfo.RedirectStandardInput == true)
725                                         MonoIO.Close (stdin_rd, out error);
726
727                                 if (startInfo.RedirectStandardOutput == true)
728                                         MonoIO.Close (stdout_wr, out error);
729
730                                 if (startInfo.RedirectStandardError == true)
731                                         MonoIO.Close (stderr_wr, out error);
732
733                                 throw new Win32Exception (-proc_info.pid);
734                         }
735
736                         if (process.enableRaisingEvents && process.Exited != null) {
737                                 WaitOrTimerCallback cb = new WaitOrTimerCallback (CBOnExit);
738                                 ProcessWaitHandle h = new ProcessWaitHandle (proc_info.process_handle);
739                                 ThreadPool.RegisterWaitForSingleObject (h, cb, process, -1, true);
740                         }
741                         
742                         process.process_handle=proc_info.process_handle;
743                         process.pid=proc_info.pid;
744                         
745                         if(startInfo.RedirectStandardInput==true) {
746                                 MonoIO.Close(stdin_rd, out error);
747                                 process.input_stream=new StreamWriter(new FileStream(stdin_wr, FileAccess.Write, true));
748                                 process.input_stream.AutoFlush=true;
749                         }
750
751                         if(startInfo.RedirectStandardOutput==true) {
752                                 MonoIO.Close(stdout_wr, out error);
753                                 process.output_stream=new StreamReader(new FileStream(stdout_rd, FileAccess.Read, true));
754                         }
755
756                         if(startInfo.RedirectStandardError==true) {
757                                 MonoIO.Close(stderr_wr, out error);
758                                 process.error_stream=new StreamReader(new FileStream(stderr_rd, FileAccess.Read, true));
759                         }
760
761                         return(ret);
762                 }
763                 
764                 public bool Start() {
765                         bool ret;
766                         
767                         ret=Start_common(start_info, this);
768                         
769                         return(ret);
770                 }
771
772                 public static Process Start(ProcessStartInfo startInfo) {
773                         Process process=new Process();
774                         bool ret;
775
776                         ret=Start_common(startInfo, process);
777                         
778                         if(ret==true) {
779                                 return(process);
780                         } else {
781                                 return(null);
782                         }
783                 }
784
785                 public static Process Start(string fileName) {
786                        return Start(new ProcessStartInfo(fileName));
787                 }
788
789                 public static Process Start(string fileName,
790                                             string arguments) {
791                        return Start(new ProcessStartInfo(fileName, arguments));
792                 }
793
794                 public override string ToString() {
795                         return(base.ToString() +
796                                " (" + this.ProcessName + ")");
797                 }
798
799                 /* Waits up to ms milliseconds for process 'handle' to
800                  * exit.  ms can be <0 to mean wait forever.
801                  */
802                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
803                 private extern bool WaitForExit_internal(IntPtr handle,
804                                                          int ms);
805
806                 public void WaitForExit() {
807                         WaitForExit_internal(process_handle, -1);
808                 }
809
810                 public bool WaitForExit(int milliseconds) {
811                         if (milliseconds == int.MaxValue)
812                                 milliseconds = -1;
813
814                         return WaitForExit_internal (process_handle, milliseconds);
815                 }
816
817                 [MonoTODO]
818                 public bool WaitForInputIdle() {
819                         return(false);
820                 }
821
822                 [MonoTODO]
823                 public bool WaitForInputIdle(int milliseconds) {
824                         return(false);
825                 }
826
827                 [Category ()]
828                 [MonitoringDescription ("Raised when this process exits.")]
829                 public event EventHandler Exited;
830
831                 // Closes the system process handle
832                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
833                 private extern void Process_free_internal(IntPtr handle);
834                 
835                 private bool disposed = false;
836                 
837                 protected override void Dispose(bool disposing) {
838                         // Check to see if Dispose has already been called.
839                         if(this.disposed) {
840                                 this.disposed=true;
841                                 // If this is a call to Dispose,
842                                 // dispose all managed resources.
843                                 if(disposing) {
844                                         // Do stuff here
845                                 }
846                                 
847                                 // Release unmanaged resources
848
849                                 lock(this) {
850                                         if(process_handle!=IntPtr.Zero) {
851                                                 
852                                                 Process_free_internal(process_handle);
853                                                 process_handle=IntPtr.Zero;
854                                         }
855                                 }
856                         }
857                         base.Dispose (disposing);
858                 }
859
860                 static void CBOnExit (object state, bool unused)
861                 {
862                         Process p = (Process) state;
863                         p.OnExited ();
864                 }
865
866                 protected void OnExited() 
867                 {
868                         if (Exited != null)
869                                 Exited (this, EventArgs.Empty);
870                 }
871
872                 class ProcessWaitHandle : WaitHandle
873                 {
874                         public ProcessWaitHandle (IntPtr handle)
875                         {
876                                 Handle = handle;
877                         }
878                 }
879         }
880 }
881