[process] Fix Process.GetProcessesByName (#4351)
[mono.git] / mcs / class / System / System.Diagnostics / Process.cs
index 59616e64d94d652f9091843da386f04e2ab191b6..8423659fdc7cd86f9fd552b6656e3a49396cc0f1 100644 (file)
@@ -34,6 +34,7 @@
 
 using System.IO;
 using System.Text;
+using System.Collections;
 using System.ComponentModel;
 using System.ComponentModel.Design;
 using System.Runtime.CompilerServices;
@@ -43,16 +44,12 @@ using System.Security.Permissions;
 using System.Collections.Generic;
 using System.Security;
 using System.Threading;
+using Microsoft.Win32;
 using Microsoft.Win32.SafeHandles;
 
-namespace System.Diagnostics {
-
-       [DefaultEvent ("Exited"), DefaultProperty ("StartInfo")]
-       [Designer ("System.Diagnostics.Design.ProcessDesigner, " + Consts.AssemblySystem_Design)]
-       [PermissionSet (SecurityAction.LinkDemand, Unrestricted = true)]
-       [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
-       [MonitoringDescription ("Represents a system process")]
-       public class Process : Component 
+namespace System.Diagnostics
+{
+       public partial class Process : Component 
        {
                [StructLayout(LayoutKind.Sequential)]
                private struct ProcInfo 
@@ -66,29 +63,19 @@ namespace System.Diagnostics {
                        public IntPtr thread_handle;
                        public int pid; // Contains -GetLastError () on failure.
                        public int tid;
-                       public string [] envKeys;
-                       public string [] envValues;
+                       public string[] envVariables;
                        public string UserName;
                        public string Domain;
                        public IntPtr Password;
                        public bool LoadUserProfile;
                };
 
-               IntPtr process_handle;
-               int pid;
-               int enable_raising_events;
-               Thread background_wait_for_exit_thread;
-               ISynchronizeInvoke synchronizingObject;
-               EventHandler exited_event;
+               string process_name;
 
                /* Private constructor called from other methods */
-               private Process(IntPtr handle, int id) {
-                       process_handle = handle;
-                       pid=id;
-               }
-
-               public Process ()
-               {
+               private Process (SafeProcessHandle handle, int id) {
+                       SetProcessHandle (handle);
+                       SetProcessId (id);
                }
 
                [MonoTODO]
@@ -98,67 +85,6 @@ namespace System.Diagnostics {
                        get { return 0; }
                }
 
-               [DefaultValue (false), Browsable (false)]
-               [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
-               public bool EnableRaisingEvents {
-                       get {
-                               return enable_raising_events == 1;
-                       }
-                       set {
-                               if (value && Interlocked.Exchange (ref enable_raising_events, 1) == 0)
-                                       StartBackgroundWaitForExit ();
-                       }
-               }
-
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static int ExitCode_internal(IntPtr handle);
-
-               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
-               [MonitoringDescription ("The exit code of the process.")]
-               public int ExitCode {
-                       get {
-                               if (process_handle == IntPtr.Zero)
-                                       throw new InvalidOperationException ("Process has not been started.");
-
-                               int code = ExitCode_internal (process_handle);
-                               if (code == 259)
-                                       throw new InvalidOperationException ("The process must exit before getting the requested information.");
-
-                               return code;
-                       }
-               }
-
-               /* Returns the process start time in Windows file
-                * times (ticks from DateTime(1/1/1601 00:00 GMT))
-                */
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static long ExitTime_internal(IntPtr handle);
-               
-               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
-               [MonitoringDescription ("The exit time of the process.")]
-               public DateTime ExitTime {
-                       get {
-                               if (process_handle == IntPtr.Zero)
-                                       throw new InvalidOperationException ("Process has not been started.");
-
-                               if (!HasExited)
-                                       throw new InvalidOperationException ("The process must exit before " +
-                                                                       "getting the requested information.");
-
-                               return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
-                       }
-               }
-
-               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
-               [MonitoringDescription ("Handle for this process.")]
-               public IntPtr Handle {
-                       get {
-                               if (process_handle == IntPtr.Zero)
-                                       throw new InvalidOperationException ("No process is associated with this object.");
-                               return(process_handle);
-                       }
-               }
-
                [MonoTODO]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("Handles for this process.")]
@@ -168,44 +94,6 @@ namespace System.Diagnostics {
                        }
                }
 
-               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
-               [MonitoringDescription ("Determines if the process is still running.")]
-               public bool HasExited {
-                       get {
-                               if (process_handle == IntPtr.Zero)
-                                       throw new InvalidOperationException ("Process has not been started.");
-                                       
-                               int exitcode = ExitCode_internal (process_handle);
-
-                               if(exitcode==259) {
-                                       /* STILL_ACTIVE */
-                                       return(false);
-                               } else {
-                                       return(true);
-                               }
-                       }
-               }
-
-               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               [MonitoringDescription ("Process identifier.")]
-               public int Id {
-                       get {
-                               if (pid == 0)
-                                       throw new InvalidOperationException ("Process ID has not been set.");
-
-                               return(pid);
-                       }
-               }
-
-               [MonoTODO]
-               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
-               [MonitoringDescription ("The name of the computer running the process.")]
-               public string MachineName {
-                       get {
-                               return("localhost");
-                       }
-               }
-
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
                [MonitoringDescription ("The main module of the process.")]
                public ProcessModule MainModule {
@@ -232,86 +120,39 @@ namespace System.Diagnostics {
                        }
                }
 
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);
-
-               /* LAMESPEC: why is this an IntPtr not a plain int? */
-               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               [MonitoringDescription ("The maximum working set for this process.")]
-               public IntPtr MaxWorkingSet {
-                       get {
-                               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) {
-                                       throw new Win32Exception();
-                               }
-                               
-                               return((IntPtr)max);
-                       }
-                       set {
-                               if(HasExited) {
-                                       throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
-                               }
-                               
-                               bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
-                               if(ok==false) {
-                                       throw new Win32Exception();
-                               }
-                       }
-               }
-
-               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               [MonitoringDescription ("The minimum working set for this process.")]
-               public IntPtr MinWorkingSet {
-                       get {
-                               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)
-                                       throw new Win32Exception();
-                               return ((IntPtr) min);
-                       }
-                       set {
-                               if(HasExited)
-                                       throw new InvalidOperationException(
-                                               "The process " + ProcessName +
-                                               " (ID " + Id + ") has exited");
-                               
-                               bool ok = SetWorkingSet_internal (process_handle, value.ToInt32(), 0, true);
-                               if (!ok)
-                                       throw new Win32Exception();
-                       }
-               }
-
                /* Returns the list of process modules.  The main module is
                 * element 0.
                 */
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private extern ProcessModule[] GetModules_internal(IntPtr handle);
 
-               private ProcessModuleCollection module_collection;
-               
+               ProcessModule[] GetModules_internal (SafeProcessHandle handle)
+               {
+                       bool release = false;
+                       try {
+                               handle.DangerousAddRef (ref release);
+                               return GetModules_internal (handle.DangerousGetHandle ());
+                       } finally {
+                               if (release)
+                                       handle.DangerousRelease ();
+                       }
+               }
+
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
                [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 (process_handle));
-                               return(module_collection);
+                               if (modules == null) {
+                                       SafeProcessHandle handle = null;
+                                       try {
+                                               handle = GetProcessHandle (NativeMethods.PROCESS_QUERY_INFORMATION);
+                                               modules = new ProcessModuleCollection (GetModules_internal (handle));
+                                       } finally {
+                                               ReleaseProcessHandle (handle);
+                                       }
+                               }
+
+                               return modules;
                        }
                }
 
@@ -363,7 +204,7 @@ namespace System.Diagnostics {
                public int PeakVirtualMemorySize {
                        get {
                                int error;
-                               return (int)GetProcessData (pid, 8, out error);
+                               return (int)GetProcessData (processId, 8, out error);
                        }
                }
 
@@ -373,7 +214,7 @@ namespace System.Diagnostics {
                public int PeakWorkingSet {
                        get {
                                int error;
-                               return (int)GetProcessData (pid, 5, out error);
+                               return (int)GetProcessData (processId, 5, out error);
                        }
                }
 
@@ -393,7 +234,7 @@ namespace System.Diagnostics {
                public long PagedMemorySize64 {
                        get {
                                int error;
-                               return GetProcessData (pid, 12, out error);
+                               return GetProcessData (processId, 12, out error);
                        }
                }
 
@@ -422,7 +263,7 @@ namespace System.Diagnostics {
                public long PeakVirtualMemorySize64 {
                        get {
                                int error;
-                               return GetProcessData (pid, 8, out error);
+                               return GetProcessData (processId, 8, out error);
                        }
                }
 
@@ -432,7 +273,7 @@ namespace System.Diagnostics {
                public long PeakWorkingSet64 {
                        get {
                                int error;
-                               return GetProcessData (pid, 5, out error);
+                               return GetProcessData (processId, 5, out error);
                        }
                }
 
@@ -447,55 +288,13 @@ namespace System.Diagnostics {
                        }
                }
 
-               [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
-               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               [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)
-                                       throw new Win32Exception (error);
-                               return (ProcessPriorityClass) prio;
-                       }
-                       set {
-                               if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
-                                       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)) {
-                                       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);
-
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The amount of memory exclusively used by this process.")]
                [Obsolete ("Use PrivateMemorySize64")]
                public int PrivateMemorySize {
                        get {
                                int error;
-                               return (int)GetProcessData (pid, 6, out error);
+                               return (int)GetProcessData (processId, 6, out error);
                        }
                }
 
@@ -503,57 +302,48 @@ namespace System.Diagnostics {
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The session ID for this process.")]
                public int SessionId {
-                       get { throw new NotImplementedException (); }
+                       get { return 0; }
                }
 
-               /* 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);
+               private extern static string ProcessName_internal(IntPtr handle);
 
-               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
-               public TimeSpan PrivilegedProcessorTime {
-                       get {
-                               return new TimeSpan (Times (process_handle, 1));
+               static string ProcessName_internal(SafeProcessHandle handle)
+               {
+                       bool release = false;
+                       try {
+                               handle.DangerousAddRef (ref release);
+                               return ProcessName_internal (handle.DangerousGetHandle ());
+                       } finally {
+                               if (release)
+                                       handle.DangerousRelease ();
                        }
                }
 
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static string ProcessName_internal(IntPtr handle);
-               
-               private string process_name=null;
-               
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The name of this process.")]
                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 InvalidOperationException ("Process has exited, so the requested information is not available.");
-                                       
-                                       /* Strip the suffix (if it
-                                        * exists) simplistically
-                                        * instead of removing any
-                                        * trailing \.???, so we dont
-                                        * get stupid results on sane
-                                        * systems
-                                        */
-                                       if(process_name.EndsWith(".exe") ||
-                                          process_name.EndsWith(".bat") ||
-                                          process_name.EndsWith(".com")) {
-                                               process_name=process_name.Substring(0, process_name.Length-4);
+                               if (process_name == null) {
+                                       SafeProcessHandle handle = null;
+                                       try {
+                                               handle = GetProcessHandle (NativeMethods.PROCESS_QUERY_INFORMATION);
+
+                                               process_name = ProcessName_internal (handle);
+
+                                               /* If process_name is _still_ null, assume 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 instead of removing
+                                                * any trailing \.???, so we dont get stupid results on sane systems */
+                                               if(process_name.EndsWith(".exe") || process_name.EndsWith(".bat") || process_name.EndsWith(".com"))
+                                                       process_name = process_name.Substring (0, process_name.Length - 4);
+                                       } finally {
+                                               ReleaseProcessHandle (handle);
                                        }
                                }
-                               return(process_name);
+                               return process_name;
                        }
                }
 
@@ -577,79 +367,13 @@ namespace System.Diagnostics {
                        }
                }
 
-#if MONO_FEATURE_PROCESS_START
-               private StreamReader error_stream=null;
-               bool error_stream_exposed;
-
-               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
-               [MonitoringDescription ("The standard error stream of this process.")]
-               public StreamReader StandardError {
-                       get {
-                               if (error_stream == null)
-                                       throw new InvalidOperationException("Standard error has not been redirected");
-
-                               if ((async_mode & AsyncModes.AsyncError) != 0)
-                                       throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
-
-                               async_mode |= AsyncModes.SyncError;
-
-                               error_stream_exposed = true;
-                               return(error_stream);
-                       }
-               }
-
-               private StreamWriter input_stream=null;
-               bool input_stream_exposed;
-               
-               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
-               [MonitoringDescription ("The standard input stream of this process.")]
-               public StreamWriter StandardInput {
-                       get {
-                               if (input_stream == null)
-                                       throw new InvalidOperationException("Standard input has not been redirected");
-
-                               input_stream_exposed = true;
-                               return(input_stream);
-                       }
-               }
-
-               private StreamReader output_stream=null;
-               bool output_stream_exposed;
-               
-               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
-               [MonitoringDescription ("The standard output stream of this process.")]
-               public StreamReader StandardOutput {
-                       get {
-                               if (output_stream == null)
-                                       throw new InvalidOperationException("Standard output has not been redirected");
-
-                               if ((async_mode & AsyncModes.AsyncOutput) != 0)
-                                       throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
-
-                               async_mode |= AsyncModes.SyncOutput;
-
-                               output_stream_exposed = true;
-                               return(output_stream);
-                       }
-               }
-
-               private ProcessStartInfo start_info=null;
-               
-               [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
-               [MonitoringDescription ("Information for the start of this process.")]
+#if !MONO_FEATURE_PROCESS_START
+               [Obsolete ("Process.StartInfo is not supported on the current platform.", true)]
                public ProcessStartInfo StartInfo {
-                       get {
-                               if (start_info == null)
-                                       start_info = new ProcessStartInfo();
-                               return start_info;
-                       }
-                       set {
-                               if (value == null)
-                                       throw new ArgumentNullException("value");
-                               start_info = value;
-                       }
+                       get { throw new PlatformNotSupportedException ("Process.StartInfo is not supported on the current platform."); }
+                       set { throw new PlatformNotSupportedException ("Process.StartInfo is not supported on the current platform."); }
                }
-#else
+
                [Obsolete ("Process.StandardError is not supported on the current platform.", true)]
                public StreamReader StandardError {
                        get { throw new PlatformNotSupportedException ("Process.StandardError is not supported on the current platform."); }
@@ -664,59 +388,20 @@ namespace System.Diagnostics {
                public StreamReader StandardOutput {
                        get { throw new PlatformNotSupportedException ("Process.StandardOutput is not supported on the current platform."); }
                }
-
-               [Obsolete ("Process.StartInfo is not supported on the current platform.", true)]
-               public ProcessStartInfo StartInfo {
-                       get { throw new PlatformNotSupportedException ("Process.StartInfo is not supported on the current platform."); }
-                       set { throw new PlatformNotSupportedException ("Process.StartInfo is not supported on the current platform."); }
-               }
-#endif // MONO_FEATURE_PROCESS_START
-
-               /* Returns the process start time in Windows file
-                * times (ticks from DateTime(1/1/1601 00:00 GMT))
-                */
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static long StartTime_internal(IntPtr handle);
-               
-               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               [MonitoringDescription ("The time this process started.")]
-               public DateTime StartTime {
-                       get {
-                               return(DateTime.FromFileTime(StartTime_internal(process_handle)));
-                       }
-               }
-
-               [DefaultValue (null), Browsable (false)]
-               [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
-               public ISynchronizeInvoke SynchronizingObject {
-                       get { return synchronizingObject; }
-                       set { synchronizingObject = value; }
-               }
+#endif // !MONO_FEATURE_PROCESS_START
 
                [MonoTODO]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("The number of threads of this process.")]
                public ProcessThreadCollection Threads {
                        get {
-                               // This'll return a correctly-sized array of empty ProcessThreads for now.
-                               int error;
-                               return new ProcessThreadCollection(new ProcessThread[GetProcessData (pid, 0, out error)]);
-                       }
-               }
-
-               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               [MonitoringDescription ("The total CPU time spent for this process.")]
-               public TimeSpan TotalProcessorTime {
-                       get {
-                               return new TimeSpan (Times (process_handle, 2));
-                       }
-               }
+                               if (threads == null) {
+                                       int error;
+                                       // This'll return a correctly-sized array of empty ProcessThreads for now.
+                                       threads = new ProcessThreadCollection(new ProcessThread [GetProcessData (processId, 0, out error)]);
+                               }
 
-               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               [MonitoringDescription ("The CPU time spent for this process in user mode.")]
-               public TimeSpan UserProcessorTime {
-                       get {
-                               return new TimeSpan (Times (process_handle, 0));
+                               return threads;
                        }
                }
 
@@ -726,7 +411,7 @@ namespace System.Diagnostics {
                public int VirtualMemorySize {
                        get {
                                int error;
-                               return (int)GetProcessData (pid, 7, out error);
+                               return (int)GetProcessData (processId, 7, out error);
                        }
                }
 
@@ -736,7 +421,7 @@ namespace System.Diagnostics {
                public int WorkingSet {
                        get {
                                int error;
-                               return (int)GetProcessData (pid, 4, out error);
+                               return (int)GetProcessData (processId, 4, out error);
                        }
                }
 
@@ -746,7 +431,7 @@ namespace System.Diagnostics {
                public long PrivateMemorySize64 {
                        get {
                                int error;
-                               return GetProcessData (pid, 6, out error);
+                               return GetProcessData (processId, 6, out error);
                        }
                }
 
@@ -756,7 +441,7 @@ namespace System.Diagnostics {
                public long VirtualMemorySize64 {
                        get {
                                int error;
-                               return GetProcessData (pid, 7, out error);
+                               return GetProcessData (processId, 7, out error);
                        }
                }
 
@@ -766,103 +451,71 @@ namespace System.Diagnostics {
                public long WorkingSet64 {
                        get {
                                int error;
-                               return GetProcessData (pid, 4, out error);
+                               return GetProcessData (processId, 4, out error);
                        }
                }
 
-               public void Close()
-               {
-                       Dispose (true);
-               }
-
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               extern static bool Kill_internal (IntPtr handle, int signo);
-
-               /* int kill -> 1 KILL, 2 CloseMainWindow */
-               bool Close (int signo)
-               {
-                       if (process_handle == IntPtr.Zero)
-                               throw new SystemException ("No process to kill.");
-
-                       int exitcode = ExitCode_internal (process_handle);
-                       if (exitcode != 259)
-                               throw new InvalidOperationException ("The process already finished.");
-
-                       return Kill_internal (process_handle, signo);
-               }
-
                public bool CloseMainWindow ()
                {
-                       return Close (2);
-               }
-
-               [MonoTODO]
-               public static void EnterDebugMode() {
+                       SafeProcessHandle handle = null;
+                       try {
+                               handle = GetProcessHandle (NativeMethods.PROCESS_TERMINATE);
+                               return NativeMethods.TerminateProcess(handle, -2);
+                       } finally {
+                               ReleaseProcessHandle(handle);
+                       }
                }
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private extern static IntPtr GetProcess_internal(int pid);
-               
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static int GetPid_internal();
 
-               public static Process GetCurrentProcess()
-               {
-                       int pid = GetPid_internal();
-                       IntPtr proc = GetProcess_internal(pid);
-                       
-                       if (proc == IntPtr.Zero)
-                               throw new SystemException("Can't find current process");
+               [MonoTODO ("There is no support for retrieving process information from a remote machine")]
+               public static Process GetProcessById(int processId, string machineName) {
+                       if (machineName == null)
+                               throw new ArgumentNullException ("machineName");
 
-                       return (new Process (proc, pid));
-               }
+                       if (!IsLocalMachine (machineName))
+                               throw new NotImplementedException ();
 
-               public static Process GetProcessById(int processId)
-               {
                        IntPtr proc = GetProcess_internal(processId);
-                       
+
                        if (proc == IntPtr.Zero)
                                throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
 
-                       return (new Process (proc, processId));
+                       return (new Process (new SafeProcessHandle (proc, false), processId));
                }
 
-               [MonoTODO ("There is no support for retrieving process information from a remote machine")]
-               public static Process GetProcessById(int processId, string machineName) {
+               public static Process[] GetProcessesByName(string processName, string machineName)
+               {
                        if (machineName == null)
                                throw new ArgumentNullException ("machineName");
 
                        if (!IsLocalMachine (machineName))
                                throw new NotImplementedException ();
 
-                       return GetProcessById (processId);
-               }
+                       Process[] processes = GetProcesses ();
+                       if (processes.Length == 0)
+                               return processes;
 
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static int[] GetProcesses_internal();
+                       int size = 0;
 
-               public static Process[] GetProcesses ()
-               {
-                       int [] pids = GetProcesses_internal ();
-                       if (pids == null)
-                               return new Process [0];
-
-                       var proclist = new List<Process> (pids.Length);
-                       for (int i = 0; i < pids.Length; i++) {
+                       for (int i = 0; i < processes.Length; i++) {
                                try {
-                                       proclist.Add (GetProcessById (pids [i]));
+                                       if (String.Compare (processName, processes[i].ProcessName, true) == 0)
+                                               processes [size++] = processes[i];
                                } catch (SystemException) {
-                                       /* The process might exit
-                                        * between
-                                        * GetProcesses_internal and
-                                        * GetProcessById
-                                        */
+                                       /* The process might exit between GetProcesses_internal and GetProcessById */
                                }
                        }
 
-                       return proclist.ToArray ();
+                       Array.Resize<Process> (ref processes, size);
+
+                       return processes;
                }
 
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               private extern static int[] GetProcesses_internal();
+
                [MonoTODO ("There is no support for retrieving process information from a remote machine")]
                public static Process[] GetProcesses(string machineName) {
                        if (machineName == null)
@@ -871,21 +524,14 @@ namespace System.Diagnostics {
                        if (!IsLocalMachine (machineName))
                                throw new NotImplementedException ();
 
-                       return GetProcesses ();
-               }
-
-               public static Process[] GetProcessesByName(string processName)
-               {
                        int [] pids = GetProcesses_internal ();
                        if (pids == null)
                                return new Process [0];
-                       
+
                        var proclist = new List<Process> (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);
+                                       proclist.Add (GetProcessById (pids [i]));
                                } catch (SystemException) {
                                        /* The process might exit
                                         * between
@@ -898,69 +544,61 @@ namespace System.Diagnostics {
                        return proclist.ToArray ();
                }
 
-               [MonoTODO]
-               public static Process[] GetProcessesByName(string processName, string machineName) {
-                       throw new NotImplementedException();
-               }
-
-               public void Kill ()
+               private static bool IsLocalMachine (string machineName)
                {
-                       Close (1);
-               }
-
-               [MonoTODO]
-               public static void LeaveDebugMode() {
-               }
+                       if (machineName == "." || machineName.Length == 0)
+                               return true;
 
-               public void Refresh ()
-               {
-                       // FIXME: should refresh any cached data we might have about
-                       // the process (currently we have none).
+                       return (string.Compare (machineName, Environment.MachineName, true) == 0);
                }
 
 #if MONO_FEATURE_PROCESS_START
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
-                                                                  ref ProcInfo proc_info);
+               private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo, ref ProcInfo procInfo);
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
-                                                                 IntPtr stdin,
-                                                                 IntPtr stdout,
-                                                                 IntPtr stderr,
-                                                                 ref ProcInfo proc_info);
+               private extern static bool CreateProcess_internal(ProcessStartInfo startInfo, IntPtr stdin, IntPtr stdout, IntPtr stderr, ref ProcInfo procInfo);
 
-               private static bool Start_shell (ProcessStartInfo startInfo, Process process)
+               bool StartWithShellExecuteEx (ProcessStartInfo startInfo)
                {
-                       ProcInfo proc_info=new ProcInfo();
-                       bool ret;
+                       if (this.disposed)
+                               throw new ObjectDisposedException (GetType ().Name);
 
-                       if (startInfo.RedirectStandardInput ||
-                           startInfo.RedirectStandardOutput ||
-                           startInfo.RedirectStandardError) {
-                               throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
-                       }
+                       if (!String.IsNullOrEmpty(startInfo.UserName) || (startInfo.Password != null))
+                               throw new InvalidOperationException(SR.GetString(SR.CantStartAsUser));
+
+                       if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError)
+                               throw new InvalidOperationException(SR.GetString(SR.CantRedirectStreams));
+
+                       if (startInfo.StandardErrorEncoding != null)
+                               throw new InvalidOperationException(SR.GetString(SR.StandardErrorEncodingNotAllowed));
+
+                       if (startInfo.StandardOutputEncoding != null)
+                               throw new InvalidOperationException(SR.GetString(SR.StandardOutputEncodingNotAllowed));
 
-                       if (startInfo.HaveEnvVars)
-                               throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
+                       // can't set env vars with ShellExecuteEx...
+                       if (startInfo.environmentVariables != null)
+                               throw new InvalidOperationException(SR.GetString(SR.CantUseEnvVars));
 
-                       FillUserInfo (startInfo, ref proc_info);
+                       ProcInfo procInfo = new ProcInfo();
+                       bool ret;
+
+                       FillUserInfo (startInfo, ref procInfo);
                        try {
-                               ret = ShellExecuteEx_internal (startInfo,
-                                                              ref proc_info);
+                               ret = ShellExecuteEx_internal (startInfo, ref procInfo);
                        } finally {
-                               if (proc_info.Password != IntPtr.Zero)
-                                       Marshal.ZeroFreeBSTR (proc_info.Password);
-                               proc_info.Password = IntPtr.Zero;
+                               if (procInfo.Password != IntPtr.Zero)
+                                       Marshal.ZeroFreeBSTR (procInfo.Password);
+                               procInfo.Password = IntPtr.Zero;
                        }
                        if (!ret) {
-                               throw new Win32Exception (-proc_info.pid);
+                               throw new Win32Exception (-procInfo.pid);
                        }
 
-                       process.process_handle = proc_info.process_handle;
-                       process.pid = proc_info.pid;
-                       process.StartBackgroundWaitForExit ();
-                       return(ret);
+                       SetProcessHandle (new SafeProcessHandle (procInfo.process_handle, true));
+                       SetProcessId (procInfo.pid);
+
+                       return ret;
                }
 
                //
@@ -1012,18 +650,58 @@ namespace System.Diagnostics {
                        }
                }
 
-               static bool Start_noshell (ProcessStartInfo startInfo, Process process)
+               static bool IsWindows
                {
-                       var proc_info = new ProcInfo ();
+                       get
+                       {
+                               PlatformID platform = Environment.OSVersion.Platform;
+                               if (platform == PlatformID.Win32S ||
+                                       platform == PlatformID.Win32Windows ||
+                                       platform == PlatformID.Win32NT ||
+                                       platform == PlatformID.WinCE) {
+                                       return true;
+                               }
+                               return false;
+                       }
+               }
+
+               bool StartWithCreateProcess (ProcessStartInfo startInfo)
+               {
+                       if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
+                               throw new InvalidOperationException (SR.GetString(SR.StandardOutputEncodingNotAllowed));
+
+                       if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
+                               throw new InvalidOperationException (SR.GetString(SR.StandardErrorEncodingNotAllowed));
+
+                       if (this.disposed)
+                               throw new ObjectDisposedException (GetType ().Name);
+
+                       var procInfo = new ProcInfo ();
 
                        if (startInfo.HaveEnvVars) {
-                               string [] strs = new string [startInfo.EnvironmentVariables.Count];
-                               startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
-                               proc_info.envKeys = strs;
+                               List<string> envVariables = null;
+                               StringBuilder sb = null;
+
+                               foreach (DictionaryEntry de in startInfo.EnvironmentVariables) {
+                                       if (de.Value == null)
+                                               continue;
+
+                                       if (envVariables == null)
+                                               envVariables = new List<string> ();
+
+                                       if (sb == null)
+                                               sb = new StringBuilder ();
+                                       else
+                                               sb.Clear ();
 
-                               strs = new string [startInfo.EnvironmentVariables.Count];
-                               startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
-                               proc_info.envValues = strs;
+                                       sb.Append ((string) de.Key);
+                                       sb.Append ('=');
+                                       sb.Append ((string) de.Value);
+
+                                       envVariables.Add (sb.ToString ());
+                               }
+
+                               procInfo.envVariables = envVariables?.ToArray ();
                        }
 
                        MonoIOError error;
@@ -1053,19 +731,16 @@ namespace System.Diagnostics {
                                        stderr_write = MonoIO.ConsoleError;
                                }
 
-                               FillUserInfo (startInfo, ref proc_info);
+                               FillUserInfo (startInfo, ref procInfo);
 
                                //
                                // FIXME: For redirected pipes we need to send descriptors of
                                // stdin_write, stdout_read, stderr_read to child process and
                                // close them there (fork makes exact copy of parent's descriptors)
                                //
-                               if (!CreateProcess_internal (startInfo, stdin_read, stdout_write, stderr_write, ref proc_info)) {
-                                       throw new Win32Exception (-proc_info.pid, 
-                                       "ApplicationName='" + startInfo.FileName +
-                                       "', CommandLine='" + startInfo.Arguments +
-                                       "', CurrentDirectory='" + startInfo.WorkingDirectory +
-                                       "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
+                               if (!CreateProcess_internal (startInfo, stdin_read, stdout_write, stderr_write, ref procInfo)) {
+                                       throw new Win32Exception (-procInfo.pid, "ApplicationName='" + startInfo.FileName + "', CommandLine='" + startInfo.Arguments +
+                                               "', CurrentDirectory='" + startInfo.WorkingDirectory + "', Native error= " + Win32Exception.GetErrorMessage (-procInfo.pid));
                                }
                        } catch {
                                if (startInfo.RedirectStandardInput) {
@@ -1091,28 +766,26 @@ namespace System.Diagnostics {
 
                                throw;
                        } finally {
-                               if (proc_info.Password != IntPtr.Zero) {
-                                       Marshal.ZeroFreeBSTR (proc_info.Password);
-                                       proc_info.Password = IntPtr.Zero;
+                               if (procInfo.Password != IntPtr.Zero) {
+                                       Marshal.ZeroFreeBSTR (procInfo.Password);
+                                       procInfo.Password = IntPtr.Zero;
                                }
                        }
 
-                       process.process_handle = proc_info.process_handle;
-                       process.pid = proc_info.pid;
+                       SetProcessHandle (new SafeProcessHandle (procInfo.process_handle, true));
+                       SetProcessId (procInfo.pid);
                        
+#pragma warning disable 618
+
                        if (startInfo.RedirectStandardInput) {
-                               //
-                               // FIXME: The descriptor needs to be closed but due to wapi io-layer
-                               // not coping with duplicated descriptors any StandardInput write fails
-                               //
-                               // MonoIO.Close (stdin_read, out error);
+                               MonoIO.Close (stdin_read, out error);
 
 #if MOBILE
                                var stdinEncoding = Encoding.Default;
 #else
                                var stdinEncoding = Console.InputEncoding;
 #endif
-                               process.input_stream = new StreamWriter (new FileStream (stdin_write, FileAccess.Write, true, 8192), stdinEncoding) {
+                               standardInput = new StreamWriter (new FileStream (stdin_write, FileAccess.Write, true, 8192), stdinEncoding) {
                                        AutoFlush = true
                                };
                        }
@@ -1122,7 +795,7 @@ namespace System.Diagnostics {
 
                                Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
 
-                               process.output_stream = new StreamReader (new FileStream (stdout_read, FileAccess.Read, true, 8192), stdoutEncoding, true);
+                               standardOutput = new StreamReader (new FileStream (stdout_read, FileAccess.Read, true, 8192), stdoutEncoding, true);
                        }
 
                        if (startInfo.RedirectStandardError) {
@@ -1130,91 +803,26 @@ namespace System.Diagnostics {
 
                                Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
 
-                               process.error_stream = new StreamReader (new FileStream (stderr_read, FileAccess.Read, true, 8192), stderrEncoding, true);
+                               standardError = new StreamReader (new FileStream (stderr_read, FileAccess.Read, true, 8192), stderrEncoding, true);
                        }
-
-                       process.StartBackgroundWaitForExit ();
+#pragma warning restore
 
                        return true;
                }
 
                // Note that ProcInfo.Password must be freed.
-               private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
+               private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo procInfo)
                {
                        if (startInfo.UserName.Length != 0) {
-                               proc_info.UserName = startInfo.UserName;
-                               proc_info.Domain = startInfo.Domain;
+                               procInfo.UserName = startInfo.UserName;
+                               procInfo.Domain = startInfo.Domain;
                                if (startInfo.Password != null)
-                                       proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
+                                       procInfo.Password = Marshal.SecureStringToBSTR (startInfo.Password);
                                else
-                                       proc_info.Password = IntPtr.Zero;
-                               proc_info.LoadUserProfile = startInfo.LoadUserProfile;
+                                       procInfo.Password = IntPtr.Zero;
+                               procInfo.LoadUserProfile = startInfo.LoadUserProfile;
                        }
                }
-
-               private static bool Start_common (ProcessStartInfo startInfo,
-                                                 Process process)
-               {
-                       if (startInfo.FileName.Length == 0)
-                               throw new InvalidOperationException("File name has not been set");
-                       
-                       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");
-                       
-                       if (startInfo.UseShellExecute) {
-                               if (startInfo.UserName.Length != 0)
-                                       throw new InvalidOperationException ("UseShellExecute must be false if an explicit UserName is specified when starting a process");
-                               return (Start_shell (startInfo, process));
-                       } else {
-                               return (Start_noshell (startInfo, process));
-                       }
-               }
-               
-               public bool Start ()
-               {
-                       if (process_handle != IntPtr.Zero) {
-                               Process_free_internal (process_handle);
-                               process_handle = IntPtr.Zero;
-                       }
-                       return Start_common(start_info, this);
-               }
-
-               public static Process Start (ProcessStartInfo startInfo)
-               {
-                       if (startInfo == null)
-                               throw new ArgumentNullException ("startInfo");
-
-                       Process process = new Process();
-                       process.StartInfo = startInfo;
-                       if (Start_common(startInfo, process) && process.process_handle != IntPtr.Zero)
-                               return process;
-                       return null;
-               }
-
-               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 username, SecureString password, string domain) {
-                       return Start(fileName, null, username, password, domain);
-               }
-
-               public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
-                       ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
-                       psi.UserName = username;
-                       psi.Password = password;
-                       psi.Domain = domain;
-                       psi.UseShellExecute = false;
-                       return Start(psi);
-               }
 #else
                [Obsolete ("Process.Start is not supported on the current platform.", true)]
                public bool Start ()
@@ -1253,186 +861,7 @@ namespace System.Diagnostics {
                }
 #endif // MONO_FEATURE_PROCESS_START
 
-               public override string ToString()
-               {
-                       return(base.ToString() + " (" + this.ProcessName + ")");
-               }
-
-               /* Waits up to ms milliseconds for process 'handle' to
-                * exit.  ms can be <0 to mean wait forever.
-                */
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern bool WaitForExit_internal(IntPtr handle, int ms);
-
-               public void WaitForExit ()
-               {
-                       WaitForExit (-1);
-               }
-
-               public bool WaitForExit(int milliseconds) {
-                       int ms = milliseconds;
-                       if (ms == int.MaxValue)
-                               ms = -1;
-
-                       if (process_handle == IntPtr.Zero)
-                               throw new InvalidOperationException ("No process is associated with this object.");
-
-                       if (!WaitForExit_internal (process_handle, ms))
-                               return false;
-
-#if MONO_FEATURE_PROCESS_START
-                       if (async_output != null)
-                               async_output.WaitUtilEOF ();
-
-                       if (async_error != null)
-                               async_error.WaitUtilEOF ();
-#endif // MONO_FEATURE_PROCESS_START
-
-                       if (EnableRaisingEvents)
-                               OnExited ();
-
-                       return true;
-               }
-
-               /* 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 WaitForInputIdle (-1);
-               }
-
-               // The internal call is only implemented properly on Windows.
-               [MonoTODO]
-               public bool WaitForInputIdle(int milliseconds) {
-                       return WaitForInputIdle_internal (process_handle, milliseconds);
-               }
-
-               private static bool IsLocalMachine (string machineName)
-               {
-                       if (machineName == "." || machineName.Length == 0)
-                               return true;
-
-                       return (string.Compare (machineName, Environment.MachineName, true) == 0);
-               }
-
-               [Browsable (true)]
-               [MonitoringDescription ("Raised when it receives output data")]
-               public event DataReceivedEventHandler OutputDataReceived;
-               [Browsable (true)]
-               [MonitoringDescription ("Raised when it receives error data")]
-               public event DataReceivedEventHandler ErrorDataReceived;
-
-#if MONO_FEATURE_PROCESS_START
-               [Flags]
-               enum AsyncModes {
-                       NoneYet = 0,
-                       SyncOutput = 1,
-                       SyncError = 1 << 1,
-                       AsyncOutput = 1 << 2,
-                       AsyncError = 1 << 3
-               }
-
-               AsyncModes async_mode;
-               AsyncStreamReader async_output;
-               AsyncStreamReader async_error;
-
-               [ComVisibleAttribute(false)] 
-               public void BeginOutputReadLine ()
-               {
-                       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 ((async_mode & AsyncModes.SyncOutput) != 0)
-                               throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
-
-                       async_mode |= AsyncModes.AsyncOutput;
-
-                       if (async_output == null)
-                               async_output = new AsyncStreamReader (this, output_stream.BaseStream, new UserCallBack(this.OutputReadNotifyUser), output_stream.CurrentEncoding);
-
-                       async_output.BeginReadLine ();
-               }
-
-               void OutputReadNotifyUser (String data)
-               {
-                       // To avoid ---- between remove handler and raising the event
-                       DataReceivedEventHandler outputDataReceived = OutputDataReceived;
-                       if (outputDataReceived != null) {
-                               if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
-                                       SynchronizingObject.Invoke (outputDataReceived, new object[] { this, new DataReceivedEventArgs (data) });
-                               else
-                                       outputDataReceived (this, new DataReceivedEventArgs (data)); // Call back to user informing data is available.
-                       }
-               }
-
-               [ComVisibleAttribute(false)] 
-               public void CancelOutputRead ()
-               {
-                       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 ((async_mode & AsyncModes.SyncOutput) != 0)
-                               throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
-
-                       if (async_output == null)
-                               throw new InvalidOperationException ("No async operation in progress.");
-
-                       async_output.CancelOperation ();
-
-                       async_mode &= ~AsyncModes.AsyncOutput;
-               }
-
-               [ComVisibleAttribute(false)] 
-               public void BeginErrorReadLine ()
-               {
-                       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.SyncError) != 0)
-                               throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
-
-                       async_mode |= AsyncModes.AsyncError;
-
-                       if (async_error == null)
-                               async_error = new AsyncStreamReader (this, error_stream.BaseStream, new UserCallBack(this.ErrorReadNotifyUser), error_stream.CurrentEncoding);
-
-                       async_error.BeginReadLine ();
-               }
-
-               void ErrorReadNotifyUser (String data)
-               {
-                       // To avoid ---- between remove handler and raising the event
-                       DataReceivedEventHandler errorDataReceived = ErrorDataReceived;
-                       if (errorDataReceived != null) {
-                               if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
-                                       SynchronizingObject.Invoke (errorDataReceived, new object[] { this, new DataReceivedEventArgs (data) });
-                               else
-                                       errorDataReceived (this, new DataReceivedEventArgs (data)); // Call back to user informing data is available.
-                       }
-               }
-
-               [ComVisibleAttribute(false)] 
-               public void CancelErrorRead ()
-               {
-                       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.");
-
-                       if (async_error == null)
-                               throw new InvalidOperationException ("No async operation in progress.");
-
-                       async_error.CancelOperation ();
-
-                       async_mode &= ~AsyncModes.AsyncError;
-               }
-#else
+#if !MONO_FEATURE_PROCESS_START
                [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
                public void BeginOutputReadLine ()
                {
@@ -1456,156 +885,24 @@ namespace System.Diagnostics {
                {
                        throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
                }
-#endif // MONO_FEATURE_PROCESS_START
-
-               [Category ("Behavior")]
-               [MonitoringDescription ("Raised when this process exits.")]
-               public event EventHandler Exited {
-                       add {
-                               if (process_handle != IntPtr.Zero && HasExited) {
-                                       value.BeginInvoke (null, null, null, null);
-                               } else {
-                                       exited_event += value;
-                                       if (exited_event != null)
-                                               StartBackgroundWaitForExit ();
-                               }
-                       }
-                       remove {
-                               exited_event -= value;
-                       }
-               }
-
-               // Closes the system process handle
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern void Process_free_internal(IntPtr handle);
-
-               int disposed;
-
-               protected override void Dispose(bool disposing) {
-                       // Check to see if Dispose has already been called.
-                       if (disposed != 0 || Interlocked.CompareExchange (ref disposed, 1, 0) != 0)
-                               return;
-
-                       // If this is a call to Dispose,
-                       // dispose all managed resources.
-                       if (disposing) {
-#if MONO_FEATURE_PROCESS_START
-                               async_output = null;
-                               async_error = null;
-
-                               if (input_stream != null) {
-                                       if (!input_stream_exposed)
-                                               input_stream.Close ();
-                                       input_stream = null;
-                               }
-                               if (output_stream != null) {
-                                       if (!output_stream_exposed)
-                                               output_stream.Close ();
-                                       output_stream = null;
-                               }
-                               if (error_stream != null) {
-                                       if (!error_stream_exposed)
-                                               error_stream.Close ();
-                                       error_stream = null;
-                               }
-#endif // MONO_FEATURE_PROCESS_START
-                       }
-
-                       // Release unmanaged resources
-
-                       if (process_handle!=IntPtr.Zero) {
-                               Process_free_internal (process_handle);
-                               process_handle = IntPtr.Zero;
-                       }
-
-                       base.Dispose (disposing);
-               }
+#endif // !MONO_FEATURE_PROCESS_START
 
-               ~Process ()
-               {
-                       Dispose (false);
-               }
-
-               int on_exited_called = 0;
-
-               protected void OnExited()
-               {
-                       if (on_exited_called != 0 || Interlocked.CompareExchange (ref on_exited_called, 1, 0) != 0)
-                               return;
-
-                       var cb = exited_event;
-                       if (cb == null)
+               /// <devdoc>
+               ///     Raise the Exited event, but make sure we don't do it more than once.
+               /// </devdoc>
+               /// <internalonly/>
+               void RaiseOnExited() {
+                       if (!watchForExit)
                                return;
-
-                       if (synchronizingObject != null) {
-                               synchronizingObject.BeginInvoke (cb, new object [] { this, EventArgs.Empty });
-                       } else {
-                               foreach (EventHandler d in cb.GetInvocationList ()) {
-                                       try {
-                                               d (this, EventArgs.Empty);
-                                       } catch {
+                       if (!raisedOnExited) {
+                               lock (this) {
+                                       if (!raisedOnExited) {
+                                               raisedOnExited = true;
+                                               OnExited();
                                        }
                                }
                        }
                }
-
-               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 false;
-                       }
-               }
-
-               void StartBackgroundWaitForExit ()
-               {
-                       IntPtr handle = process_handle;
-
-                       if (enable_raising_events == 0)
-                               return;
-                       if (exited_event == null)
-                               return;
-                       if (handle == IntPtr.Zero)
-                               return;
-                       if (background_wait_for_exit_thread != null)
-                               return;
-
-                       Thread t = new Thread (_ => {
-                               if (!WaitForExit_internal (handle, -1))
-                                       return;
-
-                               if (EnableRaisingEvents)
-                                       OnExited ();
-                       });
-
-                       t.IsBackground = true;
-
-                       if (Interlocked.CompareExchange (ref background_wait_for_exit_thread, t, null) == null)
-                               t.Start ();
-               }
-
-               class ProcessWaitHandle : WaitHandle
-               {
-                       [MethodImplAttribute (MethodImplOptions.InternalCall)]
-                       private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
-
-                       public ProcessWaitHandle (IntPtr handle)
-                       {
-                               // 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).
-                       }
-               }
        }
 }