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