//
// (C) 2002 Ximian, Inc.
// (C) 2003 Andreas Nahr
-// (c) 2004 Novell, Inc. (http://www.novell.com)
+// (c) 2004,2005,2006 Novell, Inc. (http://www.novell.com)
//
//
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-using System;
using System.IO;
+using System.Text;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Security.Permissions;
using System.Collections;
+using System.Security;
using System.Threading;
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)]
+#if NET_2_0
+ [MonitoringDescription ("Represents a system process")]
+#endif
public class Process : Component
{
[StructLayout(LayoutKind.Sequential)]
public int tid;
public string [] envKeys;
public string [] envValues;
+ public string UserName;
+ public string Domain;
+ public IntPtr Password;
+ public bool LoadUserProfile;
};
IntPtr process_handle;
bool already_waiting;
ISynchronizeInvoke synchronizingObject;
EventHandler exited_event;
+ IntPtr stdout_rd;
+ IntPtr stderr_rd;
/* Private constructor called from other methods */
private Process(IntPtr handle, int id) {
void StartExitCallbackIfNeeded ()
{
+#if !NET_2_1
bool start = (!already_waiting && enableRaisingEvents && exited_event != null);
if (start && process_handle != IntPtr.Zero && !HasExited) {
WaitOrTimerCallback cb = new WaitOrTimerCallback (CBOnExit);
ThreadPool.RegisterWaitForSingleObject (h, cb, this, -1, true);
already_waiting = true;
}
+#endif
}
[DefaultValue (false), Browsable (false)]
[MonitoringDescription ("Process identifier.")]
public int Id {
get {
- if (pid == 0) {
+ if (pid == 0)
throw new InvalidOperationException ("Process ID has not been set.");
- }
return(pid);
}
[MonitoringDescription ("The maximum working set for this process.")]
public IntPtr MaxWorkingSet {
get {
- if(HasExited) {
- throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
- }
+ if(HasExited)
+ throw new InvalidOperationException(
+ "The process " + ProcessName +
+ " (ID " + Id + ") has exited");
int min;
int max;
[MonitoringDescription ("The minimum working set for this process.")]
public IntPtr MinWorkingSet {
get {
- if(HasExited) {
- throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
- }
+ if(HasExited)
+ throw new InvalidOperationException(
+ "The process " + ProcessName +
+ " (ID " + Id + ") has exited");
int min;
int max;
- bool ok=GetWorkingSet_internal(process_handle, out min, out max);
- if(ok==false) {
+ bool ok= GetWorkingSet_internal (process_handle, out min, out max);
+ if(!ok)
throw new Win32Exception();
- }
-
- return((IntPtr)min);
+ return ((IntPtr) min);
}
set {
- if(HasExited) {
- throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
- }
+ if(HasExited)
+ throw new InvalidOperationException(
+ "The process " + ProcessName +
+ " (ID " + Id + ") has exited");
- bool ok=SetWorkingSet_internal(process_handle, value.ToInt32(), 0, true);
- if(ok==false) {
+ bool ok = SetWorkingSet_internal (process_handle, value.ToInt32(), 0, true);
+ if (!ok)
throw new Win32Exception();
- }
}
}
* element 0.
*/
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern ProcessModule[] GetModules_internal();
+ private extern ProcessModule[] GetModules_internal(IntPtr handle);
private ProcessModuleCollection module_collection;
[MonitoringDescription ("The modules that are loaded as part of this process.")]
public ProcessModuleCollection Modules {
get {
- if(module_collection==null) {
- module_collection=new ProcessModuleCollection(GetModules_internal());
- }
-
+ if (module_collection == null)
+ module_collection = new ProcessModuleCollection(
+ GetModules_internal (process_handle));
return(module_collection);
}
}
[MonoTODO]
+#if NET_2_0
+ [Obsolete ("Use NonpagedSystemMemorySize64")]
+#endif
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
[MonitoringDescription ("The number of bytes that are not pageable.")]
public int NonpagedSystemMemorySize {
}
[MonoTODO]
+#if NET_2_0
+ [Obsolete ("Use PagedMemorySize64")]
+#endif
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
[MonitoringDescription ("The number of bytes that are paged.")]
public int PagedMemorySize {
}
[MonoTODO]
+#if NET_2_0
+ [Obsolete ("Use PagedSystemMemorySize64")]
+#endif
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
[MonitoringDescription ("The amount of paged system memory in bytes.")]
public int PagedSystemMemorySize {
}
[MonoTODO]
+#if NET_2_0
+ [Obsolete ("Use PeakPagedMemorySize64")]
+#endif
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
[MonitoringDescription ("The maximum amount of paged memory used by this process.")]
public int PeakPagedMemorySize {
}
[MonoTODO]
+#if NET_2_0
+ [Obsolete ("Use PeakVirtualMemorySize64")]
+#endif
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
[MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
public int PeakVirtualMemorySize {
}
[MonoTODO]
+#if NET_2_0
+ [Obsolete ("Use PeakWorkingSet64")]
+#endif
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
[MonitoringDescription ("The maximum amount of system memory used by this process.")]
public int PeakWorkingSet {
}
}
+#if NET_2_0
+ [MonoTODO]
+ [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+ [MonitoringDescription ("The number of bytes that are not pageable.")]
+ [ComVisible (false)]
+ public long NonpagedSystemMemorySize64 {
+ get {
+ return(0);
+ }
+ }
+
+ [MonoTODO]
+ [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+ [MonitoringDescription ("The number of bytes that are paged.")]
+ [ComVisible (false)]
+ public long PagedMemorySize64 {
+ get {
+ return(0);
+ }
+ }
+
+ [MonoTODO]
+ [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+ [MonitoringDescription ("The amount of paged system memory in bytes.")]
+ [ComVisible (false)]
+ public long PagedSystemMemorySize64 {
+ get {
+ return(0);
+ }
+ }
+
+ [MonoTODO]
+ [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+ [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
+ [ComVisible (false)]
+ public long PeakPagedMemorySize64 {
+ get {
+ return(0);
+ }
+ }
+
+ [MonoTODO]
+ [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+ [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
+ [ComVisible (false)]
+ public long PeakVirtualMemorySize64 {
+ get {
+ return(0);
+ }
+ }
+
+ [MonoTODO]
+ [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+ [MonitoringDescription ("The maximum amount of system memory used by this process.")]
+ [ComVisible (false)]
+ public long PeakWorkingSet64 {
+ get {
+ return(0);
+ }
+ }
+#endif
+
[MonoTODO]
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
[MonitoringDescription ("Process will be of higher priority while it is actively used.")]
}
}
- [MonoTODO]
+ [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
[MonitoringDescription ("The relative process priority.")]
public ProcessPriorityClass PriorityClass {
get {
- return(ProcessPriorityClass.Normal);
+ 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))
+ throw new Win32Exception (error);
}
}
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ static extern int GetPriorityClass (IntPtr handle, out int error);
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);
+
[MonoTODO]
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
[MonitoringDescription ("The amount of memory exclusively used by this process.")]
+#if NET_2_0
+ [Obsolete ("Use PrivateMemorySize64")]
+#endif
public int PrivateMemorySize {
get {
return(0);
}
}
- [MonoTODO]
+#if NET_2_0
+ [MonoNotSupported ("")]
+ [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+ [MonitoringDescription ("The session ID for this process.")]
+ public int SessionId {
+ get { throw new NotImplementedException (); }
+ }
+#endif
+
+ /* the meaning of type is as follows: 0: user, 1: system, 2: total */
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private extern static long Times (IntPtr handle, int type);
+
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
[MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
public TimeSpan PrivilegedProcessorTime {
get {
- return(new TimeSpan(0));
+ return new TimeSpan (Times (process_handle, 1));
}
}
* null, assume the process
* has exited
*/
- if(process_name==null) {
+ if (process_name == null)
throw new SystemException("The process has exited");
- }
/* Strip the suffix (if it
* exists) simplistically
[MonitoringDescription ("The standard error stream of this process.")]
public StreamReader StandardError {
get {
- if (error_stream == null) {
+ if (error_stream == null)
throw new InvalidOperationException("Standard error has not been redirected");
- }
+
+#if NET_2_0
+ if ((async_mode & AsyncModes.AsyncError) != 0)
+ throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
+
+ async_mode |= AsyncModes.SyncError;
+#endif
return(error_stream);
}
[MonitoringDescription ("The standard input stream of this process.")]
public StreamWriter StandardInput {
get {
- if (input_stream == null) {
+ if (input_stream == null)
throw new InvalidOperationException("Standard input has not been redirected");
- }
return(input_stream);
}
[MonitoringDescription ("The standard output stream of this process.")]
public StreamReader StandardOutput {
get {
- if (output_stream == null) {
+ if (output_stream == null)
throw new InvalidOperationException("Standard output has not been redirected");
- }
+
+#if NET_2_0
+ if ((async_mode & AsyncModes.AsyncOutput) != 0)
+ throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
+
+ async_mode |= AsyncModes.SyncOutput;
+#endif
return(output_stream);
}
[MonitoringDescription ("Information for the start of this process.")]
public ProcessStartInfo StartInfo {
get {
- if(start_info==null) {
- start_info=new ProcessStartInfo();
- }
-
- return(start_info);
+ if (start_info == null)
+ start_info = new ProcessStartInfo();
+ return start_info;
}
set {
- if(value==null) {
- throw new ArgumentException("value is null");
- }
-
- start_info=value;
+ if (value == null)
+ throw new ArgumentNullException("value");
+ start_info = value;
}
}
[MonitoringDescription ("The number of threads of this process.")]
public ProcessThreadCollection Threads {
get {
- return(null);
+ return ProcessThreadCollection.GetEmpty ();
}
}
- [MonoTODO]
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
[MonitoringDescription ("The total CPU time spent for this process.")]
public TimeSpan TotalProcessorTime {
get {
- return(new TimeSpan(0));
+ return new TimeSpan (Times (process_handle, 2));
}
}
- [MonoTODO]
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
[MonitoringDescription ("The CPU time spent for this process in user mode.")]
public TimeSpan UserProcessorTime {
get {
- return(new TimeSpan(0));
+ return new TimeSpan (Times (process_handle, 0));
}
}
[MonoTODO]
+#if NET_2_0
+ [Obsolete ("Use VirtualMemorySize64")]
+#endif
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
[MonitoringDescription ("The amount of virtual memory currently used for this process.")]
public int VirtualMemorySize {
}
[MonoTODO]
+#if NET_2_0
+ [Obsolete ("Use WorkingSet64")]
+#endif
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
[MonitoringDescription ("The amount of physical memory currently used for this process.")]
public int WorkingSet {
}
}
+#if NET_2_0
+ [MonoTODO]
+ [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+ [MonitoringDescription ("The amount of memory exclusively used by this process.")]
+ [ComVisible (false)]
+ public long PrivateMemorySize64 {
+ get {
+ return(0);
+ }
+ }
+
+ [MonoTODO]
+ [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+ [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
+ [ComVisible (false)]
+ public long VirtualMemorySize64 {
+ get {
+ return(0);
+ }
+ }
+
+ [MonoTODO]
+ [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+ [MonitoringDescription ("The amount of physical memory currently used for this process.")]
+ [ComVisible (false)]
+ public long WorkingSet64 {
+ get {
+ return(0);
+ }
+ }
+#endif
+
public void Close()
{
Dispose (true);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern static int GetPid_internal();
- public static Process GetCurrentProcess() {
- int pid=GetPid_internal();
- IntPtr proc=GetProcess_internal(pid);
+ public static Process GetCurrentProcess()
+ {
+ int pid = GetPid_internal();
+ IntPtr proc = GetProcess_internal(pid);
- if(proc==IntPtr.Zero) {
+ if (proc == IntPtr.Zero)
throw new SystemException("Can't find current process");
- }
- return(new Process(proc, pid));
+ return (new Process (proc, pid));
}
- public static Process GetProcessById(int processId) {
- IntPtr proc=GetProcess_internal(processId);
+ 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());
- }
+ if (proc == IntPtr.Zero)
+ throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
- return(new Process(proc, processId));
+ return (new Process (proc, processId));
}
- [MonoTODO]
+ [MonoTODO ("There is no support for retrieving process information from a remote machine")]
public static Process GetProcessById(int processId, string machineName) {
- throw new NotImplementedException();
+ if (machineName == null)
+ throw new ArgumentNullException ("machineName");
+
+ if (!IsLocalMachine (machineName))
+ throw new NotImplementedException ();
+
+ return GetProcessById (processId);
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern static int[] GetProcesses_internal();
- public static Process[] GetProcesses() {
- int[] pids=GetProcesses_internal();
- ArrayList proclist=new ArrayList();
+ public static Process[] GetProcesses()
+ {
+ int [] pids = GetProcesses_internal ();
+ ArrayList proclist = new ArrayList ();
- for(int i=0; i<pids.Length; i++) {
+ for (int i = 0; i < pids.Length; i++) {
try {
- proclist.Add(GetProcessById(pids[i]));
+ proclist.Add (GetProcessById (pids [i]));
} catch (SystemException) {
/* The process might exit
* between
}
}
- return((Process[])proclist.ToArray(typeof(Process)));
+ return ((Process []) proclist.ToArray (typeof (Process)));
}
- [MonoTODO]
+ [MonoTODO ("There is no support for retrieving process information from a remote machine")]
public static Process[] GetProcesses(string machineName) {
- throw new NotImplementedException();
+ if (machineName == null)
+ throw new ArgumentNullException ("machineName");
+
+ if (!IsLocalMachine (machineName))
+ throw new NotImplementedException ();
+
+ return GetProcesses ();
}
- public static Process[] GetProcessesByName(string processName) {
- Process[] procs=GetProcesses();
- ArrayList proclist=new ArrayList();
+ public static Process[] GetProcessesByName(string processName)
+ {
+ Process [] procs = GetProcesses();
+ ArrayList proclist = new ArrayList();
- for(int i=0; i<procs.Length; i++) {
+ for (int i = 0; i < procs.Length; i++) {
/* Ignore case */
- if(String.Compare(processName,
- procs[i].ProcessName,
- true)==0) {
- proclist.Add(procs[i]);
+ if (String.Compare (processName,
+ procs [i].ProcessName,
+ true) == 0) {
+ proclist.Add (procs [i]);
}
}
- return((Process[])proclist.ToArray(typeof(Process)));
+ return ((Process[]) proclist.ToArray (typeof(Process)));
}
[MonoTODO]
public static void LeaveDebugMode() {
}
- [MonoTODO]
- public void Refresh() {
+ public void Refresh ()
+ {
+ // FIXME: should refresh any cached data we might have about
+ // the process (currently we have none).
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
}
- if (startInfo.HaveEnvVars) {
+ if (startInfo.HaveEnvVars)
throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
- }
- ret = ShellExecuteEx_internal (startInfo,
- ref proc_info);
+ FillUserInfo (startInfo, ref proc_info);
+ try {
+ ret = ShellExecuteEx_internal (startInfo,
+ ref proc_info);
+ } finally {
+ if (proc_info.Password != IntPtr.Zero)
+ Marshal.FreeBSTR (proc_info.Password);
+ proc_info.Password = IntPtr.Zero;
+ }
if (!ret) {
throw new Win32Exception (-proc_info.pid);
}
{
ProcInfo proc_info=new ProcInfo();
IntPtr stdin_rd, stdin_wr;
- IntPtr stdout_rd, stdout_wr;
- IntPtr stderr_rd, stderr_wr;
+ IntPtr stdout_wr;
+ IntPtr stderr_wr;
bool ret;
+ MonoIOError error;
if (startInfo.HaveEnvVars) {
string [] strs = new string [startInfo.EnvironmentVariables.Count];
} else {
stdin_rd = MonoIO.ConsoleInput;
/* This is required to stop the
- * &$*£ing stupid compiler moaning
+ * &$*£ing stupid compiler moaning
* that stdin_wr is unassigned, below.
*/
stdin_wr = (IntPtr)0;
}
if (startInfo.RedirectStandardOutput == true) {
- ret = MonoIO.CreatePipe (out stdout_rd,
+ IntPtr out_rd;
+ ret = MonoIO.CreatePipe (out out_rd,
out stdout_wr);
+
+ process.stdout_rd = out_rd;
if (ret == false) {
+ if (startInfo.RedirectStandardInput == true) {
+ MonoIO.Close (stdin_rd, out error);
+ MonoIO.Close (stdin_wr, out error);
+ }
+
throw new IOException ("Error creating standard output pipe");
}
} else {
- stdout_rd = (IntPtr)0;
+ process.stdout_rd = (IntPtr)0;
stdout_wr = MonoIO.ConsoleOutput;
}
if (startInfo.RedirectStandardError == true) {
- ret = MonoIO.CreatePipe (out stderr_rd,
+ IntPtr err_rd;
+ ret = MonoIO.CreatePipe (out err_rd,
out stderr_wr);
+
+ process.stderr_rd = err_rd;
if (ret == false) {
+ if (startInfo.RedirectStandardInput == true) {
+ MonoIO.Close (stdin_rd, out error);
+ MonoIO.Close (stdin_wr, out error);
+ }
+ if (startInfo.RedirectStandardOutput == true) {
+ MonoIO.Close (process.stdout_rd, out error);
+ MonoIO.Close (stdout_wr, out error);
+ }
+
throw new IOException ("Error creating standard error pipe");
}
} else {
- stderr_rd = (IntPtr)0;
+ process.stderr_rd = (IntPtr)0;
stderr_wr = MonoIO.ConsoleError;
}
-
- ret = CreateProcess_internal (startInfo,
- stdin_rd, stdout_wr, stderr_wr,
- ref proc_info);
- MonoIOError error;
-
+ FillUserInfo (startInfo, ref proc_info);
+ try {
+ ret = CreateProcess_internal (startInfo,
+ stdin_rd, stdout_wr, stderr_wr,
+ ref proc_info);
+ } finally {
+ if (proc_info.Password != IntPtr.Zero)
+ Marshal.FreeBSTR (proc_info.Password);
+ proc_info.Password = IntPtr.Zero;
+ }
if (!ret) {
- if (startInfo.RedirectStandardInput == true)
+ if (startInfo.RedirectStandardInput == true) {
MonoIO.Close (stdin_rd, out error);
+ MonoIO.Close (stdin_wr, out error);
+ }
- if (startInfo.RedirectStandardOutput == true)
+ if (startInfo.RedirectStandardOutput == true) {
+ MonoIO.Close (process.stdout_rd, out error);
MonoIO.Close (stdout_wr, out error);
+ }
- if (startInfo.RedirectStandardError == true)
+ if (startInfo.RedirectStandardError == true) {
+ MonoIO.Close (process.stderr_rd, out error);
MonoIO.Close (stderr_wr, out error);
+ }
- throw new Win32Exception (-proc_info.pid);
+ throw new Win32Exception (-proc_info.pid,
+ "ApplicationName='" + startInfo.FileName +
+ "', CommandLine='" + startInfo.Arguments +
+ "', CurrentDirectory='" + startInfo.WorkingDirectory + "'");
}
process.process_handle = proc_info.process_handle;
if (startInfo.RedirectStandardInput == true) {
MonoIO.Close (stdin_rd, out error);
- process.input_stream = new StreamWriter (new FileStream (stdin_wr, FileAccess.Write, true));
+ process.input_stream = new StreamWriter (new MonoSyncFileStream (stdin_wr, FileAccess.Write, true, 8192), Console.Out.Encoding);
process.input_stream.AutoFlush = true;
}
+#if NET_2_0
+ Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
+ Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
+#else
+ Encoding stdoutEncoding = Console.Out.Encoding;
+ Encoding stderrEncoding = stdoutEncoding;
+#endif
+
if (startInfo.RedirectStandardOutput == true) {
MonoIO.Close (stdout_wr, out error);
- process.output_stream = new StreamReader (new FileStream (stdout_rd, FileAccess.Read, true));
+ process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding);
}
if (startInfo.RedirectStandardError == true) {
MonoIO.Close (stderr_wr, out error);
- process.error_stream = new StreamReader (new FileStream (stderr_rd, FileAccess.Read, true));
+ process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding);
}
process.StartExitCallbackIfNeeded ();
return(ret);
}
+ // Note that ProcInfo.Password must be freed.
+ private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
+ {
+#if NET_2_0
+ if (startInfo.UserName != null) {
+ proc_info.UserName = startInfo.UserName;
+ proc_info.Domain = startInfo.Domain;
+ if (startInfo.Password != null)
+ proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
+ else
+ proc_info.Password = IntPtr.Zero;
+ proc_info.LoadUserProfile = startInfo.LoadUserProfile;
+ }
+#endif
+ }
+
private static bool Start_common (ProcessStartInfo startInfo,
Process process)
{
- if(startInfo.FileName == null ||
- startInfo.FileName == "") {
+ if (startInfo.FileName == null || startInfo.FileName.Length == 0)
throw new InvalidOperationException("File name has not been set");
- }
+
+#if NET_2_0
+ if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
+ throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
+ if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
+ throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
+#endif
if (startInfo.UseShellExecute) {
+#if NET_2_0
+ if (startInfo.UserName != null)
+ throw new InvalidOperationException ("UserShellExecute must be false if an explicit UserName is specified when starting a process");
+#endif
return (Start_shell (startInfo, process));
} else {
return (Start_noshell (startInfo, process));
}
}
- public bool Start() {
- bool ret;
-
- ret=Start_common(start_info, this);
-
- return(ret);
+ 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) {
+ public static Process Start (ProcessStartInfo startInfo)
+ {
+ if (startInfo == null)
+ throw new ArgumentNullException ("startInfo");
+
Process process=new Process();
- bool ret;
+ process.StartInfo = startInfo;
+ if (Start_common(startInfo, process))
+ return process;
+ return null;
+ }
- ret=Start_common(startInfo, process);
-
- if(ret==true) {
- return(process);
- } else {
- 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) {
- return Start(new ProcessStartInfo(fileName));
+#if NET_2_0
+ 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) {
- return Start(new ProcessStartInfo(fileName, arguments));
+ 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);
}
+#endif
- public override string ToString() {
- return(base.ToString() +
- " (" + this.ProcessName + ")");
+ public override string ToString()
+ {
+ return(base.ToString() + " (" + this.ProcessName + ")");
}
/* Waits up to ms milliseconds for process 'handle' to
* exit. ms can be <0 to mean wait forever.
*/
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern bool WaitForExit_internal(IntPtr handle,
- int ms);
+ private extern bool WaitForExit_internal(IntPtr handle, int ms);
- public void WaitForExit() {
- WaitForExit_internal(process_handle, -1);
+ public void WaitForExit ()
+ {
+ WaitForExit (-1);
}
public bool WaitForExit(int milliseconds) {
- if (milliseconds == int.MaxValue)
- milliseconds = -1;
+ int ms = milliseconds;
+ if (ms == int.MaxValue)
+ ms = -1;
+
+#if NET_2_0
+ DateTime start = DateTime.UtcNow;
+ if (async_output != null && !async_output.IsCompleted) {
+ if (false == async_output.WaitHandle.WaitOne (ms, false))
+ return false; // Timed out
+
+ if (ms >= 0) {
+ DateTime now = DateTime.UtcNow;
+ ms -= (int) (now - start).TotalMilliseconds;
+ if (ms <= 0)
+ return false;
+ start = now;
+ }
+ }
- return WaitForExit_internal (process_handle, milliseconds);
+ if (async_error != null && !async_error.IsCompleted) {
+ if (false == async_error.WaitHandle.WaitOne (ms, false))
+ return false; // Timed out
+
+ if (ms >= 0) {
+ ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
+ if (ms <= 0)
+ return false;
+ }
+ }
+#endif
+ return WaitForExit_internal (process_handle, ms);
}
[MonoTODO]
return(false);
}
+ private static bool IsLocalMachine (string machineName)
+ {
+ if (machineName == "." || machineName.Length == 0)
+ return true;
+
+ return (string.Compare (machineName, Environment.MachineName, true) == 0);
+ }
+
+#if NET_2_0
+ [Browsable (true)]
+ [MonitoringDescription ("Raised when it receives output data")]
+ public event DataReceivedEventHandler OutputDataReceived;
+ [Browsable (true)]
+ [MonitoringDescription ("Raised when it receives error data")]
+ public event DataReceivedEventHandler ErrorDataReceived;
+
+ void OnOutputDataReceived (string str)
+ {
+ if (OutputDataReceived != null)
+ OutputDataReceived (this, new DataReceivedEventArgs (str));
+ }
+
+ void OnErrorDataReceived (string str)
+ {
+ if (ErrorDataReceived != null)
+ ErrorDataReceived (this, new DataReceivedEventArgs (str));
+ }
+
+ [Flags]
+ enum AsyncModes {
+ NoneYet = 0,
+ SyncOutput = 1,
+ SyncError = 1 << 1,
+ AsyncOutput = 1 << 2,
+ AsyncError = 1 << 3
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ sealed class ProcessAsyncReader
+ {
+ /*
+ The following fields match those of SocketAsyncResult.
+ This is so that changes needed in the runtime to handle
+ asynchronous reads are trivial
+ */
+ /* DON'T shuffle fields around. DON'T remove fields */
+ public object Sock;
+ public IntPtr handle;
+ public object state;
+ public AsyncCallback callback;
+ public ManualResetEvent wait_handle;
+
+ public Exception delayedException;
+
+ public object EndPoint;
+ byte [] buffer = new byte [4196];
+ public int Offset;
+ public int Size;
+ public int SockFlags;
+
+ public object acc_socket;
+ public int total;
+ public bool completed_sync;
+ bool completed;
+ bool err_out; // true -> stdout, false -> stderr
+ internal int error;
+ public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
+ public object ares;
+
+
+ // These fields are not in SocketAsyncResult
+ Process process;
+ Stream stream;
+ StringBuilder sb = new StringBuilder ();
+ public AsyncReadHandler ReadHandler;
+
+ public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
+ {
+ this.process = process;
+ this.handle = handle;
+ stream = new FileStream (handle, FileAccess.Read, false);
+ this.ReadHandler = new AsyncReadHandler (AddInput);
+ this.err_out = err_out;
+ }
+
+ public void AddInput ()
+ {
+ lock (this) {
+ int nread = stream.Read (buffer, 0, buffer.Length);
+ if (nread == 0) {
+ completed = true;
+ if (wait_handle != null)
+ wait_handle.Set ();
+ Flush (true);
+ return;
+ }
+
+ try {
+ sb.Append (Encoding.Default.GetString (buffer, 0, nread));
+ } catch {
+ // Just in case the encoding fails...
+ for (int i = 0; i < nread; i++) {
+ sb.Append ((char) buffer [i]);
+ }
+ }
+
+ Flush (false);
+ ReadHandler.BeginInvoke (null, this);
+ }
+ }
+
+ void Flush (bool last)
+ {
+ if (sb.Length == 0 ||
+ (err_out && process.output_canceled) ||
+ (!err_out && process.error_canceled))
+ return;
+
+ string total = sb.ToString ();
+ sb.Length = 0;
+ string [] strs = total.Split ('\n');
+ int len = strs.Length;
+ if (len == 0)
+ return;
+
+ for (int i = 0; i < len - 1; i++) {
+ if (err_out)
+ process.OnOutputDataReceived (strs [i]);
+ else
+ process.OnErrorDataReceived (strs [i]);
+ }
+
+ string end = strs [len - 1];
+ if (last || (len == 1 && end == "")) {
+ if (err_out) {
+ process.OnOutputDataReceived (end);
+ } else {
+ process.OnErrorDataReceived (end);
+ }
+ } else {
+ sb.Append (end);
+ }
+ }
+
+ public bool IsCompleted {
+ get { return completed; }
+ }
+
+ public WaitHandle WaitHandle {
+ get {
+ lock (this) {
+ if (wait_handle == null)
+ wait_handle = new ManualResetEvent (completed);
+ return wait_handle;
+ }
+ }
+ }
+ }
+
+ AsyncModes async_mode;
+ bool output_canceled;
+ bool error_canceled;
+ ProcessAsyncReader async_output;
+ ProcessAsyncReader async_error;
+ delegate void AsyncReadHandler ();
+
+ [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;
+ output_canceled = false;
+ if (async_output == null) {
+ async_output = new ProcessAsyncReader (this, stdout_rd, true);
+ async_output.ReadHandler.BeginInvoke (null, async_output);
+ }
+ }
+
+ [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.");
+
+ output_canceled = true;
+ }
+
+ [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;
+ error_canceled = false;
+ if (async_error == null) {
+ async_error = new ProcessAsyncReader (this, stderr_rd, false);
+ async_error.ReadHandler.BeginInvoke (null, async_error);
+ }
+ }
+
+ [ComVisibleAttribute(false)]
+ public void CancelErrorRead ()
+ {
+ if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
+ throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
+
+ if ((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.");
+
+ error_canceled = true;
+ }
+#endif
+
[Category ("Behavior")]
[MonitoringDescription ("Raised when this process exits.")]
public event EventHandler Exited {
base.Dispose (disposing);
}
+ ~Process ()
+ {
+ Dispose (false);
+ }
+
static void CBOnExit (object state, bool unused)
{
Process p = (Process) state;