26a5c1ba93daabd7080b7d03f3bb283cf9a8e9c2
[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.Collections;
38 using System.ComponentModel;
39 using System.ComponentModel.Design;
40 using System.Runtime.CompilerServices;
41 using System.Runtime.InteropServices;
42 using System.Runtime.Remoting.Messaging;
43 using System.Security.Permissions;
44 using System.Collections.Generic;
45 using System.Security;
46 using System.Threading;
47 using Microsoft.Win32;
48 using Microsoft.Win32.SafeHandles;
49
50 namespace System.Diagnostics
51 {
52         public partial class Process : Component 
53         {
54                 [StructLayout(LayoutKind.Sequential)]
55                 private struct ProcInfo 
56                 {
57                         public IntPtr process_handle;
58                         /* If thread_handle is ever needed for
59                          * something, take out the CloseHandle() in
60                          * the Start_internal icall in
61                          * mono/metadata/process.c
62                          */
63                         public IntPtr thread_handle;
64                         public int pid; // Contains -GetLastError () on failure.
65                         public int tid;
66                         public string[] envVariables;
67                         public string UserName;
68                         public string Domain;
69                         public IntPtr Password;
70                         public bool LoadUserProfile;
71                 };
72
73                 string process_name;
74
75                 /* Private constructor called from other methods */
76                 private Process (SafeProcessHandle handle, int id) {
77                         SetProcessHandle (handle);
78                         SetProcessId (id);
79                 }
80
81                 [MonoTODO]
82                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
83                 [MonitoringDescription ("Base process priority.")]
84                 public int BasePriority {
85                         get { return 0; }
86                 }
87
88                 [MonoTODO]
89                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
90                 [MonitoringDescription ("Handles for this process.")]
91                 public int HandleCount {
92                         get {
93                                 return(0);
94                         }
95                 }
96
97                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
98                 [MonitoringDescription ("The main module of the process.")]
99                 public ProcessModule MainModule {
100                         get {
101                                 return(this.Modules[0]);
102                         }
103                 }
104
105                 [MonoTODO]
106                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
107                 [MonitoringDescription ("The handle of the main window of the process.")]
108                 public IntPtr MainWindowHandle {
109                         get {
110                                 return((IntPtr)0);
111                         }
112                 }
113
114                 [MonoTODO]
115                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
116                 [MonitoringDescription ("The title of the main window of the process.")]
117                 public string MainWindowTitle {
118                         get {
119                                 return("null");
120                         }
121                 }
122
123                 /* Returns the list of process modules.  The main module is
124                  * element 0.
125                  */
126                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
127                 private extern ProcessModule[] GetModules_internal(IntPtr handle);
128
129                 ProcessModule[] GetModules_internal (SafeProcessHandle handle)
130                 {
131                         bool release = false;
132                         try {
133                                 handle.DangerousAddRef (ref release);
134                                 return GetModules_internal (handle.DangerousGetHandle ());
135                         } finally {
136                                 if (release)
137                                         handle.DangerousRelease ();
138                         }
139                 }
140
141                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
142                 [MonitoringDescription ("The modules that are loaded as part of this process.")]
143                 public ProcessModuleCollection Modules {
144                         get {
145                                 if (modules == null) {
146                                         SafeProcessHandle handle = null;
147                                         try {
148                                                 handle = GetProcessHandle (NativeMethods.PROCESS_QUERY_INFORMATION);
149                                                 modules = new ProcessModuleCollection (GetModules_internal (handle));
150                                         } finally {
151                                                 ReleaseProcessHandle (handle);
152                                         }
153                                 }
154
155                                 return modules;
156                         }
157                 }
158
159                 /* data type is from the MonoProcessData enum in mono-proclib.h in the runtime */
160                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
161                 private extern static long GetProcessData (int pid, int data_type, out int error);
162
163                 [MonoTODO]
164                 [Obsolete ("Use NonpagedSystemMemorySize64")]
165                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
166                 [MonitoringDescription ("The number of bytes that are not pageable.")]
167                 public int NonpagedSystemMemorySize {
168                         get {
169                                 return(0);
170                         }
171                 }
172
173                 [Obsolete ("Use PagedMemorySize64")]
174                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
175                 [MonitoringDescription ("The number of bytes that are paged.")]
176                 public int PagedMemorySize {
177                         get {
178                                 return(int)PagedMemorySize64;
179                         }
180                 }
181
182                 [Obsolete ("Use PagedSystemMemorySize64")]
183                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
184                 [MonitoringDescription ("The amount of paged system memory in bytes.")]
185                 public int PagedSystemMemorySize {
186                         get {
187                                 return(int)PagedMemorySize64;
188                         }
189                 }
190
191                 [MonoTODO]
192                 [Obsolete ("Use PeakPagedMemorySize64")]
193                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
194                 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
195                 public int PeakPagedMemorySize {
196                         get {
197                                 return(0);
198                         }
199                 }
200
201                 [Obsolete ("Use PeakVirtualMemorySize64")]
202                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
203                 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
204                 public int PeakVirtualMemorySize {
205                         get {
206                                 int error;
207                                 return (int)GetProcessData (processId, 8, out error);
208                         }
209                 }
210
211                 [Obsolete ("Use PeakWorkingSet64")]
212                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
213                 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
214                 public int PeakWorkingSet {
215                         get {
216                                 int error;
217                                 return (int)GetProcessData (processId, 5, out error);
218                         }
219                 }
220
221                 [MonoTODO]
222                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
223                 [MonitoringDescription ("The number of bytes that are not pageable.")]
224                 [ComVisible (false)]
225                 public long NonpagedSystemMemorySize64 {
226                         get {
227                                 return(0);
228                         }
229                 }
230
231                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
232                 [MonitoringDescription ("The number of bytes that are paged.")]
233                 [ComVisible (false)]
234                 public long PagedMemorySize64 {
235                         get {
236                                 int error;
237                                 return GetProcessData (processId, 12, out error);
238                         }
239                 }
240
241                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
242                 [MonitoringDescription ("The amount of paged system memory in bytes.")]
243                 [ComVisible (false)]
244                 public long PagedSystemMemorySize64 {
245                         get {
246                                 return PagedMemorySize64;
247                         }
248                 }
249
250                 [MonoTODO]
251                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
252                 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
253                 [ComVisible (false)]
254                 public long PeakPagedMemorySize64 {
255                         get {
256                                 return(0);
257                         }
258                 }
259
260                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
261                 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
262                 [ComVisible (false)]
263                 public long PeakVirtualMemorySize64 {
264                         get {
265                                 int error;
266                                 return GetProcessData (processId, 8, out error);
267                         }
268                 }
269
270                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
271                 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
272                 [ComVisible (false)]
273                 public long PeakWorkingSet64 {
274                         get {
275                                 int error;
276                                 return GetProcessData (processId, 5, out error);
277                         }
278                 }
279
280                 [MonoTODO]
281                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
282                 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
283                 public bool PriorityBoostEnabled {
284                         get {
285                                 return(false);
286                         }
287                         set {
288                         }
289                 }
290
291                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
292                 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
293                 [Obsolete ("Use PrivateMemorySize64")]
294                 public int PrivateMemorySize {
295                         get {
296                                 int error;
297                                 return (int)GetProcessData (processId, 6, out error);
298                         }
299                 }
300
301                 [MonoNotSupported ("")]
302                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
303                 [MonitoringDescription ("The session ID for this process.")]
304                 public int SessionId {
305                         get { return 0; }
306                 }
307
308                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
309                 private extern static string ProcessName_internal(IntPtr handle);
310
311                 static string ProcessName_internal(SafeProcessHandle handle)
312                 {
313                         bool release = false;
314                         try {
315                                 handle.DangerousAddRef (ref release);
316                                 return ProcessName_internal (handle.DangerousGetHandle ());
317                         } finally {
318                                 if (release)
319                                         handle.DangerousRelease ();
320                         }
321                 }
322
323                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
324                 [MonitoringDescription ("The name of this process.")]
325                 public string ProcessName {
326                         get {
327                                 if (process_name == null) {
328                                         SafeProcessHandle handle = null;
329                                         try {
330                                                 handle = GetProcessHandle (NativeMethods.PROCESS_QUERY_INFORMATION);
331
332                                                 process_name = ProcessName_internal (handle);
333
334                                                 /* If process_name is _still_ null, assume the process has exited */
335                                                 if (process_name == null)
336                                                         throw new InvalidOperationException ("Process has exited, so the requested information is not available.");
337
338                                                 /* Strip the suffix (if it exists) simplistically instead of removing
339                                                  * any trailing \.???, so we dont get stupid results on sane systems */
340                                                 if(process_name.EndsWith(".exe") || process_name.EndsWith(".bat") || process_name.EndsWith(".com"))
341                                                         process_name = process_name.Substring (0, process_name.Length - 4);
342                                         } finally {
343                                                 ReleaseProcessHandle (handle);
344                                         }
345                                 }
346                                 return process_name;
347                         }
348                 }
349
350                 [MonoTODO]
351                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
352                 [MonitoringDescription ("Allowed processor that can be used by this process.")]
353                 public IntPtr ProcessorAffinity {
354                         get {
355                                 return((IntPtr)0);
356                         }
357                         set {
358                         }
359                 }
360
361                 [MonoTODO]
362                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
363                 [MonitoringDescription ("Is this process responsive.")]
364                 public bool Responding {
365                         get {
366                                 return(false);
367                         }
368                 }
369
370 #if !MONO_FEATURE_PROCESS_START
371                 [Obsolete ("Process.StartInfo is not supported on the current platform.", true)]
372                 public ProcessStartInfo StartInfo {
373                         get { throw new PlatformNotSupportedException ("Process.StartInfo is not supported on the current platform."); }
374                         set { throw new PlatformNotSupportedException ("Process.StartInfo is not supported on the current platform."); }
375                 }
376
377                 [Obsolete ("Process.StandardError is not supported on the current platform.", true)]
378                 public StreamReader StandardError {
379                         get { throw new PlatformNotSupportedException ("Process.StandardError is not supported on the current platform."); }
380                 }
381
382                 [Obsolete ("Process.StandardInput is not supported on the current platform.", true)]
383                 public StreamWriter StandardInput {
384                         get { throw new PlatformNotSupportedException ("Process.StandardInput is not supported on the current platform."); }
385                 }
386
387                 [Obsolete ("Process.StandardOutput is not supported on the current platform.", true)]
388                 public StreamReader StandardOutput {
389                         get { throw new PlatformNotSupportedException ("Process.StandardOutput is not supported on the current platform."); }
390                 }
391 #endif // !MONO_FEATURE_PROCESS_START
392
393                 [MonoTODO]
394                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
395                 [MonitoringDescription ("The number of threads of this process.")]
396                 public ProcessThreadCollection Threads {
397                         get {
398                                 if (threads == null) {
399                                         int error;
400                                         // This'll return a correctly-sized array of empty ProcessThreads for now.
401                                         threads = new ProcessThreadCollection(new ProcessThread [GetProcessData (processId, 0, out error)]);
402                                 }
403
404                                 return threads;
405                         }
406                 }
407
408                 [Obsolete ("Use VirtualMemorySize64")]
409                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
410                 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
411                 public int VirtualMemorySize {
412                         get {
413                                 int error;
414                                 return (int)GetProcessData (processId, 7, out error);
415                         }
416                 }
417
418                 [Obsolete ("Use WorkingSet64")]
419                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
420                 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
421                 public int WorkingSet {
422                         get {
423                                 int error;
424                                 return (int)GetProcessData (processId, 4, out error);
425                         }
426                 }
427
428                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
429                 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
430                 [ComVisible (false)]
431                 public long PrivateMemorySize64 {
432                         get {
433                                 int error;
434                                 return GetProcessData (processId, 6, out error);
435                         }
436                 }
437
438                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
439                 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
440                 [ComVisible (false)]
441                 public long VirtualMemorySize64 {
442                         get {
443                                 int error;
444                                 return GetProcessData (processId, 7, out error);
445                         }
446                 }
447
448                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
449                 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
450                 [ComVisible (false)]
451                 public long WorkingSet64 {
452                         get {
453                                 int error;
454                                 return GetProcessData (processId, 4, out error);
455                         }
456                 }
457
458                 public bool CloseMainWindow ()
459                 {
460                         SafeProcessHandle handle = null;
461                         try {
462                                 handle = GetProcessHandle (NativeMethods.PROCESS_TERMINATE);
463                                 return NativeMethods.TerminateProcess(handle, -2);
464                         } finally {
465                                 ReleaseProcessHandle(handle);
466                         }
467                 }
468
469                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
470                 private extern static IntPtr GetProcess_internal(int pid);
471
472                 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
473                 public static Process GetProcessById(int processId, string machineName) {
474                         if (machineName == null)
475                                 throw new ArgumentNullException ("machineName");
476
477                         if (!IsLocalMachine (machineName))
478                                 throw new NotImplementedException ();
479
480                         IntPtr proc = GetProcess_internal(processId);
481
482                         if (proc == IntPtr.Zero)
483                                 throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
484
485                         return (new Process (new SafeProcessHandle (proc, false), processId));
486                 }
487
488                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
489                 private extern static int[] GetProcesses_internal();
490
491                 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
492                 public static Process[] GetProcesses(string machineName) {
493                         if (machineName == null)
494                                 throw new ArgumentNullException ("machineName");
495
496                         if (!IsLocalMachine (machineName))
497                                 throw new NotImplementedException ();
498
499                         int [] pids = GetProcesses_internal ();
500                         if (pids == null)
501                                 return new Process [0];
502
503                         var proclist = new List<Process> (pids.Length);
504                         for (int i = 0; i < pids.Length; i++) {
505                                 try {
506                                         proclist.Add (GetProcessById (pids [i]));
507                                 } catch (SystemException) {
508                                         /* The process might exit
509                                          * between
510                                          * GetProcesses_internal and
511                                          * GetProcessById
512                                          */
513                                 }
514                         }
515
516                         return proclist.ToArray ();
517                 }
518
519                 private static bool IsLocalMachine (string machineName)
520                 {
521                         if (machineName == "." || machineName.Length == 0)
522                                 return true;
523
524                         return (string.Compare (machineName, Environment.MachineName, true) == 0);
525                 }
526
527 #if MONO_FEATURE_PROCESS_START
528                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
529                 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo, ref ProcInfo procInfo);
530
531                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
532                 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo, IntPtr stdin, IntPtr stdout, IntPtr stderr, ref ProcInfo procInfo);
533
534                 bool StartWithShellExecuteEx (ProcessStartInfo startInfo)
535                 {
536                         if (this.disposed)
537                                 throw new ObjectDisposedException (GetType ().Name);
538
539                         if (!String.IsNullOrEmpty(startInfo.UserName) || (startInfo.Password != null))
540                                 throw new InvalidOperationException(SR.GetString(SR.CantStartAsUser));
541
542                         if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError)
543                                 throw new InvalidOperationException(SR.GetString(SR.CantRedirectStreams));
544
545                         if (startInfo.StandardErrorEncoding != null)
546                                 throw new InvalidOperationException(SR.GetString(SR.StandardErrorEncodingNotAllowed));
547
548                         if (startInfo.StandardOutputEncoding != null)
549                                 throw new InvalidOperationException(SR.GetString(SR.StandardOutputEncodingNotAllowed));
550
551                         // can't set env vars with ShellExecuteEx...
552                         if (startInfo.environmentVariables != null)
553                                 throw new InvalidOperationException(SR.GetString(SR.CantUseEnvVars));
554
555                         ProcInfo procInfo = new ProcInfo();
556                         bool ret;
557
558                         FillUserInfo (startInfo, ref procInfo);
559                         try {
560                                 ret = ShellExecuteEx_internal (startInfo, ref procInfo);
561                         } finally {
562                                 if (procInfo.Password != IntPtr.Zero)
563                                         Marshal.ZeroFreeBSTR (procInfo.Password);
564                                 procInfo.Password = IntPtr.Zero;
565                         }
566                         if (!ret) {
567                                 throw new Win32Exception (-procInfo.pid);
568                         }
569
570                         SetProcessHandle (new SafeProcessHandle (procInfo.process_handle, true));
571                         SetProcessId (procInfo.pid);
572
573                         return ret;
574                 }
575
576                 //
577                 // Creates a pipe with read and write descriptors
578                 //
579                 static void CreatePipe (out IntPtr read, out IntPtr write, bool writeDirection)
580                 {
581                         MonoIOError error;
582
583                         //
584                         // Creates read/write pipe from parent -> child perspective
585                         // a child process uses same descriptors after fork. That's
586                         // 4 descriptors in total where only 2. One in child, one in parent
587                         // should be active and the other 2 closed. Which ones depends on
588                         // comunication direction
589                         //
590                         // parent  -------->  child   (parent can write, child can read)
591                         //
592                         // read: closed       read: used
593                         // write: used        write: closed
594                         //
595                         //
596                         // parent  <--------  child   (parent can read, child can write)
597                         //
598                         // read: used         read: closed
599                         // write: closed      write: used
600                         //
601                         // It can still be tricky for predefined descriptiors http://unixwiz.net/techtips/remap-pipe-fds.html
602                         //
603                         if (!MonoIO.CreatePipe (out read, out write, out error))
604                                 throw MonoIO.GetException (error);
605
606                         if (IsWindows) {
607                                 const int DUPLICATE_SAME_ACCESS = 0x00000002;
608                                 var tmp = writeDirection ? write : read;
609
610                                 if (!MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, tmp, Process.GetCurrentProcess ().Handle, out tmp, 0, 0, DUPLICATE_SAME_ACCESS, out error))
611                                         throw MonoIO.GetException (error);
612
613                                 if (writeDirection) {
614                                         if (!MonoIO.Close (write, out error))
615                                                 throw MonoIO.GetException (error);
616                                         write = tmp;
617                                 } else {
618                                         if (!MonoIO.Close (read, out error))
619                                                 throw MonoIO.GetException (error);
620                                         read = tmp;
621                                 }
622                         }
623                 }
624
625                 static bool IsWindows
626                 {
627                         get
628                         {
629                                 PlatformID platform = Environment.OSVersion.Platform;
630                                 if (platform == PlatformID.Win32S ||
631                                         platform == PlatformID.Win32Windows ||
632                                         platform == PlatformID.Win32NT ||
633                                         platform == PlatformID.WinCE) {
634                                         return true;
635                                 }
636                                 return false;
637                         }
638                 }
639
640                 bool StartWithCreateProcess (ProcessStartInfo startInfo)
641                 {
642                         if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
643                                 throw new InvalidOperationException (SR.GetString(SR.StandardOutputEncodingNotAllowed));
644
645                         if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
646                                 throw new InvalidOperationException (SR.GetString(SR.StandardErrorEncodingNotAllowed));
647
648                         if (this.disposed)
649                                 throw new ObjectDisposedException (GetType ().Name);
650
651                         var procInfo = new ProcInfo ();
652
653                         if (startInfo.HaveEnvVars) {
654                                 List<string> envVariables = null;
655                                 StringBuilder sb = null;
656
657                                 foreach (DictionaryEntry de in startInfo.EnvironmentVariables) {
658                                         if (de.Value == null)
659                                                 continue;
660
661                                         if (envVariables == null)
662                                                 envVariables = new List<string> ();
663
664                                         if (sb == null)
665                                                 sb = new StringBuilder ();
666                                         else
667                                                 sb.Clear ();
668
669                                         sb.Append ((string) de.Key);
670                                         sb.Append ('=');
671                                         sb.Append ((string) de.Value);
672
673                                         envVariables.Add (sb.ToString ());
674                                 }
675
676                                 procInfo.envVariables = envVariables?.ToArray ();
677                         }
678
679                         MonoIOError error;
680                         IntPtr stdin_read = IntPtr.Zero, stdin_write = IntPtr.Zero;
681                         IntPtr stdout_read = IntPtr.Zero, stdout_write = IntPtr.Zero;
682                         IntPtr stderr_read = IntPtr.Zero, stderr_write = IntPtr.Zero;
683
684                         try {
685                                 if (startInfo.RedirectStandardInput) {
686                                         CreatePipe (out stdin_read, out stdin_write, true);
687                                 } else {
688                                         stdin_read = MonoIO.ConsoleInput;
689                                         stdin_write = IntPtr.Zero;
690                                 }
691
692                                 if (startInfo.RedirectStandardOutput) {
693                                         CreatePipe (out stdout_read, out stdout_write, false);
694                                 } else {
695                                         stdout_read = IntPtr.Zero;
696                                         stdout_write = MonoIO.ConsoleOutput;
697                                 }
698
699                                 if (startInfo.RedirectStandardError) {
700                                         CreatePipe (out stderr_read, out stderr_write, false);
701                                 } else {
702                                         stderr_read = IntPtr.Zero;
703                                         stderr_write = MonoIO.ConsoleError;
704                                 }
705
706                                 FillUserInfo (startInfo, ref procInfo);
707
708                                 //
709                                 // FIXME: For redirected pipes we need to send descriptors of
710                                 // stdin_write, stdout_read, stderr_read to child process and
711                                 // close them there (fork makes exact copy of parent's descriptors)
712                                 //
713                                 if (!CreateProcess_internal (startInfo, stdin_read, stdout_write, stderr_write, ref procInfo)) {
714                                         throw new Win32Exception (-procInfo.pid, "ApplicationName='" + startInfo.FileName + "', CommandLine='" + startInfo.Arguments +
715                                                 "', CurrentDirectory='" + startInfo.WorkingDirectory + "', Native error= " + Win32Exception.GetErrorMessage (-procInfo.pid));
716                                 }
717                         } catch {
718                                 if (startInfo.RedirectStandardInput) {
719                                         if (stdin_read != IntPtr.Zero)
720                                                 MonoIO.Close (stdin_read, out error);
721                                         if (stdin_write != IntPtr.Zero)
722                                                 MonoIO.Close (stdin_write, out error);
723                                 }
724
725                                 if (startInfo.RedirectStandardOutput) {
726                                         if (stdout_read != IntPtr.Zero)
727                                                 MonoIO.Close (stdout_read, out error);
728                                         if (stdout_write != IntPtr.Zero)
729                                                 MonoIO.Close (stdout_write, out error);
730                                 }
731
732                                 if (startInfo.RedirectStandardError) {
733                                         if (stderr_read != IntPtr.Zero)
734                                                 MonoIO.Close (stderr_read, out error);
735                                         if (stderr_write != IntPtr.Zero)
736                                                 MonoIO.Close (stderr_write, out error);
737                                 }
738
739                                 throw;
740                         } finally {
741                                 if (procInfo.Password != IntPtr.Zero) {
742                                         Marshal.ZeroFreeBSTR (procInfo.Password);
743                                         procInfo.Password = IntPtr.Zero;
744                                 }
745                         }
746
747                         SetProcessHandle (new SafeProcessHandle (procInfo.process_handle, true));
748                         SetProcessId (procInfo.pid);
749                         
750 #pragma warning disable 618
751
752                         if (startInfo.RedirectStandardInput) {
753                                 MonoIO.Close (stdin_read, out error);
754
755 #if MOBILE
756                                 var stdinEncoding = Encoding.Default;
757 #else
758                                 var stdinEncoding = Console.InputEncoding;
759 #endif
760                                 standardInput = new StreamWriter (new FileStream (stdin_write, FileAccess.Write, true, 8192), stdinEncoding) {
761                                         AutoFlush = true
762                                 };
763                         }
764
765                         if (startInfo.RedirectStandardOutput) {
766                                 MonoIO.Close (stdout_write, out error);
767
768                                 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
769
770                                 standardOutput = new StreamReader (new FileStream (stdout_read, FileAccess.Read, true, 8192), stdoutEncoding, true);
771                         }
772
773                         if (startInfo.RedirectStandardError) {
774                                 MonoIO.Close (stderr_write, out error);
775
776                                 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
777
778                                 standardError = new StreamReader (new FileStream (stderr_read, FileAccess.Read, true, 8192), stderrEncoding, true);
779                         }
780 #pragma warning restore
781
782                         return true;
783                 }
784
785                 // Note that ProcInfo.Password must be freed.
786                 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo procInfo)
787                 {
788                         if (startInfo.UserName.Length != 0) {
789                                 procInfo.UserName = startInfo.UserName;
790                                 procInfo.Domain = startInfo.Domain;
791                                 if (startInfo.Password != null)
792                                         procInfo.Password = Marshal.SecureStringToBSTR (startInfo.Password);
793                                 else
794                                         procInfo.Password = IntPtr.Zero;
795                                 procInfo.LoadUserProfile = startInfo.LoadUserProfile;
796                         }
797                 }
798 #else
799                 [Obsolete ("Process.Start is not supported on the current platform.", true)]
800                 public bool Start ()
801                 {
802                         throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
803                 }
804
805                 [Obsolete ("Process.Start is not supported on the current platform.", true)]
806                 public static Process Start (ProcessStartInfo startInfo)
807                 {
808                         throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
809                 }
810
811                 [Obsolete ("Process.Start is not supported on the current platform.", true)]
812                 public static Process Start (string fileName)
813                 {
814                         throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
815                 }
816
817                 [Obsolete ("Process.Start is not supported on the current platform.", true)]
818                 public static Process Start(string fileName, string arguments)
819                 {
820                         throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
821                 }
822
823                 [Obsolete ("Process.Start is not supported on the current platform.", true)]
824                 public static Process Start(string fileName, string username, SecureString password, string domain)
825                 {
826                         throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
827                 }
828
829                 [Obsolete ("Process.Start is not supported on the current platform.", true)]
830                 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain)
831                 {
832                         throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
833                 }
834 #endif // MONO_FEATURE_PROCESS_START
835
836 #if !MONO_FEATURE_PROCESS_START
837                 [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
838                 public void BeginOutputReadLine ()
839                 {
840                         throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
841                 }
842
843                 [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
844                 public void CancelOutputRead ()
845                 {
846                         throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
847                 }
848
849                 [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
850                 public void BeginErrorReadLine ()
851                 {
852                         throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
853                 }
854
855                 [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
856                 public void CancelErrorRead ()
857                 {
858                         throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
859                 }
860 #endif // !MONO_FEATURE_PROCESS_START
861
862                 /// <devdoc>
863                 ///     Raise the Exited event, but make sure we don't do it more than once.
864                 /// </devdoc>
865                 /// <internalonly/>
866                 void RaiseOnExited() {
867                         if (!watchForExit)
868                                 return;
869                         if (!raisedOnExited) {
870                                 lock (this) {
871                                         if (!raisedOnExited) {
872                                                 raisedOnExited = true;
873                                                 OnExited();
874                                         }
875                                 }
876                         }
877                 }
878         }
879 }
880