Add a third AOT location, alongside ~/.mono/aot-cache and the assembly dir
[mono.git] / mcs / class / System / System.Diagnostics / Process.cs
1 //
2 // System.Diagnostics.Process.cs
3 //
4 // Authors:
5 //      Dick Porter (dick@ximian.com)
6 //      Andreas Nahr (ClassDevelopment@A-SoftTech.com)
7 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 //
9 // (C) 2002 Ximian, Inc.
10 // (C) 2003 Andreas Nahr
11 // (c) 2004,2005,2006 Novell, Inc. (http://www.novell.com)
12 //
13
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34
35 using System.IO;
36 using System.Text;
37 using System.ComponentModel;
38 using System.ComponentModel.Design;
39 using System.Runtime.CompilerServices;
40 using System.Runtime.InteropServices;
41 using System.Security.Permissions;
42 using System.Collections.Generic;
43 using System.Security;
44 using System.Threading;
45
46 namespace System.Diagnostics {
47
48         [DefaultEvent ("Exited"), DefaultProperty ("StartInfo")]
49         [Designer ("System.Diagnostics.Design.ProcessDesigner, " + Consts.AssemblySystem_Design)]
50         [PermissionSet (SecurityAction.LinkDemand, Unrestricted = true)]
51         [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
52         [MonitoringDescription ("Represents a system process")]
53         public class Process : Component 
54         {
55                 [StructLayout(LayoutKind.Sequential)]
56                 private struct ProcInfo 
57                 {
58                         public IntPtr process_handle;
59                         /* If thread_handle is ever needed for
60                          * something, take out the CloseHandle() in
61                          * the Start_internal icall in
62                          * mono/metadata/process.c
63                          */
64                         public IntPtr thread_handle;
65                         public int pid; // Contains -GetLastError () on failure.
66                         public int tid;
67                         public string [] envKeys;
68                         public string [] envValues;
69                         public string UserName;
70                         public string Domain;
71                         public IntPtr Password;
72                         public bool LoadUserProfile;
73                 };
74                 
75                 IntPtr process_handle;
76                 int pid;
77                 bool enableRaisingEvents;
78                 bool already_waiting;
79                 ISynchronizeInvoke synchronizingObject;
80                 EventHandler exited_event;
81                 IntPtr stdout_rd;
82                 IntPtr stderr_rd;
83                 
84                 /* Private constructor called from other methods */
85                 private Process(IntPtr handle, int id) {
86                         process_handle=handle;
87                         pid=id;
88                 }
89                 
90                 public Process ()
91                 {
92                 }
93
94                 [MonoTODO]
95                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
96                 [MonitoringDescription ("Base process priority.")]
97                 public int BasePriority {
98                         get {
99                                 return(0);
100                         }
101                 }
102
103                 void StartExitCallbackIfNeeded ()
104                 {
105                         bool start = (!already_waiting && enableRaisingEvents && exited_event != null);
106                         if (start && process_handle != IntPtr.Zero) {
107                                 WaitOrTimerCallback cb = new WaitOrTimerCallback (CBOnExit);
108                                 ProcessWaitHandle h = new ProcessWaitHandle (process_handle);
109                                 ThreadPool.RegisterWaitForSingleObject (h, cb, this, -1, true);
110                                 already_waiting = true;
111                         }
112                 }
113
114                 [DefaultValue (false), Browsable (false)]
115                 [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
116                 public bool EnableRaisingEvents {
117                         get {
118                                 return enableRaisingEvents;
119                         }
120                         set { 
121                                 bool prev = enableRaisingEvents;
122                                 enableRaisingEvents = value;
123                                 if (enableRaisingEvents && !prev)
124                                         StartExitCallbackIfNeeded ();
125                         }
126
127                 }
128
129                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
130                 private extern static int ExitCode_internal(IntPtr handle);
131
132                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
133                 [MonitoringDescription ("The exit code of the process.")]
134                 public int ExitCode {
135                         get {
136                                 if (process_handle == IntPtr.Zero)
137                                         throw new InvalidOperationException ("Process has not been started.");
138
139                                 int code = ExitCode_internal (process_handle);
140                                 if (code == 259)
141                                         throw new InvalidOperationException ("The process must exit before " +
142                                                                         "getting the requested information.");
143
144                                 return code;
145                         }
146                 }
147
148                 /* Returns the process start time in Windows file
149                  * times (ticks from DateTime(1/1/1601 00:00 GMT))
150                  */
151                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
152                 private extern static long ExitTime_internal(IntPtr handle);
153                 
154                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
155                 [MonitoringDescription ("The exit time of the process.")]
156                 public DateTime ExitTime {
157                         get {
158                                 if (process_handle == IntPtr.Zero)
159                                         throw new InvalidOperationException ("Process has not been started.");
160
161                                 if (!HasExited)
162                                         throw new InvalidOperationException ("The process must exit before " +
163                                                                         "getting the requested information.");
164
165                                 return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
166                         }
167                 }
168
169                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
170                 [MonitoringDescription ("Handle for this process.")]
171                 public IntPtr Handle {
172                         get {
173                                 if (process_handle == IntPtr.Zero)
174                                         throw new InvalidOperationException ("No process is associated with this object.");
175                                 return(process_handle);
176                         }
177                 }
178
179                 [MonoTODO]
180                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
181                 [MonitoringDescription ("Handles for this process.")]
182                 public int HandleCount {
183                         get {
184                                 return(0);
185                         }
186                 }
187
188                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
189                 [MonitoringDescription ("Determines if the process is still running.")]
190                 public bool HasExited {
191                         get {
192                                 if (process_handle == IntPtr.Zero)
193                                         throw new InvalidOperationException ("Process has not been started.");
194                                         
195                                 int exitcode = ExitCode_internal (process_handle);
196
197                                 if(exitcode==259) {
198                                         /* STILL_ACTIVE */
199                                         return(false);
200                                 } else {
201                                         return(true);
202                                 }
203                         }
204                 }
205
206                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
207                 [MonitoringDescription ("Process identifier.")]
208                 public int Id {
209                         get {
210                                 if (pid == 0)
211                                         throw new InvalidOperationException ("Process ID has not been set.");
212
213                                 return(pid);
214                         }
215                 }
216
217                 [MonoTODO]
218                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
219                 [MonitoringDescription ("The name of the computer running the process.")]
220                 public string MachineName {
221                         get {
222                                 return("localhost");
223                         }
224                 }
225
226                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
227                 [MonitoringDescription ("The main module of the process.")]
228                 public ProcessModule MainModule {
229                         get {
230                                 return(this.Modules[0]);
231                         }
232                 }
233
234                 [MonoTODO]
235                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
236                 [MonitoringDescription ("The handle of the main window of the process.")]
237                 public IntPtr MainWindowHandle {
238                         get {
239                                 return((IntPtr)0);
240                         }
241                 }
242
243                 [MonoTODO]
244                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
245                 [MonitoringDescription ("The title of the main window of the process.")]
246                 public string MainWindowTitle {
247                         get {
248                                 return("null");
249                         }
250                 }
251
252                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
253                 private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
254                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
255                 private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);
256
257                 /* LAMESPEC: why is this an IntPtr not a plain int? */
258                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
259                 [MonitoringDescription ("The maximum working set for this process.")]
260                 public IntPtr MaxWorkingSet {
261                         get {
262                                 if(HasExited)
263                                         throw new InvalidOperationException(
264                                                 "The process " + ProcessName +
265                                                 " (ID " + Id + ") has exited");
266                                 
267                                 int min;
268                                 int max;
269                                 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
270                                 if(ok==false) {
271                                         throw new Win32Exception();
272                                 }
273                                 
274                                 return((IntPtr)max);
275                         }
276                         set {
277                                 if(HasExited) {
278                                         throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
279                                 }
280                                 
281                                 bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
282                                 if(ok==false) {
283                                         throw new Win32Exception();
284                                 }
285                         }
286                 }
287
288                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
289                 [MonitoringDescription ("The minimum working set for this process.")]
290                 public IntPtr MinWorkingSet {
291                         get {
292                                 if(HasExited)
293                                         throw new InvalidOperationException(
294                                                 "The process " + ProcessName +
295                                                 " (ID " + Id + ") has exited");
296                                 
297                                 int min;
298                                 int max;
299                                 bool ok= GetWorkingSet_internal (process_handle, out min, out max);
300                                 if(!ok)
301                                         throw new Win32Exception();
302                                 return ((IntPtr) min);
303                         }
304                         set {
305                                 if(HasExited)
306                                         throw new InvalidOperationException(
307                                                 "The process " + ProcessName +
308                                                 " (ID " + Id + ") has exited");
309                                 
310                                 bool ok = SetWorkingSet_internal (process_handle, value.ToInt32(), 0, true);
311                                 if (!ok)
312                                         throw new Win32Exception();
313                         }
314                 }
315
316                 /* Returns the list of process modules.  The main module is
317                  * element 0.
318                  */
319                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
320                 private extern ProcessModule[] GetModules_internal(IntPtr handle);
321
322                 private ProcessModuleCollection module_collection;
323                 
324                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
325                 [MonitoringDescription ("The modules that are loaded as part of this process.")]
326                 public ProcessModuleCollection Modules {
327                         get {
328                                 if (module_collection == null)
329                                         module_collection = new ProcessModuleCollection(
330                                                 GetModules_internal (process_handle));
331                                 return(module_collection);
332                         }
333                 }
334
335                 /* data type is from the MonoProcessData enum in mono-proclib.h in the runtime */
336                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
337                 private extern static long GetProcessData (int pid, int data_type, out int error);
338
339                 [MonoTODO]
340                 [Obsolete ("Use NonpagedSystemMemorySize64")]
341                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
342                 [MonitoringDescription ("The number of bytes that are not pageable.")]
343                 public int NonpagedSystemMemorySize {
344                         get {
345                                 return(0);
346                         }
347                 }
348
349                 [MonoTODO]
350                 [Obsolete ("Use PagedMemorySize64")]
351                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
352                 [MonitoringDescription ("The number of bytes that are paged.")]
353                 public int PagedMemorySize {
354                         get {
355                                 return(0);
356                         }
357                 }
358
359                 [MonoTODO]
360                 [Obsolete ("Use PagedSystemMemorySize64")]
361                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
362                 [MonitoringDescription ("The amount of paged system memory in bytes.")]
363                 public int PagedSystemMemorySize {
364                         get {
365                                 return(0);
366                         }
367                 }
368
369                 [MonoTODO]
370                 [Obsolete ("Use PeakPagedMemorySize64")]
371                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
372                 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
373                 public int PeakPagedMemorySize {
374                         get {
375                                 return(0);
376                         }
377                 }
378
379                 [Obsolete ("Use PeakVirtualMemorySize64")]
380                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
381                 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
382                 public int PeakVirtualMemorySize {
383                         get {
384                                 int error;
385                                 return (int)GetProcessData (pid, 8, out error);
386                         }
387                 }
388
389                 [Obsolete ("Use PeakWorkingSet64")]
390                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
391                 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
392                 public int PeakWorkingSet {
393                         get {
394                                 int error;
395                                 return (int)GetProcessData (pid, 5, out error);
396                         }
397                 }
398
399                 [MonoTODO]
400                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
401                 [MonitoringDescription ("The number of bytes that are not pageable.")]
402                 [ComVisible (false)]
403                 public long NonpagedSystemMemorySize64 {
404                         get {
405                                 return(0);
406                         }
407                 }
408
409                 [MonoTODO]
410                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
411                 [MonitoringDescription ("The number of bytes that are paged.")]
412                 [ComVisible (false)]
413                 public long PagedMemorySize64 {
414                         get {
415                                 return(0);
416                         }
417                 }
418
419                 [MonoTODO]
420                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
421                 [MonitoringDescription ("The amount of paged system memory in bytes.")]
422                 [ComVisible (false)]
423                 public long PagedSystemMemorySize64 {
424                         get {
425                                 return(0);
426                         }
427                 }
428
429                 [MonoTODO]
430                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
431                 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
432                 [ComVisible (false)]
433                 public long PeakPagedMemorySize64 {
434                         get {
435                                 return(0);
436                         }
437                 }
438
439                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
440                 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
441                 [ComVisible (false)]
442                 public long PeakVirtualMemorySize64 {
443                         get {
444                                 int error;
445                                 return GetProcessData (pid, 8, out error);
446                         }
447                 }
448
449                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
450                 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
451                 [ComVisible (false)]
452                 public long PeakWorkingSet64 {
453                         get {
454                                 int error;
455                                 return GetProcessData (pid, 5, out error);
456                         }
457                 }
458
459                 [MonoTODO]
460                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
461                 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
462                 public bool PriorityBoostEnabled {
463                         get {
464                                 return(false);
465                         }
466                         set {
467                         }
468                 }
469
470                 [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
471                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
472                 [MonitoringDescription ("The relative process priority.")]
473                 public ProcessPriorityClass PriorityClass {
474                         get {
475                                 if (process_handle == IntPtr.Zero)
476                                         throw new InvalidOperationException ("Process has not been started.");
477                                 
478                                 int error;
479                                 int prio = GetPriorityClass (process_handle, out error);
480                                 if (prio == 0)
481                                         throw new Win32Exception (error);
482                                 return (ProcessPriorityClass) prio;
483                         }
484                         set {
485                                 if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
486                                         throw new InvalidEnumArgumentException (
487                                                 "value", (int) value,
488                                                 typeof (ProcessPriorityClass));
489
490                                 if (process_handle == IntPtr.Zero)
491                                         throw new InvalidOperationException ("Process has not been started.");
492                                 
493                                 int error;
494                                 if (!SetPriorityClass (process_handle, (int) value, out error)) {
495                                         CheckExited ();
496                                         throw new Win32Exception (error);
497                                 }
498                         }
499                 }
500
501                 void CheckExited () {
502                         if (HasExited)
503                                 throw new InvalidOperationException (String.Format ("Cannot process request because the process ({0}) has exited.", Id));
504                 }
505
506                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
507                 static extern int GetPriorityClass (IntPtr handle, out int error);
508
509                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
510                 static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);
511
512                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
513                 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
514                 [Obsolete ("Use PrivateMemorySize64")]
515                 public int PrivateMemorySize {
516                         get {
517                                 int error;
518                                 return (int)GetProcessData (pid, 6, out error);
519                         }
520                 }
521
522                 [MonoNotSupported ("")]
523                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
524                 [MonitoringDescription ("The session ID for this process.")]
525                 public int SessionId {
526                         get { throw new NotImplementedException (); }
527                 }
528
529                 /* the meaning of type is as follows: 0: user, 1: system, 2: total */
530                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
531                 private extern static long Times (IntPtr handle, int type);
532
533                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
534                 [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
535                 public TimeSpan PrivilegedProcessorTime {
536                         get {
537                                 return new TimeSpan (Times (process_handle, 1));
538                         }
539                 }
540
541                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
542                 private extern static string ProcessName_internal(IntPtr handle);
543                 
544                 private string process_name=null;
545                 
546                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
547                 [MonitoringDescription ("The name of this process.")]
548                 public string ProcessName {
549                         get {
550                                 if(process_name==null) {
551                                         
552                                         if (process_handle == IntPtr.Zero)
553                                                 throw new InvalidOperationException ("No process is associated with this object.");
554                                         
555                                         process_name=ProcessName_internal(process_handle);
556                                         /* If process_name is _still_
557                                          * null, assume the process
558                                          * has exited
559                                          */
560                                         if (process_name == null)
561                                                 throw new InvalidOperationException ("Process has exited, so the requested information is not available.");
562                                         
563                                         /* Strip the suffix (if it
564                                          * exists) simplistically
565                                          * instead of removing any
566                                          * trailing \.???, so we dont
567                                          * get stupid results on sane
568                                          * systems
569                                          */
570                                         if(process_name.EndsWith(".exe") ||
571                                            process_name.EndsWith(".bat") ||
572                                            process_name.EndsWith(".com")) {
573                                                 process_name=process_name.Substring(0, process_name.Length-4);
574                                         }
575                                 }
576                                 return(process_name);
577                         }
578                 }
579
580                 [MonoTODO]
581                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
582                 [MonitoringDescription ("Allowed processor that can be used by this process.")]
583                 public IntPtr ProcessorAffinity {
584                         get {
585                                 return((IntPtr)0);
586                         }
587                         set {
588                         }
589                 }
590
591                 [MonoTODO]
592                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
593                 [MonitoringDescription ("Is this process responsive.")]
594                 public bool Responding {
595                         get {
596                                 return(false);
597                         }
598                 }
599
600                 private StreamReader error_stream=null;
601                 
602                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
603                 [MonitoringDescription ("The standard error stream of this process.")]
604                 public StreamReader StandardError {
605                         get {
606                                 if (error_stream == null)
607                                         throw new InvalidOperationException("Standard error has not been redirected");
608
609                                 if ((async_mode & AsyncModes.AsyncError) != 0)
610                                         throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
611
612                                 async_mode |= AsyncModes.SyncError;
613
614                                 return(error_stream);
615                         }
616                 }
617
618                 private StreamWriter input_stream=null;
619                 
620                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
621                 [MonitoringDescription ("The standard input stream of this process.")]
622                 public StreamWriter StandardInput {
623                         get {
624                                 if (input_stream == null)
625                                         throw new InvalidOperationException("Standard input has not been redirected");
626
627                                 return(input_stream);
628                         }
629                 }
630
631                 private StreamReader output_stream=null;
632                 
633                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
634                 [MonitoringDescription ("The standard output stream of this process.")]
635                 public StreamReader StandardOutput {
636                         get {
637                                 if (output_stream == null)
638                                         throw new InvalidOperationException("Standard output has not been redirected");
639
640                                 if ((async_mode & AsyncModes.AsyncOutput) != 0)
641                                         throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
642
643                                 async_mode |= AsyncModes.SyncOutput;
644
645                                 return(output_stream);
646                         }
647                 }
648
649                 private ProcessStartInfo start_info=null;
650                 
651                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
652                 [MonitoringDescription ("Information for the start of this process.")]
653                 public ProcessStartInfo StartInfo {
654                         get {
655                                 if (start_info == null)
656                                         start_info = new ProcessStartInfo();
657                                 return start_info;
658                         }
659                         set {
660                                 if (value == null)
661                                         throw new ArgumentNullException("value");
662                                 start_info = value;
663                         }
664                 }
665
666                 /* Returns the process start time in Windows file
667                  * times (ticks from DateTime(1/1/1601 00:00 GMT))
668                  */
669                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
670                 private extern static long StartTime_internal(IntPtr handle);
671                 
672                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
673                 [MonitoringDescription ("The time this process started.")]
674                 public DateTime StartTime {
675                         get {
676                                 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
677                         }
678                 }
679
680                 [DefaultValue (null), Browsable (false)]
681                 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
682                 public ISynchronizeInvoke SynchronizingObject {
683                         get { return synchronizingObject; }
684                         set { synchronizingObject = value; }
685                 }
686
687                 [MonoTODO]
688                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
689                 [MonitoringDescription ("The number of threads of this process.")]
690                 public ProcessThreadCollection Threads {
691                         get {
692                                 // This'll return a correctly-sized array of empty ProcessThreads for now.
693                                 int error;
694                                 return new ProcessThreadCollection(new ProcessThread[GetProcessData (pid, 0, out error)]);
695                         }
696                 }
697
698                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
699                 [MonitoringDescription ("The total CPU time spent for this process.")]
700                 public TimeSpan TotalProcessorTime {
701                         get {
702                                 return new TimeSpan (Times (process_handle, 2));
703                         }
704                 }
705
706                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
707                 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
708                 public TimeSpan UserProcessorTime {
709                         get {
710                                 return new TimeSpan (Times (process_handle, 0));
711                         }
712                 }
713
714                 [Obsolete ("Use VirtualMemorySize64")]
715                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
716                 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
717                 public int VirtualMemorySize {
718                         get {
719                                 int error;
720                                 return (int)GetProcessData (pid, 7, out error);
721                         }
722                 }
723
724                 [Obsolete ("Use WorkingSet64")]
725                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
726                 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
727                 public int WorkingSet {
728                         get {
729                                 int error;
730                                 return (int)GetProcessData (pid, 4, out error);
731                         }
732                 }
733
734                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
735                 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
736                 [ComVisible (false)]
737                 public long PrivateMemorySize64 {
738                         get {
739                                 int error;
740                                 return GetProcessData (pid, 6, out error);
741                         }
742                 }
743
744                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
745                 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
746                 [ComVisible (false)]
747                 public long VirtualMemorySize64 {
748                         get {
749                                 int error;
750                                 return GetProcessData (pid, 7, out error);
751                         }
752                 }
753
754                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
755                 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
756                 [ComVisible (false)]
757                 public long WorkingSet64 {
758                         get {
759                                 int error;
760                                 return GetProcessData (pid, 4, out error);
761                         }
762                 }
763
764                 public void Close()
765                 {
766                         Dispose (true);
767                 }
768
769                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
770                 extern static bool Kill_internal (IntPtr handle, int signo);
771
772                 /* int kill -> 1 KILL, 2 CloseMainWindow */
773                 bool Close (int signo)
774                 {
775                         if (process_handle == IntPtr.Zero)
776                                 throw new SystemException ("No process to kill.");
777
778                         int exitcode = ExitCode_internal (process_handle);
779                         if (exitcode != 259)
780                                 throw new InvalidOperationException ("The process already finished.");
781
782                         return Kill_internal (process_handle, signo);
783                 }
784
785                 public bool CloseMainWindow ()
786                 {
787                         return Close (2);
788                 }
789
790                 [MonoTODO]
791                 public static void EnterDebugMode() {
792                 }
793
794                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
795                 private extern static IntPtr GetProcess_internal(int pid);
796                 
797                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
798                 private extern static int GetPid_internal();
799
800                 public static Process GetCurrentProcess()
801                 {
802                         int pid = GetPid_internal();
803                         IntPtr proc = GetProcess_internal(pid);
804                         
805                         if (proc == IntPtr.Zero)
806                                 throw new SystemException("Can't find current process");
807
808                         return (new Process (proc, pid));
809                 }
810
811                 public static Process GetProcessById(int processId)
812                 {
813                         IntPtr proc = GetProcess_internal(processId);
814                         
815                         if (proc == IntPtr.Zero)
816                                 throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
817
818                         return (new Process (proc, processId));
819                 }
820
821                 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
822                 public static Process GetProcessById(int processId, string machineName) {
823                         if (machineName == null)
824                                 throw new ArgumentNullException ("machineName");
825
826                         if (!IsLocalMachine (machineName))
827                                 throw new NotImplementedException ();
828
829                         return GetProcessById (processId);
830                 }
831
832                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
833                 private extern static int[] GetProcesses_internal();
834
835                 public static Process[] GetProcesses ()
836                 {
837                         int [] pids = GetProcesses_internal ();
838                         if (pids == null)
839                                 return new Process [0];
840
841                         var proclist = new List<Process> (pids.Length);
842                         for (int i = 0; i < pids.Length; i++) {
843                                 try {
844                                         proclist.Add (GetProcessById (pids [i]));
845                                 } catch (SystemException) {
846                                         /* The process might exit
847                                          * between
848                                          * GetProcesses_internal and
849                                          * GetProcessById
850                                          */
851                                 }
852                         }
853
854                         return proclist.ToArray ();
855                 }
856
857                 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
858                 public static Process[] GetProcesses(string machineName) {
859                         if (machineName == null)
860                                 throw new ArgumentNullException ("machineName");
861
862                         if (!IsLocalMachine (machineName))
863                                 throw new NotImplementedException ();
864
865                         return GetProcesses ();
866                 }
867
868                 public static Process[] GetProcessesByName(string processName)
869                 {
870                         int [] pids = GetProcesses_internal ();
871                         if (pids == null)
872                                 return new Process [0];
873                         
874                         var proclist = new List<Process> (pids.Length);
875                         for (int i = 0; i < pids.Length; i++) {
876                                 try {
877                                         Process p = GetProcessById (pids [i]);
878                                         if (String.Compare (processName, p.ProcessName, true) == 0)
879                                                 proclist.Add (p);
880                                 } catch (SystemException) {
881                                         /* The process might exit
882                                          * between
883                                          * GetProcesses_internal and
884                                          * GetProcessById
885                                          */
886                                 }
887                         }
888
889                         return proclist.ToArray ();
890                 }
891
892                 [MonoTODO]
893                 public static Process[] GetProcessesByName(string processName, string machineName) {
894                         throw new NotImplementedException();
895                 }
896
897                 public void Kill ()
898                 {
899                         Close (1);
900                 }
901
902                 [MonoTODO]
903                 public static void LeaveDebugMode() {
904                 }
905
906                 public void Refresh ()
907                 {
908                         // FIXME: should refresh any cached data we might have about
909                         // the process (currently we have none).
910                 }
911
912                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
913                 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
914                                                                    ref ProcInfo proc_info);
915
916                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
917                 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
918                                                                   IntPtr stdin,
919                                                                   IntPtr stdout,
920                                                                   IntPtr stderr,
921                                                                   ref ProcInfo proc_info);
922
923                 private static bool Start_shell (ProcessStartInfo startInfo, Process process)
924                 {
925                         ProcInfo proc_info=new ProcInfo();
926                         bool ret;
927
928                         if (startInfo.RedirectStandardInput ||
929                             startInfo.RedirectStandardOutput ||
930                             startInfo.RedirectStandardError) {
931                                 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
932                         }
933
934                         if (startInfo.HaveEnvVars)
935                                 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
936
937                         FillUserInfo (startInfo, ref proc_info);
938                         try {
939                                 ret = ShellExecuteEx_internal (startInfo,
940                                                                ref proc_info);
941                         } finally {
942                                 if (proc_info.Password != IntPtr.Zero)
943                                         Marshal.ZeroFreeBSTR (proc_info.Password);
944                                 proc_info.Password = IntPtr.Zero;
945                         }
946                         if (!ret) {
947                                 throw new Win32Exception (-proc_info.pid);
948                         }
949
950                         process.process_handle = proc_info.process_handle;
951                         process.pid = proc_info.pid;
952                         process.StartExitCallbackIfNeeded ();
953                         return(ret);
954                 }
955
956                 private static bool Start_noshell (ProcessStartInfo startInfo,
957                                                    Process process)
958                 {
959                         ProcInfo proc_info=new ProcInfo();
960                         IntPtr stdin_rd = IntPtr.Zero, stdin_wr = IntPtr.Zero;
961                         IntPtr stdout_wr;
962                         IntPtr stderr_wr;
963                         bool ret;
964                         MonoIOError error;
965
966                         if (startInfo.HaveEnvVars) {
967                                 string [] strs = new string [startInfo.EnvironmentVariables.Count];
968                                 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
969                                 proc_info.envKeys = strs;
970
971                                 strs = new string [startInfo.EnvironmentVariables.Count];
972                                 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
973                                 proc_info.envValues = strs;
974                         }
975
976                         if (startInfo.RedirectStandardInput == true) {
977                                 if (IsWindows) {
978                                         int DUPLICATE_SAME_ACCESS = 0x00000002;
979                                         IntPtr stdin_wr_tmp;
980
981                                         ret = MonoIO.CreatePipe (out stdin_rd,
982                                                                          out stdin_wr_tmp);
983                                         if (ret) {
984                                                 ret = MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, stdin_wr_tmp,
985                                                 Process.GetCurrentProcess ().Handle, out stdin_wr, 0, 0, DUPLICATE_SAME_ACCESS);
986                                                 MonoIO.Close (stdin_wr_tmp, out error);
987                                         }
988                                 }
989                                 else
990                                 {
991                                         ret = MonoIO.CreatePipe (out stdin_rd,
992                                                                          out stdin_wr);
993                                 }
994                                 if (ret == false) {
995                                         throw new IOException ("Error creating standard input pipe");
996                                 }
997                         } else {
998                                 stdin_rd = MonoIO.ConsoleInput;
999                                 /* This is required to stop the
1000                                  * &$*£ing stupid compiler moaning
1001                                  * that stdin_wr is unassigned, below.
1002                                  */
1003                                 stdin_wr = (IntPtr)0;
1004                         }
1005
1006                         if (startInfo.RedirectStandardOutput == true) {
1007                                 IntPtr out_rd = IntPtr.Zero;
1008                                 if (IsWindows) {
1009                                         IntPtr out_rd_tmp;
1010                                         int DUPLICATE_SAME_ACCESS = 0x00000002;
1011
1012                                         ret = MonoIO.CreatePipe (out out_rd_tmp,
1013                                                                          out stdout_wr);
1014                                         if (ret) {
1015                                                 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, out_rd_tmp,
1016                                                 Process.GetCurrentProcess ().Handle, out out_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1017                                                 MonoIO.Close (out_rd_tmp, out error);
1018                                         }
1019                                 }
1020                                 else {
1021                                         ret = MonoIO.CreatePipe (out out_rd,
1022                                                                          out stdout_wr);
1023                                 }
1024
1025                                 process.stdout_rd = out_rd;
1026                                 if (ret == false) {
1027                                         if (startInfo.RedirectStandardInput == true) {
1028                                                 MonoIO.Close (stdin_rd, out error);
1029                                                 MonoIO.Close (stdin_wr, out error);
1030                                         }
1031
1032                                         throw new IOException ("Error creating standard output pipe");
1033                                 }
1034                         } else {
1035                                 process.stdout_rd = (IntPtr)0;
1036                                 stdout_wr = MonoIO.ConsoleOutput;
1037                         }
1038
1039                         if (startInfo.RedirectStandardError == true) {
1040                                 IntPtr err_rd = IntPtr.Zero;
1041                                 if (IsWindows) {
1042                                         IntPtr err_rd_tmp;
1043                                         int DUPLICATE_SAME_ACCESS = 0x00000002;
1044
1045                                         ret = MonoIO.CreatePipe (out err_rd_tmp,
1046                                                                          out stderr_wr);
1047                                         if (ret) {
1048                                                 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, err_rd_tmp,
1049                                                 Process.GetCurrentProcess ().Handle, out err_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1050                                                 MonoIO.Close (err_rd_tmp, out error);
1051                                         }
1052                                 }
1053                                 else {
1054                                         ret = MonoIO.CreatePipe (out err_rd,
1055                                                                          out stderr_wr);
1056                                 }
1057
1058                                 process.stderr_rd = err_rd;
1059                                 if (ret == false) {
1060                                         if (startInfo.RedirectStandardInput == true) {
1061                                                 MonoIO.Close (stdin_rd, out error);
1062                                                 MonoIO.Close (stdin_wr, out error);
1063                                         }
1064                                         if (startInfo.RedirectStandardOutput == true) {
1065                                                 MonoIO.Close (process.stdout_rd, out error);
1066                                                 MonoIO.Close (stdout_wr, out error);
1067                                         }
1068                                         
1069                                         throw new IOException ("Error creating standard error pipe");
1070                                 }
1071                         } else {
1072                                 process.stderr_rd = (IntPtr)0;
1073                                 stderr_wr = MonoIO.ConsoleError;
1074                         }
1075
1076                         FillUserInfo (startInfo, ref proc_info);
1077                         try {
1078                                 ret = CreateProcess_internal (startInfo,
1079                                                               stdin_rd, stdout_wr, stderr_wr,
1080                                                               ref proc_info);
1081                         } finally {
1082                                 if (proc_info.Password != IntPtr.Zero)
1083                                         Marshal.ZeroFreeBSTR (proc_info.Password);
1084                                 proc_info.Password = IntPtr.Zero;
1085                         }
1086                         if (!ret) {
1087                                 if (startInfo.RedirectStandardInput == true) {
1088                                         MonoIO.Close (stdin_rd, out error);
1089                                         MonoIO.Close (stdin_wr, out error);
1090                                 }
1091
1092                                 if (startInfo.RedirectStandardOutput == true) {
1093                                         MonoIO.Close (process.stdout_rd, out error);
1094                                         MonoIO.Close (stdout_wr, out error);
1095                                 }
1096
1097                                 if (startInfo.RedirectStandardError == true) {
1098                                         MonoIO.Close (process.stderr_rd, out error);
1099                                         MonoIO.Close (stderr_wr, out error);
1100                                 }
1101
1102                                 throw new Win32Exception (-proc_info.pid,
1103                                         "ApplicationName='" + startInfo.FileName +
1104                                         "', CommandLine='" + startInfo.Arguments +
1105                                         "', CurrentDirectory='" + startInfo.WorkingDirectory +
1106                                         "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
1107                         }
1108
1109                         process.process_handle = proc_info.process_handle;
1110                         process.pid = proc_info.pid;
1111                         
1112                         if (startInfo.RedirectStandardInput == true) {
1113                                 MonoIO.Close (stdin_rd, out error);
1114                                 process.input_stream = new StreamWriter (new MonoSyncFileStream (stdin_wr, FileAccess.Write, true, 8192), Console.Out.Encoding);
1115                                 process.input_stream.AutoFlush = true;
1116                         }
1117
1118                         Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1119                         Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1120
1121                         if (startInfo.RedirectStandardOutput == true) {
1122                                 MonoIO.Close (stdout_wr, out error);
1123                                 process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding, true, 8192);
1124                         }
1125
1126                         if (startInfo.RedirectStandardError == true) {
1127                                 MonoIO.Close (stderr_wr, out error);
1128                                 process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding, true, 8192);
1129                         }
1130
1131                         process.StartExitCallbackIfNeeded ();
1132
1133                         return(ret);
1134                 }
1135
1136                 // Note that ProcInfo.Password must be freed.
1137                 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1138                 {
1139                         if (startInfo.UserName != null) {
1140                                 proc_info.UserName = startInfo.UserName;
1141                                 proc_info.Domain = startInfo.Domain;
1142                                 if (startInfo.Password != null)
1143                                         proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1144                                 else
1145                                         proc_info.Password = IntPtr.Zero;
1146                                 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1147                         }
1148                 }
1149
1150                 private static bool Start_common (ProcessStartInfo startInfo,
1151                                                   Process process)
1152                 {
1153                         if (startInfo.FileName == null || startInfo.FileName.Length == 0)
1154                                 throw new InvalidOperationException("File name has not been set");
1155                         
1156                         if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1157                                 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1158                         if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1159                                 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1160                         
1161                         if (startInfo.UseShellExecute) {
1162                                 if (!String.IsNullOrEmpty (startInfo.UserName))
1163                                         throw new InvalidOperationException ("UseShellExecute must be false if an explicit UserName is specified when starting a process");
1164                                 return (Start_shell (startInfo, process));
1165                         } else {
1166                                 return (Start_noshell (startInfo, process));
1167                         }
1168                 }
1169                 
1170                 public bool Start ()
1171                 {
1172                         if (process_handle != IntPtr.Zero) {
1173                                 Process_free_internal (process_handle);
1174                                 process_handle = IntPtr.Zero;
1175                         }
1176                         return Start_common(start_info, this);
1177                 }
1178
1179                 public static Process Start (ProcessStartInfo startInfo)
1180                 {
1181                         if (startInfo == null)
1182                                 throw new ArgumentNullException ("startInfo");
1183
1184                         Process process = new Process();
1185                         process.StartInfo = startInfo;
1186                         if (Start_common(startInfo, process) && process.process_handle != IntPtr.Zero)
1187                                 return process;
1188                         return null;
1189                 }
1190
1191                 public static Process Start (string fileName)
1192                 {
1193                         return Start (new ProcessStartInfo (fileName));
1194                 }
1195
1196                 public static Process Start(string fileName, string arguments)
1197                 {
1198                         return Start (new ProcessStartInfo (fileName, arguments));
1199                 }
1200
1201                 public static Process Start(string fileName, string username, SecureString password, string domain) {
1202                         return Start(fileName, null, username, password, domain);
1203                 }
1204
1205                 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1206                         ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1207                         psi.UserName = username;
1208                         psi.Password = password;
1209                         psi.Domain = domain;
1210                         psi.UseShellExecute = false;
1211                         return Start(psi);
1212                 }
1213
1214                 public override string ToString()
1215                 {
1216                         return(base.ToString() + " (" + this.ProcessName + ")");
1217                 }
1218
1219                 /* Waits up to ms milliseconds for process 'handle' to
1220                  * exit.  ms can be <0 to mean wait forever.
1221                  */
1222                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1223                 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1224
1225                 public void WaitForExit ()
1226                 {
1227                         WaitForExit (-1);
1228                 }
1229
1230                 public bool WaitForExit(int milliseconds) {
1231                         int ms = milliseconds;
1232                         if (ms == int.MaxValue)
1233                                 ms = -1;
1234
1235                         if (process_handle == IntPtr.Zero)
1236                                 throw new InvalidOperationException ("No process is associated with this object.");
1237
1238
1239                         DateTime start = DateTime.UtcNow;
1240                         if (async_output != null && !async_output.IsCompleted) {
1241                                 if (false == async_output.WaitHandle.WaitOne (ms, false))
1242                                         return false; // Timed out
1243
1244                                 if (ms >= 0) {
1245                                         DateTime now = DateTime.UtcNow;
1246                                         ms -= (int) (now - start).TotalMilliseconds;
1247                                         if (ms <= 0)
1248                                                 return false;
1249                                         start = now;
1250                                 }
1251                         }
1252
1253                         if (async_error != null && !async_error.IsCompleted) {
1254                                 if (false == async_error.WaitHandle.WaitOne (ms, false))
1255                                         return false; // Timed out
1256
1257                                 if (ms >= 0) {
1258                                         ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1259                                         if (ms <= 0)
1260                                                 return false;
1261                                 }
1262                         }
1263                         return WaitForExit_internal (process_handle, ms);
1264                 }
1265
1266                 /* Waits up to ms milliseconds for process 'handle' to 
1267                  * wait for input.  ms can be <0 to mean wait forever.
1268                  */
1269                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1270                 private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
1271
1272                 // The internal call is only implemented properly on Windows.
1273                 [MonoTODO]
1274                 public bool WaitForInputIdle() {
1275                         return WaitForInputIdle (-1);
1276                 }
1277
1278                 // The internal call is only implemented properly on Windows.
1279                 [MonoTODO]
1280                 public bool WaitForInputIdle(int milliseconds) {
1281                         return WaitForInputIdle_internal (process_handle, milliseconds);
1282                 }
1283
1284                 private static bool IsLocalMachine (string machineName)
1285                 {
1286                         if (machineName == "." || machineName.Length == 0)
1287                                 return true;
1288
1289                         return (string.Compare (machineName, Environment.MachineName, true) == 0);
1290                 }
1291
1292                 [Browsable (true)]
1293                 [MonitoringDescription ("Raised when it receives output data")]
1294                 public event DataReceivedEventHandler OutputDataReceived;
1295                 [Browsable (true)]
1296                 [MonitoringDescription ("Raised when it receives error data")]
1297                 public event DataReceivedEventHandler ErrorDataReceived;
1298
1299                 void OnOutputDataReceived (string str)
1300                 {
1301                         if (OutputDataReceived != null)
1302                                 OutputDataReceived (this, new DataReceivedEventArgs (str));
1303                 }
1304
1305                 void OnErrorDataReceived (string str)
1306                 {
1307                         if (ErrorDataReceived != null)
1308                                 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1309                 }
1310
1311                 [Flags]
1312                 enum AsyncModes {
1313                         NoneYet = 0,
1314                         SyncOutput = 1,
1315                         SyncError = 1 << 1,
1316                         AsyncOutput = 1 << 2,
1317                         AsyncError = 1 << 3
1318                 }
1319
1320                 [StructLayout (LayoutKind.Sequential)]
1321                 sealed class ProcessAsyncReader
1322                 {
1323                         /*
1324                            The following fields match those of SocketAsyncResult.
1325                            This is so that changes needed in the runtime to handle
1326                            asynchronous reads are trivial
1327                            Keep this in sync with SocketAsyncResult in 
1328                            ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
1329                            in metadata/socket-io.h.
1330                         */
1331                         /* DON'T shuffle fields around. DON'T remove fields */
1332                         public object Sock;
1333                         public IntPtr handle;
1334                         public object state;
1335                         public AsyncCallback callback;
1336                         public ManualResetEvent wait_handle;
1337
1338                         public Exception delayedException;
1339
1340                         public object EndPoint;
1341                         byte [] buffer = new byte [4196];
1342                         public int Offset;
1343                         public int Size;
1344                         public int SockFlags;
1345
1346                         public object AcceptSocket;
1347                         public object[] Addresses;
1348                         public int port;
1349                         public object Buffers;          // Reserve this slot in older profiles
1350                         public bool ReuseSocket;        // Disconnect
1351                         public object acc_socket;
1352                         public int total;
1353                         public bool completed_sync;
1354                         bool completed;
1355                         bool err_out; // true -> stdout, false -> stderr
1356                         internal int error;
1357                         public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1358                         public object ares;
1359                         public int EndCalled;
1360
1361                         // These fields are not in SocketAsyncResult
1362                         Process process;
1363                         Stream stream;
1364                         StringBuilder sb = new StringBuilder ();
1365                         public AsyncReadHandler ReadHandler;
1366
1367                         public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1368                         {
1369                                 this.process = process;
1370                                 this.handle = handle;
1371                                 stream = new FileStream (handle, FileAccess.Read, false);
1372                                 this.ReadHandler = new AsyncReadHandler (AddInput);
1373                                 this.err_out = err_out;
1374                         }
1375
1376                         public void AddInput ()
1377                         {
1378                                 lock (this) {
1379                                         int nread = stream.Read (buffer, 0, buffer.Length);
1380                                         if (nread == 0) {
1381                                                 completed = true;
1382                                                 if (wait_handle != null)
1383                                                         wait_handle.Set ();
1384                                                 FlushLast ();
1385                                                 return;
1386                                         }
1387
1388                                         try {
1389                                                 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1390                                         } catch {
1391                                                 // Just in case the encoding fails...
1392                                                 for (int i = 0; i < nread; i++) {
1393                                                         sb.Append ((char) buffer [i]);
1394                                                 }
1395                                         }
1396
1397                                         Flush (false);
1398                                         ReadHandler.BeginInvoke (null, this);
1399                                 }
1400                         }
1401
1402                         void FlushLast ()
1403                         {
1404                                 Flush (true);
1405                                 if (err_out) {
1406                                         process.OnOutputDataReceived (null);
1407                                 } else {
1408                                         process.OnErrorDataReceived (null);
1409                                 }
1410                         }
1411                         
1412                         void Flush (bool last)
1413                         {
1414                                 if (sb.Length == 0 ||
1415                                     (err_out && process.output_canceled) ||
1416                                     (!err_out && process.error_canceled))
1417                                         return;
1418
1419                                 string total = sb.ToString ();
1420                                 sb.Length = 0;
1421                                 string [] strs = total.Split ('\n');
1422                                 int len = strs.Length;
1423                                 if (len == 0)
1424                                         return;
1425
1426                                 for (int i = 0; i < len - 1; i++) {
1427                                         if (err_out)
1428                                                 process.OnOutputDataReceived (strs [i]);
1429                                         else
1430                                                 process.OnErrorDataReceived (strs [i]);
1431                                 }
1432
1433                                 string end = strs [len - 1];
1434                                 if (last || (len == 1 && end == "")) {
1435                                         if (err_out) {
1436                                                 process.OnOutputDataReceived (end);
1437                                         } else {
1438                                                 process.OnErrorDataReceived (end);
1439                                         }
1440                                 } else {
1441                                         sb.Append (end);
1442                                 }
1443                         }
1444
1445                         public bool IsCompleted {
1446                                 get { return completed; }
1447                         }
1448
1449                         public WaitHandle WaitHandle {
1450                                 get {
1451                                         lock (this) {
1452                                                 if (wait_handle == null)
1453                                                         wait_handle = new ManualResetEvent (completed);
1454                                                 return wait_handle;
1455                                         }
1456                                 }
1457                         }
1458
1459                         public void Close () {
1460                                 stream.Close ();
1461                         }
1462                 }
1463
1464                 AsyncModes async_mode;
1465                 bool output_canceled;
1466                 bool error_canceled;
1467                 ProcessAsyncReader async_output;
1468                 ProcessAsyncReader async_error;
1469                 delegate void AsyncReadHandler ();
1470
1471                 [ComVisibleAttribute(false)] 
1472                 public void BeginOutputReadLine ()
1473                 {
1474                         if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1475                                 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1476
1477                         if ((async_mode & AsyncModes.SyncOutput) != 0)
1478                                 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1479
1480                         async_mode |= AsyncModes.AsyncOutput;
1481                         output_canceled = false;
1482                         if (async_output == null) {
1483                                 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1484                                 async_output.ReadHandler.BeginInvoke (null, async_output);
1485                         }
1486                 }
1487
1488                 [ComVisibleAttribute(false)] 
1489                 public void CancelOutputRead ()
1490                 {
1491                         if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1492                                 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1493
1494                         if ((async_mode & AsyncModes.SyncOutput) != 0)
1495                                 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1496
1497                         if (async_output == null)
1498                                 throw new InvalidOperationException ("No async operation in progress.");
1499
1500                         output_canceled = true;
1501                 }
1502
1503                 [ComVisibleAttribute(false)] 
1504                 public void BeginErrorReadLine ()
1505                 {
1506                         if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1507                                 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1508
1509                         if ((async_mode & AsyncModes.SyncError) != 0)
1510                                 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1511
1512                         async_mode |= AsyncModes.AsyncError;
1513                         error_canceled = false;
1514                         if (async_error == null) {
1515                                 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1516                                 async_error.ReadHandler.BeginInvoke (null, async_error);
1517                         }
1518                 }
1519
1520                 [ComVisibleAttribute(false)] 
1521                 public void CancelErrorRead ()
1522                 {
1523                         if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1524                                 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1525
1526                         if ((async_mode & AsyncModes.SyncOutput) != 0)
1527                                 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1528
1529                         if (async_error == null)
1530                                 throw new InvalidOperationException ("No async operation in progress.");
1531
1532                         error_canceled = true;
1533                 }
1534
1535                 [Category ("Behavior")]
1536                 [MonitoringDescription ("Raised when this process exits.")]
1537                 public event EventHandler Exited {
1538                         add {
1539                                 if (process_handle != IntPtr.Zero && HasExited) {
1540                                         value.BeginInvoke (null, null, null, null);
1541                                 } else {
1542                                         exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1543                                         if (exited_event != null)
1544                                                 StartExitCallbackIfNeeded ();
1545                                 }
1546                         }
1547                         remove {
1548                                 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1549                         }
1550                 }
1551
1552                 // Closes the system process handle
1553                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1554                 private extern void Process_free_internal(IntPtr handle);
1555                 
1556                 private bool disposed = false;
1557                 
1558                 protected override void Dispose(bool disposing) {
1559                         // Check to see if Dispose has already been called.
1560                         if(this.disposed == false) {
1561                                 this.disposed=true;
1562                                 // If this is a call to Dispose,
1563                                 // dispose all managed resources.
1564                                 if(disposing) {
1565                                         // Do stuff here
1566                                         lock (this) {
1567                                                 /* These have open FileStreams on the pipes we are about to close */
1568                                                 if (async_output != null)
1569                                                         async_output.Close ();
1570                                                 if (async_error != null)
1571                                                         async_error.Close ();
1572
1573                                                 if (input_stream != null) {
1574                                                         input_stream.Close();
1575                                                         input_stream = null;
1576                                                 }
1577
1578                                                 if (output_stream != null) {
1579                                                         output_stream.Close();
1580                                                         output_stream = null;
1581                                                 }
1582
1583                                                 if (error_stream != null) {
1584                                                         error_stream.Close();
1585                                                         error_stream = null;
1586                                                 }
1587                                         }
1588                                 }
1589                                 
1590                                 // Release unmanaged resources
1591
1592                                 lock(this) {
1593                                         if(process_handle!=IntPtr.Zero) {
1594                                                 Process_free_internal(process_handle);
1595                                                 process_handle=IntPtr.Zero;
1596                                         }
1597                                 }
1598                         }
1599                         base.Dispose (disposing);
1600                 }
1601
1602                 ~Process ()
1603                 {
1604                         Dispose (false);
1605                 }
1606
1607                 static void CBOnExit (object state, bool unused)
1608                 {
1609                         Process p = (Process) state;
1610                         p.already_waiting = false;
1611                         p.OnExited ();
1612                 }
1613
1614                 protected void OnExited() 
1615                 {
1616                         if (exited_event == null)
1617                                 return;
1618
1619                         if (synchronizingObject == null) {
1620                                 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1621                                         try {
1622                                                 d (this, EventArgs.Empty);
1623                                         } catch {}
1624                                 }
1625                                 return;
1626                         }
1627                         
1628                         object [] args = new object [] {this, EventArgs.Empty};
1629                         synchronizingObject.BeginInvoke (exited_event, args);
1630                 }
1631
1632                 static bool IsWindows
1633                 {
1634                         get
1635                         {
1636                                 PlatformID platform = Environment.OSVersion.Platform;
1637                                 if (platform == PlatformID.Win32S ||
1638                                         platform == PlatformID.Win32Windows ||
1639                                         platform == PlatformID.Win32NT ||
1640                                         platform == PlatformID.WinCE) {
1641                                         return true;
1642                                 }
1643                                 return false;
1644                         }
1645                 }
1646
1647                 class ProcessWaitHandle : WaitHandle
1648                 {
1649                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
1650                         private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1651                         
1652                         public ProcessWaitHandle (IntPtr handle)
1653                         {
1654                                 // Need to keep a reference to this handle,
1655                                 // in case the Process object is collected
1656                                 Handle = ProcessHandle_duplicate (handle);
1657
1658                                 // When the wait handle is disposed, the duplicated handle will be
1659                                 // closed, so no need to override dispose (bug #464628).
1660                         }
1661                 }
1662         }
1663 }
1664