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