Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Henry <ludovic@xamarin.com>2016-02-08 21:56:29 +0300
committerLudovic Henry <ludovic@xamarin.com>2016-02-12 16:56:38 +0300
commitd30e99d172ec5074ce6deb44bc37f9a9ecaef7fe (patch)
tree94a5b3d3df3e72acc7d652f09ea0d1d8e7d131d9 /mcs/class/System/System.Diagnostics/Process.cs
parent35889d4bc2be1f5e7a68623e3fc33cf24080c2ee (diff)
[System] Import System.Diagnostics.Process
Diffstat (limited to 'mcs/class/System/System.Diagnostics/Process.cs')
-rw-r--r--mcs/class/System/System.Diagnostics/Process.cs1049
1 files changed, 171 insertions, 878 deletions
diff --git a/mcs/class/System/System.Diagnostics/Process.cs b/mcs/class/System/System.Diagnostics/Process.cs
index 46224521045..09340e7d045 100644
--- a/mcs/class/System/System.Diagnostics/Process.cs
+++ b/mcs/class/System/System.Diagnostics/Process.cs
@@ -43,16 +43,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
@@ -74,21 +70,12 @@ namespace System.Diagnostics {
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) {
+ m_processHandle = 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.")]
@@ -169,44 +95,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 {
get {
@@ -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);
}
}
@@ -506,54 +305,45 @@ namespace System.Diagnostics {
get { throw new NotImplementedException (); }
}
- /* the meaning of type is as follows: 0: user, 1: system, 2: total */
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static long Times (IntPtr handle, int type);
+ 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,56 +451,23 @@ 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");
-
- return (new Process (proc, pid));
- }
public static Process GetProcessById(int processId)
{
@@ -824,7 +476,7 @@ namespace System.Diagnostics {
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")]
@@ -903,51 +555,48 @@ namespace System.Diagnostics {
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 proc_info);
[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 proc_info);
- 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.HaveEnvVars)
- throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
+ if (startInfo.StandardErrorEncoding != null)
+ throw new InvalidOperationException(SR.GetString(SR.StandardErrorEncodingNotAllowed));
+
+ if (startInfo.StandardOutputEncoding != null)
+ throw new InvalidOperationException(SR.GetString(SR.StandardOutputEncodingNotAllowed));
+
+ // can't set env vars with ShellExecuteEx...
+ if (startInfo.environmentVariables != null)
+ throw new InvalidOperationException(SR.GetString(SR.CantUseEnvVars));
+
+ ProcInfo proc_info = new ProcInfo();
+ bool ret;
FillUserInfo (startInfo, ref proc_info);
try {
- ret = ShellExecuteEx_internal (startInfo,
- ref proc_info);
+ ret = ShellExecuteEx_internal (startInfo, ref proc_info);
} finally {
if (proc_info.Password != IntPtr.Zero)
Marshal.ZeroFreeBSTR (proc_info.Password);
@@ -957,10 +606,13 @@ namespace System.Diagnostics {
throw new Win32Exception (-proc_info.pid);
}
- process.process_handle = proc_info.process_handle;
- process.pid = proc_info.pid;
- process.StartBackgroundWaitForExit ();
- return(ret);
+ m_processHandle = new SafeProcessHandle (proc_info.process_handle, true);
+ haveProcessHandle = true;
+ SetProcessId (proc_info.pid);
+
+ EnsureWatchingForExit ();
+
+ return ret;
}
//
@@ -1012,8 +664,32 @@ namespace System.Diagnostics {
}
}
- static bool Start_noshell (ProcessStartInfo startInfo, Process process)
+ 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;
+ }
+ }
+
+ 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 proc_info = new ProcInfo ();
if (startInfo.HaveEnvVars) {
@@ -1061,11 +737,8 @@ namespace System.Diagnostics {
// 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));
+ throw new Win32Exception (-proc_info.pid, "ApplicationName='" + startInfo.FileName + "', CommandLine='" + startInfo.Arguments +
+ "', CurrentDirectory='" + startInfo.WorkingDirectory + "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
}
} catch {
if (startInfo.RedirectStandardInput) {
@@ -1097,8 +770,9 @@ namespace System.Diagnostics {
}
}
- process.process_handle = proc_info.process_handle;
- process.pid = proc_info.pid;
+ m_processHandle = new SafeProcessHandle (proc_info.process_handle, true);
+ haveProcessHandle = true;
+ SetProcessId (proc_info.pid);
if (startInfo.RedirectStandardInput) {
//
@@ -1112,7 +786,7 @@ namespace System.Diagnostics {
#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 +796,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,10 +804,10 @@ 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 ();
+ EnsureWatchingForExit ();
return true;
}
@@ -1151,70 +825,6 @@ namespace System.Diagnostics {
proc_info.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,192 +863,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.");
-
- if ((async_mode & AsyncModes.AsyncOutput) != 0)
- throw new InvalidOperationException ("An async read operation has already been started on the stream.");
-
- 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.");
-
- if ((async_mode & AsyncModes.AsyncError) != 0)
- throw new InvalidOperationException ("An async read operation has already been started on the stream.");
-
- 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 ()
{
@@ -1462,156 +887,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);
- }
-
- ~Process ()
- {
- Dispose (false);
- }
-
- int on_exited_called = 0;
+#endif // !MONO_FEATURE_PROCESS_START
- 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).
- }
- }
}
}