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