Merge pull request #963 from kebby/master
[mono.git] / mcs / class / System / System.Diagnostics / Process.cs
index 07ed17f498eeea26807abc464fa7e9ef98c0c6ad..af427037b285cfc9ae8e1b4e7aa7183d1fddc04b 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)]
@@ -104,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)]
@@ -334,10 +330,12 @@ namespace System.Diagnostics {
                        }
                }
 
+               /* 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 {
@@ -347,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 {
@@ -359,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 {
@@ -371,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 {
@@ -382,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.")]
@@ -447,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)]
@@ -503,37 +489,40 @@ namespace System.Diagnostics {
                                        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);
                        }
                }
 
-#if NET_2_0
                [MonoNotSupported ("")]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The session ID for this process.")]
                public int SessionId {
                        get { throw new NotImplementedException (); }
                }
-#endif
 
                /* the meaning of type is as follows: 0: user, 1: system, 2: total */
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
@@ -557,13 +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");
+                                               throw new InvalidOperationException ("Process has exited, so the requested information is not available.");
                                        
                                        /* Strip the suffix (if it
                                         * exists) simplistically
@@ -611,12 +604,10 @@ namespace System.Diagnostics {
                                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);
                        }
@@ -644,12 +635,10 @@ namespace System.Diagnostics {
                                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);
                        }
@@ -694,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 ProcessThreadCollection.GetEmpty ();
+                               // This'll return a correctly-sized array of empty ProcessThreads for now.
+                               int error;
+                               return new ProcessThreadCollection(new ProcessThread[GetProcessData (pid, 0, out error)]);
                        }
                }
 
@@ -718,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()
                {
@@ -848,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]));
@@ -878,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]
@@ -924,8 +918,7 @@ namespace System.Diagnostics {
                                                                  IntPtr stderr,
                                                                  ref ProcInfo proc_info);
 
-               private static bool Start_shell (ProcessStartInfo startInfo,
-                                                Process process)
+               private static bool Start_shell (ProcessStartInfo startInfo, Process process)
                {
                        ProcInfo proc_info=new ProcInfo();
                        bool ret;
@@ -954,9 +947,7 @@ namespace System.Diagnostics {
 
                        process.process_handle = proc_info.process_handle;
                        process.pid = proc_info.pid;
-
                        process.StartExitCallbackIfNeeded ();
-
                        return(ret);
                }
 
@@ -964,7 +955,7 @@ namespace System.Diagnostics {
                                                   Process process)
                {
                        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;
@@ -981,8 +972,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");
                                }
@@ -996,9 +1002,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) {
@@ -1015,9 +1035,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) {
@@ -1066,7 +1100,8 @@ namespace System.Diagnostics {
                                throw new Win32Exception (-proc_info.pid,
                                        "ApplicationName='" + startInfo.FileName +
                                        "', CommandLine='" + startInfo.Arguments +
-                                       "', CurrentDirectory='" + startInfo.WorkingDirectory + "'");
+                                       "', CurrentDirectory='" + startInfo.WorkingDirectory +
+                                       "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
                        }
 
                        process.process_handle = proc_info.process_handle;
@@ -1078,22 +1113,17 @@ namespace System.Diagnostics {
                                process.input_stream.AutoFlush = true;
                        }
 
-#if NET_2_0
                        Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
                        Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
-#else
-                       Encoding stdoutEncoding = Console.Out.Encoding;
-                       Encoding stderrEncoding = stdoutEncoding;
-#endif
 
                        if (startInfo.RedirectStandardOutput == true) {
                                MonoIO.Close (stdout_wr, out error);
-                               process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), 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 MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding);
+                               process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding, true, 8192);
                        }
 
                        process.StartExitCallbackIfNeeded ();
@@ -1104,7 +1134,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;
@@ -1114,7 +1143,6 @@ namespace System.Diagnostics {
                                        proc_info.Password = IntPtr.Zero;
                                proc_info.LoadUserProfile = startInfo.LoadUserProfile;
                        }
-#endif
                }
 
                private static bool Start_common (ProcessStartInfo startInfo,
@@ -1123,18 +1151,14 @@ namespace System.Diagnostics {
                        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));
@@ -1155,9 +1179,9 @@ namespace System.Diagnostics {
                        if (startInfo == null)
                                throw new ArgumentNullException ("startInfo");
 
-                       Process process=new Process();
+                       Process process = new Process();
                        process.StartInfo = startInfo;
-                       if (Start_common(startInfo, process))
+                       if (Start_common(startInfo, process) && process.process_handle != IntPtr.Zero)
                                return process;
                        return null;
                }
@@ -1172,7 +1196,6 @@ namespace System.Diagnostics {
                        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);
                }
@@ -1185,7 +1208,6 @@ namespace System.Diagnostics {
                        psi.UseShellExecute = false;
                        return Start(psi);
                }
-#endif
 
                public override string ToString()
                {
@@ -1208,7 +1230,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))
@@ -1233,18 +1254,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)
@@ -1255,7 +1283,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;
@@ -1291,6 +1318,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;
@@ -1307,6 +1337,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;
@@ -1315,7 +1350,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;
@@ -1340,7 +1375,7 @@ namespace System.Diagnostics {
                                                completed = true;
                                                if (wait_handle != null)
                                                        wait_handle.Set ();
-                                               Flush (true);
+                                               FlushLast ();
                                                return;
                                        }
 
@@ -1358,6 +1393,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 ||
@@ -1404,6 +1449,10 @@ namespace System.Diagnostics {
                                        }
                                }
                        }
+
+                       public void Close () {
+                               stream.Close ();
+                       }
                }
 
                AsyncModes async_mode;
@@ -1465,8 +1514,8 @@ namespace System.Diagnostics {
                [ComVisibleAttribute(false)] 
                public void CancelErrorRead ()
                {
-                       if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
-                               throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
+                       if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
+                               throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
 
                        if ((async_mode & AsyncModes.SyncOutput) != 0)
                                throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
@@ -1476,7 +1525,6 @@ namespace System.Diagnostics {
 
                        error_canceled = true;
                }
-#endif
 
                [Category ("Behavior")]
                [MonitoringDescription ("Raised when this process exits.")]
@@ -1509,31 +1557,37 @@ 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 ();
+
+                                               if (input_stream != null) {
+                                                       input_stream.Close();
+                                                       input_stream = null;
+                                               }
+
+                                               if (output_stream != null) {
+                                                       output_stream.Close();
+                                                       output_stream = null;
+                                               }
+
+                                               if (error_stream != null) {
+                                                       error_stream.Close();
+                                                       error_stream = null;
+                                               }
+                                       }
                                }
                                
                                // Release unmanaged resources
 
                                lock(this) {
                                        if(process_handle!=IntPtr.Zero) {
-                                               
                                                Process_free_internal(process_handle);
                                                process_handle=IntPtr.Zero;
                                        }
-
-                                       if (input_stream != null) {
-                                               input_stream.Close();
-                                               input_stream = null;
-                                       }
-
-                                       if (output_stream != null) {
-                                               output_stream.Close();
-                                               output_stream = null;
-                                       }
-
-                                       if (error_stream != null) {
-                                               error_stream.Close();
-                                               error_stream = null;
-                                       }
                                }
                        }
                        base.Dispose (disposing);
@@ -1547,6 +1601,7 @@ namespace System.Diagnostics {
                static void CBOnExit (object state, bool unused)
                {
                        Process p = (Process) state;
+                       p.already_waiting = false;
                        p.OnExited ();
                }
 
@@ -1568,16 +1623,34 @@ namespace System.Diagnostics {
                        synchronizingObject.BeginInvoke (exited_event, args);
                }
 
-               class ProcessWaitHandle : WaitHandle
+               static bool IsWindows
                {
-                       public ProcessWaitHandle (IntPtr handle)
+                       get
                        {
-                               Handle = handle;
+                               PlatformID platform = Environment.OSVersion.Platform;
+                               if (platform == PlatformID.Win32S ||
+                                       platform == PlatformID.Win32Windows ||
+                                       platform == PlatformID.Win32NT ||
+                                       platform == PlatformID.WinCE) {
+                                       return true;
+                               }
+                               return false;
                        }
+               }
 
-                       protected override void Dispose (bool explicitDisposing)
+               class ProcessWaitHandle : WaitHandle
+               {
+                       [MethodImplAttribute (MethodImplOptions.InternalCall)]
+                       private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
+                       
+                       public ProcessWaitHandle (IntPtr handle)
                        {
-                               // Do nothing, we don't own the handle and we won't close it.
+                               // Need to keep a reference to this handle,
+                               // in case the Process object is collected
+                               Handle = ProcessHandle_duplicate (handle);
+
+                               // When the wait handle is disposed, the duplicated handle will be
+                               // closed, so no need to override dispose (bug #464628).
                        }
                }
        }