Merge pull request #3809 from lateralusX/jlorenss/win-api-family-support-cleanup
[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;
47 using Microsoft.Win32.SafeHandles;
48
49 namespace System.Diagnostics
50 {
51         public partial class Process : Component 
52         {
53                 [StructLayout(LayoutKind.Sequential)]
54                 private struct ProcInfo 
55                 {
56                         public IntPtr process_handle;
57                         /* If thread_handle is ever needed for
58                          * something, take out the CloseHandle() in
59                          * the Start_internal icall in
60                          * mono/metadata/process.c
61                          */
62                         public IntPtr thread_handle;
63                         public int pid; // Contains -GetLastError () on failure.
64                         public int tid;
65                         public string [] envKeys;
66                         public string [] envValues;
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 proc_info);
530
531                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
532                 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo, IntPtr stdin, IntPtr stdout, IntPtr stderr, ref ProcInfo proc_info);
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 proc_info = new ProcInfo();
556                         bool ret;
557
558                         FillUserInfo (startInfo, ref proc_info);
559                         try {
560                                 ret = ShellExecuteEx_internal (startInfo, ref proc_info);
561                         } finally {
562                                 if (proc_info.Password != IntPtr.Zero)
563                                         Marshal.ZeroFreeBSTR (proc_info.Password);
564                                 proc_info.Password = IntPtr.Zero;
565                         }
566                         if (!ret) {
567                                 throw new Win32Exception (-proc_info.pid);
568                         }
569
570                         SetProcessHandle (new SafeProcessHandle (proc_info.process_handle, true));
571                         SetProcessId (proc_info.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 proc_info = new ProcInfo ();
652
653                         if (startInfo.HaveEnvVars) {
654                                 string [] strs = new string [startInfo.EnvironmentVariables.Count];
655                                 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
656                                 proc_info.envKeys = strs;
657
658                                 strs = new string [startInfo.EnvironmentVariables.Count];
659                                 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
660                                 proc_info.envValues = strs;
661                         }
662
663                         MonoIOError error;
664                         IntPtr stdin_read = IntPtr.Zero, stdin_write = IntPtr.Zero;
665                         IntPtr stdout_read = IntPtr.Zero, stdout_write = IntPtr.Zero;
666                         IntPtr stderr_read = IntPtr.Zero, stderr_write = IntPtr.Zero;
667
668                         try {
669                                 if (startInfo.RedirectStandardInput) {
670                                         CreatePipe (out stdin_read, out stdin_write, true);
671                                 } else {
672                                         stdin_read = MonoIO.ConsoleInput;
673                                         stdin_write = IntPtr.Zero;
674                                 }
675
676                                 if (startInfo.RedirectStandardOutput) {
677                                         CreatePipe (out stdout_read, out stdout_write, false);
678                                 } else {
679                                         stdout_read = IntPtr.Zero;
680                                         stdout_write = MonoIO.ConsoleOutput;
681                                 }
682
683                                 if (startInfo.RedirectStandardError) {
684                                         CreatePipe (out stderr_read, out stderr_write, false);
685                                 } else {
686                                         stderr_read = IntPtr.Zero;
687                                         stderr_write = MonoIO.ConsoleError;
688                                 }
689
690                                 FillUserInfo (startInfo, ref proc_info);
691
692                                 //
693                                 // FIXME: For redirected pipes we need to send descriptors of
694                                 // stdin_write, stdout_read, stderr_read to child process and
695                                 // close them there (fork makes exact copy of parent's descriptors)
696                                 //
697                                 if (!CreateProcess_internal (startInfo, stdin_read, stdout_write, stderr_write, ref proc_info)) {
698                                         throw new Win32Exception (-proc_info.pid, "ApplicationName='" + startInfo.FileName + "', CommandLine='" + startInfo.Arguments +
699                                                 "', CurrentDirectory='" + startInfo.WorkingDirectory + "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
700                                 }
701                         } catch {
702                                 if (startInfo.RedirectStandardInput) {
703                                         if (stdin_read != IntPtr.Zero)
704                                                 MonoIO.Close (stdin_read, out error);
705                                         if (stdin_write != IntPtr.Zero)
706                                                 MonoIO.Close (stdin_write, out error);
707                                 }
708
709                                 if (startInfo.RedirectStandardOutput) {
710                                         if (stdout_read != IntPtr.Zero)
711                                                 MonoIO.Close (stdout_read, out error);
712                                         if (stdout_write != IntPtr.Zero)
713                                                 MonoIO.Close (stdout_write, out error);
714                                 }
715
716                                 if (startInfo.RedirectStandardError) {
717                                         if (stderr_read != IntPtr.Zero)
718                                                 MonoIO.Close (stderr_read, out error);
719                                         if (stderr_write != IntPtr.Zero)
720                                                 MonoIO.Close (stderr_write, out error);
721                                 }
722
723                                 throw;
724                         } finally {
725                                 if (proc_info.Password != IntPtr.Zero) {
726                                         Marshal.ZeroFreeBSTR (proc_info.Password);
727                                         proc_info.Password = IntPtr.Zero;
728                                 }
729                         }
730
731                         SetProcessHandle (new SafeProcessHandle (proc_info.process_handle, true));
732                         SetProcessId (proc_info.pid);
733                         
734                         if (startInfo.RedirectStandardInput) {
735                                 MonoIO.Close (stdin_read, out error);
736
737 #if MOBILE
738                                 var stdinEncoding = Encoding.Default;
739 #else
740                                 var stdinEncoding = Console.InputEncoding;
741 #endif
742                                 standardInput = new StreamWriter (new FileStream (stdin_write, FileAccess.Write, true, 8192), stdinEncoding) {
743                                         AutoFlush = true
744                                 };
745                         }
746
747                         if (startInfo.RedirectStandardOutput) {
748                                 MonoIO.Close (stdout_write, out error);
749
750                                 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
751
752                                 standardOutput = new StreamReader (new FileStream (stdout_read, FileAccess.Read, true, 8192), stdoutEncoding, true);
753                         }
754
755                         if (startInfo.RedirectStandardError) {
756                                 MonoIO.Close (stderr_write, out error);
757
758                                 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
759
760                                 standardError = new StreamReader (new FileStream (stderr_read, FileAccess.Read, true, 8192), stderrEncoding, true);
761                         }
762
763                         return true;
764                 }
765
766                 // Note that ProcInfo.Password must be freed.
767                 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
768                 {
769                         if (startInfo.UserName.Length != 0) {
770                                 proc_info.UserName = startInfo.UserName;
771                                 proc_info.Domain = startInfo.Domain;
772                                 if (startInfo.Password != null)
773                                         proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
774                                 else
775                                         proc_info.Password = IntPtr.Zero;
776                                 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
777                         }
778                 }
779 #else
780                 [Obsolete ("Process.Start is not supported on the current platform.", true)]
781                 public bool Start ()
782                 {
783                         throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
784                 }
785
786                 [Obsolete ("Process.Start is not supported on the current platform.", true)]
787                 public static Process Start (ProcessStartInfo startInfo)
788                 {
789                         throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
790                 }
791
792                 [Obsolete ("Process.Start is not supported on the current platform.", true)]
793                 public static Process Start (string fileName)
794                 {
795                         throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
796                 }
797
798                 [Obsolete ("Process.Start is not supported on the current platform.", true)]
799                 public static Process Start(string fileName, string arguments)
800                 {
801                         throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
802                 }
803
804                 [Obsolete ("Process.Start is not supported on the current platform.", true)]
805                 public static Process Start(string fileName, string username, SecureString password, string domain)
806                 {
807                         throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
808                 }
809
810                 [Obsolete ("Process.Start is not supported on the current platform.", true)]
811                 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain)
812                 {
813                         throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
814                 }
815 #endif // MONO_FEATURE_PROCESS_START
816
817 #if !MONO_FEATURE_PROCESS_START
818                 [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
819                 public void BeginOutputReadLine ()
820                 {
821                         throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
822                 }
823
824                 [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
825                 public void CancelOutputRead ()
826                 {
827                         throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
828                 }
829
830                 [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
831                 public void BeginErrorReadLine ()
832                 {
833                         throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
834                 }
835
836                 [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
837                 public void CancelErrorRead ()
838                 {
839                         throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
840                 }
841 #endif // !MONO_FEATURE_PROCESS_START
842
843                 /// <devdoc>
844                 ///     Raise the Exited event, but make sure we don't do it more than once.
845                 /// </devdoc>
846                 /// <internalonly/>
847                 void RaiseOnExited() {
848                         if (!watchForExit)
849                                 return;
850                         if (!raisedOnExited) {
851                                 lock (this) {
852                                         if (!raisedOnExited) {
853                                                 raisedOnExited = true;
854                                                 OnExited();
855                                         }
856                                 }
857                         }
858                 }
859         }
860 }
861