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