update .sln too.
[mono.git] / mcs / class / System / System.Diagnostics / Process.cs
index 6233d1bc78718443fcf02c522349a0e66db9dc64..e08d79e0f10b97df5d49e13bbc1075a36df682a4 100644 (file)
@@ -49,9 +49,7 @@ namespace System.Diagnostics {
        [Designer ("System.Diagnostics.Design.ProcessDesigner, " + Consts.AssemblySystem_Design)]
        [PermissionSet (SecurityAction.LinkDemand, Unrestricted = true)]
        [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
-#if NET_2_0
        [MonitoringDescription ("Represents a system process")]
-#endif
        public class Process : Component 
        {
                [StructLayout(LayoutKind.Sequential)]
@@ -82,10 +80,6 @@ namespace System.Diagnostics {
                EventHandler exited_event;
                IntPtr stdout_rd;
                IntPtr stderr_rd;
-#if NET_2_0
-               Encoding stdout_encoding;
-               Encoding stderr_encoding;
-#endif
                
                /* Private constructor called from other methods */
                private Process(IntPtr handle, int id) {
@@ -108,15 +102,13 @@ namespace System.Diagnostics {
 
                void StartExitCallbackIfNeeded ()
                {
-#if !NET_2_1
                        bool start = (!already_waiting && enableRaisingEvents && exited_event != null);
-                       if (start && process_handle != IntPtr.Zero && !HasExited) {
+                       if (start && process_handle != IntPtr.Zero) {
                                WaitOrTimerCallback cb = new WaitOrTimerCallback (CBOnExit);
                                ProcessWaitHandle h = new ProcessWaitHandle (process_handle);
                                ThreadPool.RegisterWaitForSingleObject (h, cb, this, -1, true);
                                already_waiting = true;
                        }
-#endif
                }
 
                [DefaultValue (false), Browsable (false)]
@@ -213,9 +205,8 @@ namespace System.Diagnostics {
                [MonitoringDescription ("Process identifier.")]
                public int Id {
                        get {
-                               if (pid == 0) {
+                               if (pid == 0)
                                        throw new InvalidOperationException ("Process ID has not been set.");
-                               }
 
                                return(pid);
                        }
@@ -266,9 +257,10 @@ namespace System.Diagnostics {
                [MonitoringDescription ("The maximum working set for this process.")]
                public IntPtr MaxWorkingSet {
                        get {
-                               if(HasExited) {
-                                       throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
-                               }
+                               if(HasExited)
+                                       throw new InvalidOperationException(
+                                               "The process " + ProcessName +
+                                               " (ID " + Id + ") has exited");
                                
                                int min;
                                int max;
@@ -295,28 +287,27 @@ namespace System.Diagnostics {
                [MonitoringDescription ("The minimum working set for this process.")]
                public IntPtr MinWorkingSet {
                        get {
-                               if(HasExited) {
-                                       throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
-                               }
+                               if(HasExited)
+                                       throw new InvalidOperationException(
+                                               "The process " + ProcessName +
+                                               " (ID " + Id + ") has exited");
                                
                                int min;
                                int max;
-                               bool ok=GetWorkingSet_internal(process_handle, out min, out max);
-                               if(ok==false) {
+                               bool ok= GetWorkingSet_internal (process_handle, out min, out max);
+                               if(!ok)
                                        throw new Win32Exception();
-                               }
-                               
-                               return((IntPtr)min);
+                               return ((IntPtr) min);
                        }
                        set {
-                               if(HasExited) {
-                                       throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
-                               }
+                               if(HasExited)
+                                       throw new InvalidOperationException(
+                                               "The process " + ProcessName +
+                                               " (ID " + Id + ") has exited");
                                
-                               bool ok=SetWorkingSet_internal(process_handle, value.ToInt32(), 0, true);
-                               if(ok==false) {
+                               bool ok = SetWorkingSet_internal (process_handle, value.ToInt32(), 0, true);
+                               if (!ok)
                                        throw new Win32Exception();
-                               }
                        }
                }
 
@@ -324,7 +315,7 @@ namespace System.Diagnostics {
                 * element 0.
                 */
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern ProcessModule[] GetModules_internal();
+               private extern ProcessModule[] GetModules_internal(IntPtr handle);
 
                private ProcessModuleCollection module_collection;
                
@@ -332,18 +323,19 @@ namespace System.Diagnostics {
                [MonitoringDescription ("The modules that are loaded as part of this process.")]
                public ProcessModuleCollection Modules {
                        get {
-                               if(module_collection==null) {
-                                       module_collection=new ProcessModuleCollection(GetModules_internal());
-                               }
-
+                               if (module_collection == null)
+                                       module_collection = new ProcessModuleCollection(
+                                               GetModules_internal (process_handle));
                                return(module_collection);
                        }
                }
 
+               /* data type is from the MonoProcessData enum in mono-proclib.h in the runtime */
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               private extern static long GetProcessData (int pid, int data_type, out int error);
+
                [MonoTODO]
-#if NET_2_0
                [Obsolete ("Use NonpagedSystemMemorySize64")]
-#endif
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The number of bytes that are not pageable.")]
                public int NonpagedSystemMemorySize {
@@ -353,9 +345,7 @@ namespace System.Diagnostics {
                }
 
                [MonoTODO]
-#if NET_2_0
                [Obsolete ("Use PagedMemorySize64")]
-#endif
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The number of bytes that are paged.")]
                public int PagedMemorySize {
@@ -365,9 +355,7 @@ namespace System.Diagnostics {
                }
 
                [MonoTODO]
-#if NET_2_0
                [Obsolete ("Use PagedSystemMemorySize64")]
-#endif
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The amount of paged system memory in bytes.")]
                public int PagedSystemMemorySize {
@@ -377,9 +365,7 @@ namespace System.Diagnostics {
                }
 
                [MonoTODO]
-#if NET_2_0
                [Obsolete ("Use PeakPagedMemorySize64")]
-#endif
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
                public int PeakPagedMemorySize {
@@ -388,31 +374,26 @@ namespace System.Diagnostics {
                        }
                }
 
-               [MonoTODO]
-#if NET_2_0
                [Obsolete ("Use PeakVirtualMemorySize64")]
-#endif
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
                public int PeakVirtualMemorySize {
                        get {
-                               return(0);
+                               int error;
+                               return (int)GetProcessData (pid, 8, out error);
                        }
                }
 
-               [MonoTODO]
-#if NET_2_0
                [Obsolete ("Use PeakWorkingSet64")]
-#endif
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The maximum amount of system memory used by this process.")]
                public int PeakWorkingSet {
                        get {
-                               return(0);
+                               int error;
+                               return (int)GetProcessData (pid, 5, out error);
                        }
                }
 
-#if NET_2_0
                [MonoTODO]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The number of bytes that are not pageable.")]
@@ -453,26 +434,25 @@ namespace System.Diagnostics {
                        }
                }
 
-               [MonoTODO]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
                [ComVisible (false)]
                public long PeakVirtualMemorySize64 {
                        get {
-                               return(0);
+                               int error;
+                               return GetProcessData (pid, 8, out error);
                        }
                }
 
-               [MonoTODO]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The maximum amount of system memory used by this process.")]
                [ComVisible (false)]
                public long PeakWorkingSet64 {
                        get {
-                               return(0);
+                               int error;
+                               return GetProcessData (pid, 5, out error);
                        }
                }
-#endif
 
                [MonoTODO]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
@@ -490,6 +470,9 @@ namespace System.Diagnostics {
                [MonitoringDescription ("The relative process priority.")]
                public ProcessPriorityClass PriorityClass {
                        get {
+                               if (process_handle == IntPtr.Zero)
+                                       throw new InvalidOperationException ("Process has not been started.");
+                               
                                int error;
                                int prio = GetPriorityClass (process_handle, out error);
                                if (prio == 0)
@@ -497,34 +480,50 @@ namespace System.Diagnostics {
                                return (ProcessPriorityClass) prio;
                        }
                        set {
-                               // LAMESPEC: not documented on MSDN for NET_1_1
                                if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
-                                       throw new InvalidEnumArgumentException ();
+                                       throw new InvalidEnumArgumentException (
+                                               "value", (int) value,
+                                               typeof (ProcessPriorityClass));
 
+                               if (process_handle == IntPtr.Zero)
+                                       throw new InvalidOperationException ("Process has not been started.");
+                               
                                int error;
-                               if (!SetPriorityClass (process_handle, (int) value, out error))
+                               if (!SetPriorityClass (process_handle, (int) value, out error)) {
+                                       CheckExited ();
                                        throw new Win32Exception (error);
+                               }
                        }
                }
 
+               void CheckExited () {
+                       if (HasExited)
+                               throw new InvalidOperationException (String.Format ("Cannot process request because the process ({0}) has exited.", Id));
+               }
+
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                static extern int GetPriorityClass (IntPtr handle, out int error);
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);
 
-               [MonoTODO]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The amount of memory exclusively used by this process.")]
-#if NET_2_0
                [Obsolete ("Use PrivateMemorySize64")]
-#endif
                public int PrivateMemorySize {
                        get {
-                               return(0);
+                               int error;
+                               return (int)GetProcessData (pid, 6, out error);
                        }
                }
 
+               [MonoNotSupported ("")]
+               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+               [MonitoringDescription ("The session ID for this process.")]
+               public int SessionId {
+                       get { throw new NotImplementedException (); }
+               }
+
                /* the meaning of type is as follows: 0: user, 1: system, 2: total */
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private extern static long Times (IntPtr handle, int type);
@@ -547,14 +546,17 @@ namespace System.Diagnostics {
                public string ProcessName {
                        get {
                                if(process_name==null) {
+                                       
+                                       if (process_handle == IntPtr.Zero)
+                                               throw new InvalidOperationException ("No process is associated with this object.");
+                                       
                                        process_name=ProcessName_internal(process_handle);
                                        /* If process_name is _still_
                                         * null, assume the process
                                         * has exited
                                         */
-                                       if(process_name==null) {
-                                               throw new SystemException("The process has exited");
-                                       }
+                                       if (process_name == null)
+                                               throw new InvalidOperationException ("Process has exited, so the requested information is not available.");
                                        
                                        /* Strip the suffix (if it
                                         * exists) simplistically
@@ -599,15 +601,13 @@ namespace System.Diagnostics {
                [MonitoringDescription ("The standard error stream of this process.")]
                public StreamReader StandardError {
                        get {
-                               if (error_stream == null) {
+                               if (error_stream == null)
                                        throw new InvalidOperationException("Standard error has not been redirected");
-                               }
-#if NET_2_0
+
                                if ((async_mode & AsyncModes.AsyncError) != 0)
                                        throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
 
                                async_mode |= AsyncModes.SyncError;
-#endif
 
                                return(error_stream);
                        }
@@ -619,9 +619,8 @@ namespace System.Diagnostics {
                [MonitoringDescription ("The standard input stream of this process.")]
                public StreamWriter StandardInput {
                        get {
-                               if (input_stream == null) {
+                               if (input_stream == null)
                                        throw new InvalidOperationException("Standard input has not been redirected");
-                               }
 
                                return(input_stream);
                        }
@@ -633,15 +632,13 @@ namespace System.Diagnostics {
                [MonitoringDescription ("The standard output stream of this process.")]
                public StreamReader StandardOutput {
                        get {
-                               if (output_stream == null) {
+                               if (output_stream == null)
                                        throw new InvalidOperationException("Standard output has not been redirected");
-                               }
-#if NET_2_0
+
                                if ((async_mode & AsyncModes.AsyncOutput) != 0)
                                        throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
 
                                async_mode |= AsyncModes.SyncOutput;
-#endif
 
                                return(output_stream);
                        }
@@ -653,18 +650,14 @@ namespace System.Diagnostics {
                [MonitoringDescription ("Information for the start of this process.")]
                public ProcessStartInfo StartInfo {
                        get {
-                               if(start_info==null) {
-                                       start_info=new ProcessStartInfo();
-                               }
-                               
-                               return(start_info);
+                               if (start_info == null)
+                                       start_info = new ProcessStartInfo();
+                               return start_info;
                        }
                        set {
-                               if(value==null) {
-                                       throw new ArgumentException("value is null");
-                               }
-                               
-                               start_info=value;
+                               if (value == null)
+                                       throw new ArgumentNullException("value");
+                               start_info = value;
                        }
                }
 
@@ -690,11 +683,13 @@ namespace System.Diagnostics {
                }
 
                [MonoTODO]
-               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
+               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The number of threads of this process.")]
                public ProcessThreadCollection Threads {
                        get {
-                               return(null);
+                               // This'll return a correctly-sized array of empty ProcessThreads for now.
+                               int error;
+                               return new ProcessThreadCollection(new ProcessThread[GetProcessData (pid, 0, out error)]);
                        }
                }
 
@@ -714,61 +709,55 @@ namespace System.Diagnostics {
                        }
                }
 
-               [MonoTODO]
-#if NET_2_0
                [Obsolete ("Use VirtualMemorySize64")]
-#endif
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
                public int VirtualMemorySize {
                        get {
-                               return(0);
+                               int error;
+                               return (int)GetProcessData (pid, 7, out error);
                        }
                }
 
-               [MonoTODO]
-#if NET_2_0
                [Obsolete ("Use WorkingSet64")]
-#endif
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The amount of physical memory currently used for this process.")]
                public int WorkingSet {
                        get {
-                               return(0);
+                               int error;
+                               return (int)GetProcessData (pid, 4, out error);
                        }
                }
 
-#if NET_2_0
-               [MonoTODO]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The amount of memory exclusively used by this process.")]
                [ComVisible (false)]
                public long PrivateMemorySize64 {
                        get {
-                               return(0);
+                               int error;
+                               return GetProcessData (pid, 6, out error);
                        }
                }
 
-               [MonoTODO]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
                [ComVisible (false)]
                public long VirtualMemorySize64 {
                        get {
-                               return(0);
+                               int error;
+                               return GetProcessData (pid, 7, out error);
                        }
                }
 
-               [MonoTODO]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The amount of physical memory currently used for this process.")]
                [ComVisible (false)]
                public long WorkingSet64 {
                        get {
-                               return(0);
+                               int error;
+                               return GetProcessData (pid, 4, out error);
                        }
                }
-#endif
 
                public void Close()
                {
@@ -811,9 +800,8 @@ namespace System.Diagnostics {
                        int pid = GetPid_internal();
                        IntPtr proc = GetProcess_internal(pid);
                        
-                       if (proc == IntPtr.Zero) {
+                       if (proc == IntPtr.Zero)
                                throw new SystemException("Can't find current process");
-                       }
 
                        return (new Process (proc, pid));
                }
@@ -822,9 +810,8 @@ namespace System.Diagnostics {
                {
                        IntPtr proc = GetProcess_internal(processId);
                        
-                       if (proc == IntPtr.Zero) {
+                       if (proc == IntPtr.Zero)
                                throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
-                       }
 
                        return (new Process (proc, processId));
                }
@@ -846,8 +833,10 @@ namespace System.Diagnostics {
                public static Process[] GetProcesses()
                {
                        int [] pids = GetProcesses_internal ();
-                       ArrayList proclist = new ArrayList ();
-                       
+                       if (pids == null)
+                               return new Process [0];
+
+                       ArrayList proclist = new ArrayList (pids.Length);
                        for (int i = 0; i < pids.Length; i++) {
                                try {
                                        proclist.Add (GetProcessById (pids [i]));
@@ -876,19 +865,26 @@ namespace System.Diagnostics {
 
                public static Process[] GetProcessesByName(string processName)
                {
-                       Process [] procs = GetProcesses();
-                       ArrayList proclist = new ArrayList();
+                       int [] pids = GetProcesses_internal ();
+                       if (pids == null)
+                               return new Process [0];
                        
-                       for (int i = 0; i < procs.Length; i++) {
-                               /* Ignore case */
-                               if (String.Compare (processName,
-                                                   procs [i].ProcessName,
-                                                   true) == 0) {
-                                       proclist.Add (procs [i]);
+                       ArrayList proclist = new ArrayList (pids.Length);
+                       for (int i = 0; i < pids.Length; i++) {
+                               try {
+                                       Process p = GetProcessById (pids [i]);
+                                       if (String.Compare (processName, p.ProcessName, true) == 0)
+                                               proclist.Add (p);
+                               } catch (SystemException) {
+                                       /* The process might exit
+                                        * between
+                                        * GetProcesses_internal and
+                                        * GetProcessById
+                                        */
                                }
                        }
 
-                       return ((Process[]) proclist.ToArray (typeof(Process)));
+                       return ((Process []) proclist.ToArray (typeof (Process)));
                }
 
                [MonoTODO]
@@ -906,7 +902,7 @@ namespace System.Diagnostics {
                }
 
                public void Refresh ()
-               {
+               {
                        // FIXME: should refresh any cached data we might have about
                        // the process (currently we have none).
                }
@@ -934,9 +930,8 @@ namespace System.Diagnostics {
                                throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
                        }
 
-                       if (startInfo.HaveEnvVars) {
+                       if (startInfo.HaveEnvVars)
                                throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
-                       }
 
                        FillUserInfo (startInfo, ref proc_info);
                        try {
@@ -962,10 +957,8 @@ namespace System.Diagnostics {
                private static bool Start_noshell (ProcessStartInfo startInfo,
                                                   Process process)
                {
-                       if (Path.IsPathRooted (startInfo.FileName) && !File.Exists (startInfo.FileName))
-                               throw new FileNotFoundException  ("Executable not found: " + startInfo.FileName);
                        ProcInfo proc_info=new ProcInfo();
-                       IntPtr stdin_rd, stdin_wr;
+                       IntPtr stdin_rd = IntPtr.Zero, stdin_wr = IntPtr.Zero;
                        IntPtr stdout_wr;
                        IntPtr stderr_wr;
                        bool ret;
@@ -982,8 +975,23 @@ namespace System.Diagnostics {
                        }
 
                        if (startInfo.RedirectStandardInput == true) {
-                               ret = MonoIO.CreatePipe (out stdin_rd,
-                                                        out stdin_wr);
+                               if (IsWindows) {
+                                       int DUPLICATE_SAME_ACCESS = 0x00000002;
+                                       IntPtr stdin_wr_tmp;
+
+                                       ret = MonoIO.CreatePipe (out stdin_rd,
+                                                                        out stdin_wr_tmp);
+                                       if (ret) {
+                                               ret = MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, stdin_wr_tmp,
+                                               Process.GetCurrentProcess ().Handle, out stdin_wr, 0, 0, DUPLICATE_SAME_ACCESS);
+                                               MonoIO.Close (stdin_wr_tmp, out error);
+                                       }
+                               }
+                               else
+                               {
+                                       ret = MonoIO.CreatePipe (out stdin_rd,
+                                                                        out stdin_wr);
+                               }
                                if (ret == false) {
                                        throw new IOException ("Error creating standard input pipe");
                                }
@@ -997,9 +1005,23 @@ namespace System.Diagnostics {
                        }
 
                        if (startInfo.RedirectStandardOutput == true) {
-                               IntPtr out_rd;
-                               ret = MonoIO.CreatePipe (out out_rd,
-                                                        out stdout_wr);
+                               IntPtr out_rd = IntPtr.Zero;
+                               if (IsWindows) {
+                                       IntPtr out_rd_tmp;
+                                       int DUPLICATE_SAME_ACCESS = 0x00000002;
+
+                                       ret = MonoIO.CreatePipe (out out_rd_tmp,
+                                                                        out stdout_wr);
+                                       if (ret) {
+                                               MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, out_rd_tmp,
+                                               Process.GetCurrentProcess ().Handle, out out_rd, 0, 0, DUPLICATE_SAME_ACCESS);
+                                               MonoIO.Close (out_rd_tmp, out error);
+                                       }
+                               }
+                               else {
+                                       ret = MonoIO.CreatePipe (out out_rd,
+                                                                        out stdout_wr);
+                               }
 
                                process.stdout_rd = out_rd;
                                if (ret == false) {
@@ -1016,9 +1038,23 @@ namespace System.Diagnostics {
                        }
 
                        if (startInfo.RedirectStandardError == true) {
-                               IntPtr err_rd;
-                               ret = MonoIO.CreatePipe (out err_rd,
-                                                        out stderr_wr);
+                               IntPtr err_rd = IntPtr.Zero;
+                               if (IsWindows) {
+                                       IntPtr err_rd_tmp;
+                                       int DUPLICATE_SAME_ACCESS = 0x00000002;
+
+                                       ret = MonoIO.CreatePipe (out err_rd_tmp,
+                                                                        out stderr_wr);
+                                       if (ret) {
+                                               MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, err_rd_tmp,
+                                               Process.GetCurrentProcess ().Handle, out err_rd, 0, 0, DUPLICATE_SAME_ACCESS);
+                                               MonoIO.Close (err_rd_tmp, out error);
+                                       }
+                               }
+                               else {
+                                       ret = MonoIO.CreatePipe (out err_rd,
+                                                                        out stderr_wr);
+                               }
 
                                process.stderr_rd = err_rd;
                                if (ret == false) {
@@ -1064,11 +1100,11 @@ namespace System.Diagnostics {
                                        MonoIO.Close (stderr_wr, out error);
                                }
 
-                               throw new Win32Exception (-proc_info.pid, 
-                                       "ApplicationName='"+startInfo.FileName+
-                                       "', CommandLine='"+startInfo.Arguments+
-                                       "', CurrentDirectory='"+startInfo.WorkingDirectory+
-                                       "', PATH='"+startInfo.EnvironmentVariables["PATH"]+"'");
+                               throw new Win32Exception (-proc_info.pid,
+                                       "ApplicationName='" + startInfo.FileName +
+                                       "', CommandLine='" + startInfo.Arguments +
+                                       "', CurrentDirectory='" + startInfo.WorkingDirectory +
+                                       "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
                        }
 
                        process.process_handle = proc_info.process_handle;
@@ -1076,28 +1112,21 @@ namespace System.Diagnostics {
                        
                        if (startInfo.RedirectStandardInput == true) {
                                MonoIO.Close (stdin_rd, out error);
-                               process.input_stream = new StreamWriter (new FileStream (stdin_wr, FileAccess.Write, true), ConsoleEncoding.InputEncoding);
+                               process.input_stream = new StreamWriter (new MonoSyncFileStream (stdin_wr, FileAccess.Write, true, 8192), Console.Out.Encoding);
                                process.input_stream.AutoFlush = true;
                        }
 
-#if NET_2_0
-                       // TODO: which ones has precedence? The one from startInfo or the one set using
-                       // the Process instance properties?
-                       Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? process.StandardOutputEncoding;
-                       Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? process.StandardErrorEncoding;
-#else
-                       Encoding stdoutEncoding = ConsoleEncoding.OutputEncoding;
-                       Encoding stderrEncoding = ConsoleEncoding.OutputEncoding;
-#endif
+                       Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
+                       Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
 
                        if (startInfo.RedirectStandardOutput == true) {
                                MonoIO.Close (stdout_wr, out error);
-                               process.output_stream = new StreamReader (new FileStream (process.stdout_rd, FileAccess.Read, true), stdoutEncoding);
+                               process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding, true, 8192);
                        }
 
                        if (startInfo.RedirectStandardError == true) {
                                MonoIO.Close (stderr_wr, out error);
-                               process.error_stream = new StreamReader (new FileStream (process.stderr_rd, FileAccess.Read, true), stderrEncoding);
+                               process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding, true, 8192);
                        }
 
                        process.StartExitCallbackIfNeeded ();
@@ -1108,7 +1137,6 @@ namespace System.Diagnostics {
                // Note that ProcInfo.Password must be freed.
                private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
                {
-#if NET_2_0
                        if (startInfo.UserName != null) {
                                proc_info.UserName = startInfo.UserName;
                                proc_info.Domain = startInfo.Domain;
@@ -1118,72 +1146,59 @@ namespace System.Diagnostics {
                                        proc_info.Password = IntPtr.Zero;
                                proc_info.LoadUserProfile = startInfo.LoadUserProfile;
                        }
-#endif
                }
 
                private static bool Start_common (ProcessStartInfo startInfo,
                                                  Process process)
                {
-                       if(startInfo.FileName == null ||
-                          startInfo.FileName == "") {
+                       if (startInfo.FileName == null || startInfo.FileName.Length == 0)
                                throw new InvalidOperationException("File name has not been set");
-                       }
                        
-#if NET_2_0
                        if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
                                throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
                        if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
                                throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
-#endif
                        
                        if (startInfo.UseShellExecute) {
-#if NET_2_0
-                               if (startInfo.UserName != null)
+                               if (!String.IsNullOrEmpty (startInfo.UserName))
                                        throw new InvalidOperationException ("UserShellExecute must be false if an explicit UserName is specified when starting a process");
-#endif
                                return (Start_shell (startInfo, process));
                        } else {
                                return (Start_noshell (startInfo, process));
                        }
                }
                
-               public bool Start() {
-                       bool ret;
-
+               public bool Start ()
+               {
                        if (process_handle != IntPtr.Zero) {
                                Process_free_internal (process_handle);
                                process_handle = IntPtr.Zero;
                        }
-                       ret=Start_common(start_info, this);
-                       
-                       return(ret);
+                       return Start_common(start_info, this);
                }
 
-               public static Process Start(ProcessStartInfo startInfo) {
+               public static Process Start (ProcessStartInfo startInfo)
+               {
+                       if (startInfo == null)
+                               throw new ArgumentNullException ("startInfo");
 
                        Process process=new Process();
-                       bool ret;
-
                        process.StartInfo = startInfo;
-                       ret=Start_common(startInfo, process);
-                       
-                       if(ret==true) {
-                               return(process);
-                       } else {
-                               return(null);
-                       }
+                       if (Start_common(startInfo, process))
+                               return process;
+                       return null;
                }
 
-               public static Process Start(string fileName) {
-                       return Start(new ProcessStartInfo(fileName));
+               public static Process Start (string fileName)
+               {
+                       return Start (new ProcessStartInfo (fileName));
                }
 
-               public static Process Start(string fileName,
-                                           string arguments) {
-                       return Start(new ProcessStartInfo(fileName, arguments));
+               public static Process Start(string fileName, string arguments)
+               {
+                       return Start (new ProcessStartInfo (fileName, arguments));
                }
 
-#if NET_2_0
                public static Process Start(string fileName, string username, SecureString password, string domain) {
                        return Start(fileName, null, username, password, domain);
                }
@@ -1196,11 +1211,10 @@ namespace System.Diagnostics {
                        psi.UseShellExecute = false;
                        return Start(psi);
                }
-#endif
 
-               public override string ToString() {
-                       return(base.ToString() +
-                              " (" + this.ProcessName + ")");
+               public override string ToString()
+               {
+                       return(base.ToString() + " (" + this.ProcessName + ")");
                }
 
                /* Waits up to ms milliseconds for process 'handle' to
@@ -1219,7 +1233,6 @@ namespace System.Diagnostics {
                        if (ms == int.MaxValue)
                                ms = -1;
 
-#if NET_2_0
                        DateTime start = DateTime.UtcNow;
                        if (async_output != null && !async_output.IsCompleted) {
                                if (false == async_output.WaitHandle.WaitOne (ms, false))
@@ -1244,18 +1257,25 @@ namespace System.Diagnostics {
                                                return false;
                                }
                        }
-#endif
                        return WaitForExit_internal (process_handle, ms);
                }
 
+               /* Waits up to ms milliseconds for process 'handle' to 
+                * wait for input.  ms can be <0 to mean wait forever.
+                */
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
+
+               // The internal call is only implemented properly on Windows.
                [MonoTODO]
                public bool WaitForInputIdle() {
-                       return(false);
+                       return WaitForInputIdle (-1);
                }
 
+               // The internal call is only implemented properly on Windows.
                [MonoTODO]
                public bool WaitForInputIdle(int milliseconds) {
-                       return(false);
+                       return WaitForInputIdle_internal (process_handle, milliseconds);
                }
 
                private static bool IsLocalMachine (string machineName)
@@ -1266,7 +1286,6 @@ namespace System.Diagnostics {
                        return (string.Compare (machineName, Environment.MachineName, true) == 0);
                }
 
-#if NET_2_0
                [Browsable (true)]
                [MonitoringDescription ("Raised when it receives output data")]
                public event DataReceivedEventHandler OutputDataReceived;
@@ -1302,6 +1321,9 @@ namespace System.Diagnostics {
                           The following fields match those of SocketAsyncResult.
                           This is so that changes needed in the runtime to handle
                           asynchronous reads are trivial
+                          Keep this in sync with SocketAsyncResult in 
+                          ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
+                          in metadata/socket-io.h.
                        */
                        /* DON'T shuffle fields around. DON'T remove fields */
                        public object Sock;
@@ -1318,6 +1340,11 @@ namespace System.Diagnostics {
                        public int Size;
                        public int SockFlags;
 
+                       public object AcceptSocket;
+                       public object[] Addresses;
+                       public int port;
+                       public object Buffers;          // Reserve this slot in older profiles
+                       public bool ReuseSocket;        // Disconnect
                        public object acc_socket;
                        public int total;
                        public bool completed_sync;
@@ -1326,7 +1353,7 @@ namespace System.Diagnostics {
                        internal int error;
                        public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
                        public object ares;
-
+                       public int EndCalled;
 
                        // These fields are not in SocketAsyncResult
                        Process process;
@@ -1351,7 +1378,7 @@ namespace System.Diagnostics {
                                                completed = true;
                                                if (wait_handle != null)
                                                        wait_handle.Set ();
-                                               Flush (true);
+                                               FlushLast ();
                                                return;
                                        }
 
@@ -1369,6 +1396,16 @@ namespace System.Diagnostics {
                                }
                        }
 
+                       void FlushLast ()
+                       {
+                               Flush (true);
+                               if (err_out) {
+                                       process.OnOutputDataReceived (null);
+                               } else {
+                                       process.OnErrorDataReceived (null);
+                               }
+                       }
+                       
                        void Flush (bool last)
                        {
                                if (sb.Length == 0 ||
@@ -1415,6 +1452,10 @@ namespace System.Diagnostics {
                                        }
                                }
                        }
+
+                       public void Close () {
+                               stream.Close ();
+                       }
                }
 
                AsyncModes async_mode;
@@ -1487,7 +1528,6 @@ namespace System.Diagnostics {
 
                        error_canceled = true;
                }
-#endif
 
                [Category ("Behavior")]
                [MonitoringDescription ("Raised when this process exits.")]
@@ -1520,13 +1560,19 @@ namespace System.Diagnostics {
                                // dispose all managed resources.
                                if(disposing) {
                                        // Do stuff here
+                                       lock (this) {
+                                               /* These have open FileStreams on the pipes we are about to close */
+                                               if (async_output != null)
+                                                       async_output.Close ();
+                                               if (async_error != null)
+                                                       async_error.Close ();
+                                       }
                                }
                                
                                // Release unmanaged resources
 
                                lock(this) {
                                        if(process_handle!=IntPtr.Zero) {
-                                               
                                                Process_free_internal(process_handle);
                                                process_handle=IntPtr.Zero;
                                        }
@@ -1558,6 +1604,7 @@ namespace System.Diagnostics {
                static void CBOnExit (object state, bool unused)
                {
                        Process p = (Process) state;
+                       p.already_waiting = false;
                        p.OnExited ();
                }
 
@@ -1579,97 +1626,34 @@ namespace System.Diagnostics {
                        synchronizingObject.BeginInvoke (exited_event, args);
                }
 
-#if NET_2_0
-               public Encoding StandardOutputEncoding {
-                       get {
-                               if (stdout_encoding != null) {
-                                       return stdout_encoding;
-                               }
-                               return ConsoleEncoding.OutputEncoding;
-                       }
-                       set {
-                               stdout_encoding = value; // if null, we'll use the default
-                       }
-               }
-
-               public Encoding StandardErrorEncoding {
-                       get {
-                               if (stderr_encoding != null) {
-                                       return stderr_encoding;
+               static bool IsWindows
+               {
+                       get
+                       {
+                               PlatformID platform = Environment.OSVersion.Platform;
+                               if (platform == PlatformID.Win32S ||
+                                       platform == PlatformID.Win32Windows ||
+                                       platform == PlatformID.Win32NT ||
+                                       platform == PlatformID.WinCE) {
+                                       return true;
                                }
-                               return ConsoleEncoding.OutputEncoding;
-                       }
-                       set {
-                               stderr_encoding = value; // if null, we'll use the default
+                               return false;
                        }
                }
-#endif
 
                class ProcessWaitHandle : WaitHandle
                {
+                       [MethodImplAttribute (MethodImplOptions.InternalCall)]
+                       private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
+                       
                        public ProcessWaitHandle (IntPtr handle)
                        {
-                               Handle = handle;
-                       }
+                               // Need to keep a reference to this handle,
+                               // in case the Process object is collected
+                               Handle = ProcessHandle_duplicate (handle);
 
-                       protected override void Dispose (bool explicitDisposing)
-                       {
-                               // Do nothing, we don't own the handle and we won't close it.
-                       }
-               }
-
-               class ConsoleEncoding
-               {
-                       [DllImport ("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
-                       private static extern int GetConsoleCP ();
-                       [DllImport ("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
-                       private static extern int GetConsoleOutputCP ();
-
-                       static bool RunningOnWindows {
-                               get {
-                                       return ((int) Environment.OSVersion.Platform != 4 &&
-#if NET_2_0
-                                               Environment.OSVersion.Platform != PlatformID.Unix);
-#else
-                                               (int) Environment.OSVersion.Platform != 128);
-#endif
-                               }
-                       }
-
-                       public static Encoding InputEncoding {
-                               get {
-                                       if(!RunningOnWindows) {
-                                               return Encoding.Default;
-                                       }
-
-#if !NET_2_0
-                                       try {
-                                               return Encoding.GetEncoding (GetConsoleCP ());
-                                       } catch {
-                                               return Encoding.GetEncoding (28591);
-                                       }
-#else
-                                       return Console.InputEncoding;
-#endif
-                               }
-                       }
-
-                       public static Encoding OutputEncoding {
-                               get {
-                                       if(!RunningOnWindows) {
-                                               return Encoding.Default;
-                                       }
-
-#if !NET_2_0
-                                       try {
-                                               return Encoding.GetEncoding (GetConsoleOutputCP ());
-                                       } catch {
-                                               return Encoding.GetEncoding (28591);
-                                       }
-#else
-                                       return Console.OutputEncoding;
-#endif
-                               }
+                               // When the wait handle is disposed, the duplicated handle will be
+                               // closed, so no need to override dispose (bug #464628).
                        }
                }
        }