[process] Improve error message for inaccessible process (#4354)
[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 or is inaccessible */
335                                                 if (process_name == null)
336                                                         throw new InvalidOperationException ("Process has exited or is inaccessible, 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                 public static Process[] GetProcessesByName(string processName, string machineName)
489                 {
490                         if (machineName == null)
491                                 throw new ArgumentNullException ("machineName");
492
493                         if (!IsLocalMachine (machineName))
494                                 throw new NotImplementedException ();
495
496                         Process[] processes = GetProcesses ();
497                         if (processes.Length == 0)
498                                 return processes;
499
500                         int size = 0;
501
502                         for (int i = 0; i < processes.Length; i++) {
503                                 try {
504                                         if (String.Compare (processName, processes[i].ProcessName, true) == 0)
505                                                 processes [size++] = processes[i];
506                                 } catch (SystemException) {
507                                         /* The process might exit between GetProcesses_internal and GetProcessById */
508                                 }
509                         }
510
511                         Array.Resize<Process> (ref processes, size);
512
513                         return processes;
514                 }
515
516                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
517                 private extern static int[] GetProcesses_internal();
518
519                 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
520                 public static Process[] GetProcesses(string machineName) {
521                         if (machineName == null)
522                                 throw new ArgumentNullException ("machineName");
523
524                         if (!IsLocalMachine (machineName))
525                                 throw new NotImplementedException ();
526
527                         int [] pids = GetProcesses_internal ();
528                         if (pids == null)
529                                 return new Process [0];
530
531                         var proclist = new List<Process> (pids.Length);
532                         for (int i = 0; i < pids.Length; i++) {
533                                 try {
534                                         proclist.Add (GetProcessById (pids [i]));
535                                 } catch (SystemException) {
536                                         /* The process might exit
537                                          * between
538                                          * GetProcesses_internal and
539                                          * GetProcessById
540                                          */
541                                 }
542                         }
543
544                         return proclist.ToArray ();
545                 }
546
547                 private static bool IsLocalMachine (string machineName)
548                 {
549                         if (machineName == "." || machineName.Length == 0)
550                                 return true;
551
552                         return (string.Compare (machineName, Environment.MachineName, true) == 0);
553                 }
554
555 #if MONO_FEATURE_PROCESS_START
556                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
557                 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo, ref ProcInfo procInfo);
558
559                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
560                 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo, IntPtr stdin, IntPtr stdout, IntPtr stderr, ref ProcInfo procInfo);
561
562                 bool StartWithShellExecuteEx (ProcessStartInfo startInfo)
563                 {
564                         if (this.disposed)
565                                 throw new ObjectDisposedException (GetType ().Name);
566
567                         if (!String.IsNullOrEmpty(startInfo.UserName) || (startInfo.Password != null))
568                                 throw new InvalidOperationException(SR.GetString(SR.CantStartAsUser));
569
570                         if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError)
571                                 throw new InvalidOperationException(SR.GetString(SR.CantRedirectStreams));
572
573                         if (startInfo.StandardErrorEncoding != null)
574                                 throw new InvalidOperationException(SR.GetString(SR.StandardErrorEncodingNotAllowed));
575
576                         if (startInfo.StandardOutputEncoding != null)
577                                 throw new InvalidOperationException(SR.GetString(SR.StandardOutputEncodingNotAllowed));
578
579                         // can't set env vars with ShellExecuteEx...
580                         if (startInfo.environmentVariables != null)
581                                 throw new InvalidOperationException(SR.GetString(SR.CantUseEnvVars));
582
583                         ProcInfo procInfo = new ProcInfo();
584                         bool ret;
585
586                         FillUserInfo (startInfo, ref procInfo);
587                         try {
588                                 ret = ShellExecuteEx_internal (startInfo, ref procInfo);
589                         } finally {
590                                 if (procInfo.Password != IntPtr.Zero)
591                                         Marshal.ZeroFreeBSTR (procInfo.Password);
592                                 procInfo.Password = IntPtr.Zero;
593                         }
594                         if (!ret) {
595                                 throw new Win32Exception (-procInfo.pid);
596                         }
597
598                         SetProcessHandle (new SafeProcessHandle (procInfo.process_handle, true));
599                         SetProcessId (procInfo.pid);
600
601                         return ret;
602                 }
603
604                 //
605                 // Creates a pipe with read and write descriptors
606                 //
607                 static void CreatePipe (out IntPtr read, out IntPtr write, bool writeDirection)
608                 {
609                         MonoIOError error;
610
611                         //
612                         // Creates read/write pipe from parent -> child perspective
613                         // a child process uses same descriptors after fork. That's
614                         // 4 descriptors in total where only 2. One in child, one in parent
615                         // should be active and the other 2 closed. Which ones depends on
616                         // comunication direction
617                         //
618                         // parent  -------->  child   (parent can write, child can read)
619                         //
620                         // read: closed       read: used
621                         // write: used        write: closed
622                         //
623                         //
624                         // parent  <--------  child   (parent can read, child can write)
625                         //
626                         // read: used         read: closed
627                         // write: closed      write: used
628                         //
629                         // It can still be tricky for predefined descriptiors http://unixwiz.net/techtips/remap-pipe-fds.html
630                         //
631                         if (!MonoIO.CreatePipe (out read, out write, out error))
632                                 throw MonoIO.GetException (error);
633
634                         if (IsWindows) {
635                                 const int DUPLICATE_SAME_ACCESS = 0x00000002;
636                                 var tmp = writeDirection ? write : read;
637
638                                 if (!MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, tmp, Process.GetCurrentProcess ().Handle, out tmp, 0, 0, DUPLICATE_SAME_ACCESS, out error))
639                                         throw MonoIO.GetException (error);
640
641                                 if (writeDirection) {
642                                         if (!MonoIO.Close (write, out error))
643                                                 throw MonoIO.GetException (error);
644                                         write = tmp;
645                                 } else {
646                                         if (!MonoIO.Close (read, out error))
647                                                 throw MonoIO.GetException (error);
648                                         read = tmp;
649                                 }
650                         }
651                 }
652
653                 static bool IsWindows
654                 {
655                         get
656                         {
657                                 PlatformID platform = Environment.OSVersion.Platform;
658                                 if (platform == PlatformID.Win32S ||
659                                         platform == PlatformID.Win32Windows ||
660                                         platform == PlatformID.Win32NT ||
661                                         platform == PlatformID.WinCE) {
662                                         return true;
663                                 }
664                                 return false;
665                         }
666                 }
667
668                 bool StartWithCreateProcess (ProcessStartInfo startInfo)
669                 {
670                         if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
671                                 throw new InvalidOperationException (SR.GetString(SR.StandardOutputEncodingNotAllowed));
672
673                         if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
674                                 throw new InvalidOperationException (SR.GetString(SR.StandardErrorEncodingNotAllowed));
675
676                         if (this.disposed)
677                                 throw new ObjectDisposedException (GetType ().Name);
678
679                         var procInfo = new ProcInfo ();
680
681                         if (startInfo.HaveEnvVars) {
682                                 List<string> envVariables = null;
683                                 StringBuilder sb = null;
684
685                                 foreach (DictionaryEntry de in startInfo.EnvironmentVariables) {
686                                         if (de.Value == null)
687                                                 continue;
688
689                                         if (envVariables == null)
690                                                 envVariables = new List<string> ();
691
692                                         if (sb == null)
693                                                 sb = new StringBuilder ();
694                                         else
695                                                 sb.Clear ();
696
697                                         sb.Append ((string) de.Key);
698                                         sb.Append ('=');
699                                         sb.Append ((string) de.Value);
700
701                                         envVariables.Add (sb.ToString ());
702                                 }
703
704                                 procInfo.envVariables = envVariables?.ToArray ();
705                         }
706
707                         MonoIOError error;
708                         IntPtr stdin_read = IntPtr.Zero, stdin_write = IntPtr.Zero;
709                         IntPtr stdout_read = IntPtr.Zero, stdout_write = IntPtr.Zero;
710                         IntPtr stderr_read = IntPtr.Zero, stderr_write = IntPtr.Zero;
711
712                         try {
713                                 if (startInfo.RedirectStandardInput) {
714                                         CreatePipe (out stdin_read, out stdin_write, true);
715                                 } else {
716                                         stdin_read = MonoIO.ConsoleInput;
717                                         stdin_write = IntPtr.Zero;
718                                 }
719
720                                 if (startInfo.RedirectStandardOutput) {
721                                         CreatePipe (out stdout_read, out stdout_write, false);
722                                 } else {
723                                         stdout_read = IntPtr.Zero;
724                                         stdout_write = MonoIO.ConsoleOutput;
725                                 }
726
727                                 if (startInfo.RedirectStandardError) {
728                                         CreatePipe (out stderr_read, out stderr_write, false);
729                                 } else {
730                                         stderr_read = IntPtr.Zero;
731                                         stderr_write = MonoIO.ConsoleError;
732                                 }
733
734                                 FillUserInfo (startInfo, ref procInfo);
735
736                                 //
737                                 // FIXME: For redirected pipes we need to send descriptors of
738                                 // stdin_write, stdout_read, stderr_read to child process and
739                                 // close them there (fork makes exact copy of parent's descriptors)
740                                 //
741                                 if (!CreateProcess_internal (startInfo, stdin_read, stdout_write, stderr_write, ref procInfo)) {
742                                         throw new Win32Exception (-procInfo.pid, "ApplicationName='" + startInfo.FileName + "', CommandLine='" + startInfo.Arguments +
743                                                 "', CurrentDirectory='" + startInfo.WorkingDirectory + "', Native error= " + Win32Exception.GetErrorMessage (-procInfo.pid));
744                                 }
745                         } catch {
746                                 if (startInfo.RedirectStandardInput) {
747                                         if (stdin_read != IntPtr.Zero)
748                                                 MonoIO.Close (stdin_read, out error);
749                                         if (stdin_write != IntPtr.Zero)
750                                                 MonoIO.Close (stdin_write, out error);
751                                 }
752
753                                 if (startInfo.RedirectStandardOutput) {
754                                         if (stdout_read != IntPtr.Zero)
755                                                 MonoIO.Close (stdout_read, out error);
756                                         if (stdout_write != IntPtr.Zero)
757                                                 MonoIO.Close (stdout_write, out error);
758                                 }
759
760                                 if (startInfo.RedirectStandardError) {
761                                         if (stderr_read != IntPtr.Zero)
762                                                 MonoIO.Close (stderr_read, out error);
763                                         if (stderr_write != IntPtr.Zero)
764                                                 MonoIO.Close (stderr_write, out error);
765                                 }
766
767                                 throw;
768                         } finally {
769                                 if (procInfo.Password != IntPtr.Zero) {
770                                         Marshal.ZeroFreeBSTR (procInfo.Password);
771                                         procInfo.Password = IntPtr.Zero;
772                                 }
773                         }
774
775                         SetProcessHandle (new SafeProcessHandle (procInfo.process_handle, true));
776                         SetProcessId (procInfo.pid);
777                         
778 #pragma warning disable 618
779
780                         if (startInfo.RedirectStandardInput) {
781                                 MonoIO.Close (stdin_read, out error);
782
783 #if MOBILE
784                                 var stdinEncoding = Encoding.Default;
785 #else
786                                 var stdinEncoding = Console.InputEncoding;
787 #endif
788                                 standardInput = new StreamWriter (new FileStream (stdin_write, FileAccess.Write, true, 8192), stdinEncoding) {
789                                         AutoFlush = true
790                                 };
791                         }
792
793                         if (startInfo.RedirectStandardOutput) {
794                                 MonoIO.Close (stdout_write, out error);
795
796                                 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
797
798                                 standardOutput = new StreamReader (new FileStream (stdout_read, FileAccess.Read, true, 8192), stdoutEncoding, true);
799                         }
800
801                         if (startInfo.RedirectStandardError) {
802                                 MonoIO.Close (stderr_write, out error);
803
804                                 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
805
806                                 standardError = new StreamReader (new FileStream (stderr_read, FileAccess.Read, true, 8192), stderrEncoding, true);
807                         }
808 #pragma warning restore
809
810                         return true;
811                 }
812
813                 // Note that ProcInfo.Password must be freed.
814                 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo procInfo)
815                 {
816                         if (startInfo.UserName.Length != 0) {
817                                 procInfo.UserName = startInfo.UserName;
818                                 procInfo.Domain = startInfo.Domain;
819                                 if (startInfo.Password != null)
820                                         procInfo.Password = Marshal.SecureStringToBSTR (startInfo.Password);
821                                 else
822                                         procInfo.Password = IntPtr.Zero;
823                                 procInfo.LoadUserProfile = startInfo.LoadUserProfile;
824                         }
825                 }
826 #else
827                 [Obsolete ("Process.Start is not supported on the current platform.", true)]
828                 public bool Start ()
829                 {
830                         throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
831                 }
832
833                 [Obsolete ("Process.Start is not supported on the current platform.", true)]
834                 public static Process Start (ProcessStartInfo startInfo)
835                 {
836                         throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
837                 }
838
839                 [Obsolete ("Process.Start is not supported on the current platform.", true)]
840                 public static Process Start (string fileName)
841                 {
842                         throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
843                 }
844
845                 [Obsolete ("Process.Start is not supported on the current platform.", true)]
846                 public static Process Start(string fileName, string arguments)
847                 {
848                         throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
849                 }
850
851                 [Obsolete ("Process.Start is not supported on the current platform.", true)]
852                 public static Process Start(string fileName, string username, SecureString password, string domain)
853                 {
854                         throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
855                 }
856
857                 [Obsolete ("Process.Start is not supported on the current platform.", true)]
858                 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain)
859                 {
860                         throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
861                 }
862 #endif // MONO_FEATURE_PROCESS_START
863
864 #if !MONO_FEATURE_PROCESS_START
865                 [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
866                 public void BeginOutputReadLine ()
867                 {
868                         throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
869                 }
870
871                 [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
872                 public void CancelOutputRead ()
873                 {
874                         throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
875                 }
876
877                 [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
878                 public void BeginErrorReadLine ()
879                 {
880                         throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
881                 }
882
883                 [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
884                 public void CancelErrorRead ()
885                 {
886                         throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
887                 }
888 #endif // !MONO_FEATURE_PROCESS_START
889
890                 /// <devdoc>
891                 ///     Raise the Exited event, but make sure we don't do it more than once.
892                 /// </devdoc>
893                 /// <internalonly/>
894                 void RaiseOnExited() {
895                         if (!watchForExit)
896                                 return;
897                         if (!raisedOnExited) {
898                                 lock (this) {
899                                         if (!raisedOnExited) {
900                                                 raisedOnExited = true;
901                                                 OnExited();
902                                         }
903                                 }
904                         }
905                 }
906         }
907 }
908