2 // System.Diagnostics.Process.cs
5 // Dick Porter (dick@ximian.com)
6 // Andreas Nahr (ClassDevelopment@A-SoftTech.com)
7 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 // (C) 2002 Ximian, Inc.
10 // (C) 2003 Andreas Nahr
11 // (c) 2004,2005,2006 Novell, Inc. (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 using System.ComponentModel;
38 using System.ComponentModel.Design;
39 using System.Runtime.CompilerServices;
40 using System.Runtime.InteropServices;
41 using System.Security.Permissions;
42 using System.Collections;
43 using System.Threading;
45 namespace System.Diagnostics {
47 [DefaultEvent ("Exited"), DefaultProperty ("StartInfo")]
48 [Designer ("System.Diagnostics.Design.ProcessDesigner, " + Consts.AssemblySystem_Design)]
49 [PermissionSet (SecurityAction.LinkDemand, Unrestricted = true)]
50 [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
51 public class Process : Component
53 [StructLayout(LayoutKind.Sequential)]
54 private struct ProcInfo
56 public IntPtr process_handle;
57 /* If thread_handle is ever needed for
58 * something, take out the CloseHandle() in
59 * the Start_internal icall in
60 * mono/metadata/process.c
62 public IntPtr thread_handle;
63 public int pid; // Contains -GetLastError () on failure.
65 public string [] envKeys;
66 public string [] envValues;
69 IntPtr process_handle;
71 bool enableRaisingEvents;
73 ISynchronizeInvoke synchronizingObject;
74 EventHandler exited_event;
78 /* Private constructor called from other methods */
79 private Process(IntPtr handle, int id) {
80 process_handle=handle;
89 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
90 [MonitoringDescription ("Base process priority.")]
91 public int BasePriority {
97 void StartExitCallbackIfNeeded ()
99 bool start = (!already_waiting && enableRaisingEvents && exited_event != null);
100 if (start && process_handle != IntPtr.Zero && !HasExited) {
101 WaitOrTimerCallback cb = new WaitOrTimerCallback (CBOnExit);
102 ProcessWaitHandle h = new ProcessWaitHandle (process_handle);
103 ThreadPool.RegisterWaitForSingleObject (h, cb, this, -1, true);
104 already_waiting = true;
108 [DefaultValue (false), Browsable (false)]
109 [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
110 public bool EnableRaisingEvents {
112 return enableRaisingEvents;
115 bool prev = enableRaisingEvents;
116 enableRaisingEvents = value;
117 if (enableRaisingEvents && !prev)
118 StartExitCallbackIfNeeded ();
123 [MethodImplAttribute(MethodImplOptions.InternalCall)]
124 private extern static int ExitCode_internal(IntPtr handle);
126 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
127 [MonitoringDescription ("The exit code of the process.")]
128 public int ExitCode {
130 if (process_handle == IntPtr.Zero)
131 throw new InvalidOperationException ("Process has not been started.");
133 int code = ExitCode_internal (process_handle);
135 throw new InvalidOperationException ("The process must exit before " +
136 "getting the requested information.");
142 /* Returns the process start time in Windows file
143 * times (ticks from DateTime(1/1/1601 00:00 GMT))
145 [MethodImplAttribute(MethodImplOptions.InternalCall)]
146 private extern static long ExitTime_internal(IntPtr handle);
148 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
149 [MonitoringDescription ("The exit time of the process.")]
150 public DateTime ExitTime {
152 if (process_handle == IntPtr.Zero)
153 throw new InvalidOperationException ("Process has not been started.");
156 throw new InvalidOperationException ("The process must exit before " +
157 "getting the requested information.");
159 return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
163 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
164 [MonitoringDescription ("Handle for this process.")]
165 public IntPtr Handle {
167 return(process_handle);
172 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
173 [MonitoringDescription ("Handles for this process.")]
174 public int HandleCount {
180 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
181 [MonitoringDescription ("Determines if the process is still running.")]
182 public bool HasExited {
184 if (process_handle == IntPtr.Zero)
185 throw new InvalidOperationException ("Process has not been started.");
187 int exitcode = ExitCode_internal (process_handle);
198 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
199 [MonitoringDescription ("Process identifier.")]
203 throw new InvalidOperationException ("Process ID has not been set.");
211 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
212 [MonitoringDescription ("The name of the computer running the process.")]
213 public string MachineName {
219 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
220 [MonitoringDescription ("The main module of the process.")]
221 public ProcessModule MainModule {
223 return(this.Modules[0]);
228 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
229 [MonitoringDescription ("The handle of the main window of the process.")]
230 public IntPtr MainWindowHandle {
237 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
238 [MonitoringDescription ("The title of the main window of the process.")]
239 public string MainWindowTitle {
245 [MethodImplAttribute(MethodImplOptions.InternalCall)]
246 private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
247 [MethodImplAttribute(MethodImplOptions.InternalCall)]
248 private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);
250 /* LAMESPEC: why is this an IntPtr not a plain int? */
251 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
252 [MonitoringDescription ("The maximum working set for this process.")]
253 public IntPtr MaxWorkingSet {
256 throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
261 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
263 throw new Win32Exception();
270 throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
273 bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
275 throw new Win32Exception();
280 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
281 [MonitoringDescription ("The minimum working set for this process.")]
282 public IntPtr MinWorkingSet {
285 throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
290 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
292 throw new Win32Exception();
299 throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
302 bool ok=SetWorkingSet_internal(process_handle, value.ToInt32(), 0, true);
304 throw new Win32Exception();
309 /* Returns the list of process modules. The main module is
312 [MethodImplAttribute(MethodImplOptions.InternalCall)]
313 private extern ProcessModule[] GetModules_internal();
315 private ProcessModuleCollection module_collection;
317 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
318 [MonitoringDescription ("The modules that are loaded as part of this process.")]
319 public ProcessModuleCollection Modules {
321 if(module_collection==null) {
322 module_collection=new ProcessModuleCollection(GetModules_internal());
325 return(module_collection);
331 [Obsolete ("Use NonpagedSystemMemorySize64")]
333 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
334 [MonitoringDescription ("The number of bytes that are not pageable.")]
335 public int NonpagedSystemMemorySize {
343 [Obsolete ("Use PagedMemorySize64")]
345 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
346 [MonitoringDescription ("The number of bytes that are paged.")]
347 public int PagedMemorySize {
355 [Obsolete ("Use PagedSystemMemorySize64")]
357 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
358 [MonitoringDescription ("The amount of paged system memory in bytes.")]
359 public int PagedSystemMemorySize {
367 [Obsolete ("Use PeakPagedMemorySize64")]
369 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
370 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
371 public int PeakPagedMemorySize {
379 [Obsolete ("Use PeakVirtualMemorySize64")]
381 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
382 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
383 public int PeakVirtualMemorySize {
391 [Obsolete ("Use PeakWorkingSet64")]
393 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
394 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
395 public int PeakWorkingSet {
403 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
404 [MonitoringDescription ("The number of bytes that are not pageable.")]
405 public long NonpagedSystemMemorySize64 {
412 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
413 [MonitoringDescription ("The number of bytes that are paged.")]
414 public long PagedMemorySize64 {
421 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
422 [MonitoringDescription ("The amount of paged system memory in bytes.")]
423 public long PagedSystemMemorySize64 {
430 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
431 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
432 public long PeakPagedMemorySize64 {
439 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
440 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
441 public long PeakVirtualMemorySize64 {
448 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
449 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
450 public long PeakWorkingSet64 {
458 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
459 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
460 public bool PriorityBoostEnabled {
469 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
470 [MonitoringDescription ("The relative process priority.")]
471 public ProcessPriorityClass PriorityClass {
473 return(ProcessPriorityClass.Normal);
480 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
481 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
482 public int PrivateMemorySize {
489 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
490 [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
491 public TimeSpan PrivilegedProcessorTime {
493 return(new TimeSpan(0));
497 [MethodImplAttribute(MethodImplOptions.InternalCall)]
498 private extern static string ProcessName_internal(IntPtr handle);
500 private string process_name=null;
502 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
503 [MonitoringDescription ("The name of this process.")]
504 public string ProcessName {
506 if(process_name==null) {
507 process_name=ProcessName_internal(process_handle);
508 /* If process_name is _still_
509 * null, assume the process
512 if(process_name==null) {
513 throw new SystemException("The process has exited");
516 /* Strip the suffix (if it
517 * exists) simplistically
518 * instead of removing any
519 * trailing \.???, so we dont
520 * get stupid results on sane
523 if(process_name.EndsWith(".exe") ||
524 process_name.EndsWith(".bat") ||
525 process_name.EndsWith(".com")) {
526 process_name=process_name.Substring(0, process_name.Length-4);
529 return(process_name);
534 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
535 [MonitoringDescription ("Allowed processor that can be used by this process.")]
536 public IntPtr ProcessorAffinity {
545 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
546 [MonitoringDescription ("Is this process responsive.")]
547 public bool Responding {
553 private StreamReader error_stream=null;
555 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
556 [MonitoringDescription ("The standard error stream of this process.")]
557 public StreamReader StandardError {
559 if (error_stream == null) {
560 throw new InvalidOperationException("Standard error has not been redirected");
563 if ((async_mode & AsyncModes.AsyncError) != 0)
564 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
566 async_mode |= AsyncModes.SyncError;
569 return(error_stream);
573 private StreamWriter input_stream=null;
575 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
576 [MonitoringDescription ("The standard input stream of this process.")]
577 public StreamWriter StandardInput {
579 if (input_stream == null) {
580 throw new InvalidOperationException("Standard input has not been redirected");
583 return(input_stream);
587 private StreamReader output_stream=null;
589 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
590 [MonitoringDescription ("The standard output stream of this process.")]
591 public StreamReader StandardOutput {
593 if (output_stream == null) {
594 throw new InvalidOperationException("Standard output has not been redirected");
597 if ((async_mode & AsyncModes.AsyncOutput) != 0)
598 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
600 async_mode |= AsyncModes.SyncOutput;
603 return(output_stream);
607 private ProcessStartInfo start_info=null;
609 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
610 [MonitoringDescription ("Information for the start of this process.")]
611 public ProcessStartInfo StartInfo {
613 if(start_info==null) {
614 start_info=new ProcessStartInfo();
621 throw new ArgumentException("value is null");
628 /* Returns the process start time in Windows file
629 * times (ticks from DateTime(1/1/1601 00:00 GMT))
631 [MethodImplAttribute(MethodImplOptions.InternalCall)]
632 private extern static long StartTime_internal(IntPtr handle);
634 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
635 [MonitoringDescription ("The time this process started.")]
636 public DateTime StartTime {
638 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
642 [DefaultValue (null), Browsable (false)]
643 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
644 public ISynchronizeInvoke SynchronizingObject {
645 get { return synchronizingObject; }
646 set { synchronizingObject = value; }
650 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
651 [MonitoringDescription ("The number of threads of this process.")]
652 public ProcessThreadCollection Threads {
659 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
660 [MonitoringDescription ("The total CPU time spent for this process.")]
661 public TimeSpan TotalProcessorTime {
663 return(new TimeSpan(0));
668 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
669 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
670 public TimeSpan UserProcessorTime {
672 return(new TimeSpan(0));
678 [Obsolete ("Use VirtualMemorySize64")]
680 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
681 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
682 public int VirtualMemorySize {
690 [Obsolete ("Use WorkingSet64")]
692 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
693 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
694 public int WorkingSet {
702 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
703 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
704 public long VirtualMemorySize64 {
711 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
712 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
713 public long WorkingSet64 {
725 [MethodImplAttribute(MethodImplOptions.InternalCall)]
726 extern static bool Kill_internal (IntPtr handle, int signo);
728 /* int kill -> 1 KILL, 2 CloseMainWindow */
729 bool Close (int signo)
731 if (process_handle == IntPtr.Zero)
732 throw new SystemException ("No process to kill.");
734 int exitcode = ExitCode_internal (process_handle);
736 throw new InvalidOperationException ("The process already finished.");
738 return Kill_internal (process_handle, signo);
741 public bool CloseMainWindow ()
747 public static void EnterDebugMode() {
750 [MethodImplAttribute(MethodImplOptions.InternalCall)]
751 private extern static IntPtr GetProcess_internal(int pid);
753 [MethodImplAttribute(MethodImplOptions.InternalCall)]
754 private extern static int GetPid_internal();
756 public static Process GetCurrentProcess()
758 int pid = GetPid_internal();
759 IntPtr proc = GetProcess_internal(pid);
761 if (proc == IntPtr.Zero) {
762 throw new SystemException("Can't find current process");
765 return (new Process (proc, pid));
768 public static Process GetProcessById(int processId)
770 IntPtr proc = GetProcess_internal(processId);
772 if (proc == IntPtr.Zero) {
773 throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
776 return (new Process (proc, processId));
780 public static Process GetProcessById(int processId, string machineName) {
781 throw new NotImplementedException();
784 [MethodImplAttribute(MethodImplOptions.InternalCall)]
785 private extern static int[] GetProcesses_internal();
787 public static Process[] GetProcesses()
789 int [] pids = GetProcesses_internal ();
790 ArrayList proclist = new ArrayList ();
792 for (int i = 0; i < pids.Length; i++) {
794 proclist.Add (GetProcessById (pids [i]));
795 } catch (SystemException) {
796 /* The process might exit
798 * GetProcesses_internal and
804 return ((Process []) proclist.ToArray (typeof (Process)));
807 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
808 public static Process[] GetProcesses(string machineName) {
809 throw new NotImplementedException();
812 public static Process[] GetProcessesByName(string processName)
814 Process [] procs = GetProcesses();
815 ArrayList proclist = new ArrayList();
817 for (int i = 0; i < procs.Length; i++) {
819 if (String.Compare (processName,
820 procs [i].ProcessName,
822 proclist.Add (procs [i]);
826 return ((Process[]) proclist.ToArray (typeof(Process)));
830 public static Process[] GetProcessesByName(string processName, string machineName) {
831 throw new NotImplementedException();
840 public static void LeaveDebugMode() {
843 public void Refresh ()
845 // FIXME: should refresh any cached data we might have about
846 // the process (currently we have none).
849 [MethodImplAttribute(MethodImplOptions.InternalCall)]
850 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
851 ref ProcInfo proc_info);
853 [MethodImplAttribute(MethodImplOptions.InternalCall)]
854 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
858 ref ProcInfo proc_info);
860 private static bool Start_shell (ProcessStartInfo startInfo,
863 ProcInfo proc_info=new ProcInfo();
866 if (startInfo.RedirectStandardInput ||
867 startInfo.RedirectStandardOutput ||
868 startInfo.RedirectStandardError) {
869 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
872 if (startInfo.HaveEnvVars) {
873 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
876 ret = ShellExecuteEx_internal (startInfo,
879 throw new Win32Exception (-proc_info.pid);
882 process.process_handle = proc_info.process_handle;
883 process.pid = proc_info.pid;
885 process.StartExitCallbackIfNeeded ();
890 private static bool Start_noshell (ProcessStartInfo startInfo,
893 if (Path.IsPathRooted (startInfo.FileName) && !File.Exists (startInfo.FileName))
894 throw new FileNotFoundException ("Executable not found: " + startInfo.FileName);
895 ProcInfo proc_info=new ProcInfo();
896 IntPtr stdin_rd, stdin_wr;
902 if (startInfo.HaveEnvVars) {
903 string [] strs = new string [startInfo.EnvironmentVariables.Count];
904 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
905 proc_info.envKeys = strs;
907 strs = new string [startInfo.EnvironmentVariables.Count];
908 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
909 proc_info.envValues = strs;
912 if (startInfo.RedirectStandardInput == true) {
913 ret = MonoIO.CreatePipe (out stdin_rd,
916 throw new IOException ("Error creating standard input pipe");
919 stdin_rd = MonoIO.ConsoleInput;
920 /* This is required to stop the
921 * &$*£ing stupid compiler moaning
922 * that stdin_wr is unassigned, below.
924 stdin_wr = (IntPtr)0;
927 if (startInfo.RedirectStandardOutput == true) {
929 ret = MonoIO.CreatePipe (out out_rd,
932 process.stdout_rd = out_rd;
934 if (startInfo.RedirectStandardInput == true) {
935 MonoIO.Close (stdin_rd, out error);
936 MonoIO.Close (stdin_wr, out error);
939 throw new IOException ("Error creating standard output pipe");
942 process.stdout_rd = (IntPtr)0;
943 stdout_wr = MonoIO.ConsoleOutput;
946 if (startInfo.RedirectStandardError == true) {
948 ret = MonoIO.CreatePipe (out err_rd,
951 process.stderr_rd = err_rd;
953 if (startInfo.RedirectStandardInput == true) {
954 MonoIO.Close (stdin_rd, out error);
955 MonoIO.Close (stdin_wr, out error);
957 if (startInfo.RedirectStandardOutput == true) {
958 MonoIO.Close (process.stdout_rd, out error);
959 MonoIO.Close (stdout_wr, out error);
962 throw new IOException ("Error creating standard error pipe");
965 process.stderr_rd = (IntPtr)0;
966 stderr_wr = MonoIO.ConsoleError;
969 ret = CreateProcess_internal (startInfo,
970 stdin_rd, stdout_wr, stderr_wr,
973 if (startInfo.RedirectStandardInput == true) {
974 MonoIO.Close (stdin_rd, out error);
975 MonoIO.Close (stdin_wr, out error);
978 if (startInfo.RedirectStandardOutput == true) {
979 MonoIO.Close (process.stdout_rd, out error);
980 MonoIO.Close (stdout_wr, out error);
983 if (startInfo.RedirectStandardError == true) {
984 MonoIO.Close (process.stderr_rd, out error);
985 MonoIO.Close (stderr_wr, out error);
988 throw new Win32Exception (-proc_info.pid,
989 "ApplicationName='"+startInfo.FileName+
990 "', CommandLine='"+startInfo.Arguments+
991 "', CurrentDirectory='"+startInfo.WorkingDirectory+
992 "', PATH='"+startInfo.EnvironmentVariables["PATH"]+"'");
995 process.process_handle = proc_info.process_handle;
996 process.pid = proc_info.pid;
998 if (startInfo.RedirectStandardInput == true) {
999 MonoIO.Close (stdin_rd, out error);
1000 process.input_stream = new StreamWriter (new FileStream (stdin_wr, FileAccess.Write, true));
1001 process.input_stream.AutoFlush = true;
1004 if (startInfo.RedirectStandardOutput == true) {
1005 MonoIO.Close (stdout_wr, out error);
1006 process.output_stream = new StreamReader (new FileStream (process.stdout_rd, FileAccess.Read, true));
1009 if (startInfo.RedirectStandardError == true) {
1010 MonoIO.Close (stderr_wr, out error);
1011 process.error_stream = new StreamReader (new FileStream (process.stderr_rd, FileAccess.Read, true));
1014 process.StartExitCallbackIfNeeded ();
1019 private static bool Start_common (ProcessStartInfo startInfo,
1022 if(startInfo.FileName == null ||
1023 startInfo.FileName == "") {
1024 throw new InvalidOperationException("File name has not been set");
1027 if (startInfo.UseShellExecute) {
1028 return (Start_shell (startInfo, process));
1030 return (Start_noshell (startInfo, process));
1034 public bool Start() {
1037 if (process_handle != IntPtr.Zero) {
1038 Process_free_internal (process_handle);
1039 process_handle = IntPtr.Zero;
1041 ret=Start_common(start_info, this);
1046 public static Process Start(ProcessStartInfo startInfo) {
1047 Process process=new Process();
1050 process.StartInfo = startInfo;
1051 ret=Start_common(startInfo, process);
1060 public static Process Start(string fileName) {
1061 return Start(new ProcessStartInfo(fileName));
1064 public static Process Start(string fileName,
1066 return Start(new ProcessStartInfo(fileName, arguments));
1069 public override string ToString() {
1070 return(base.ToString() +
1071 " (" + this.ProcessName + ")");
1074 /* Waits up to ms milliseconds for process 'handle' to
1075 * exit. ms can be <0 to mean wait forever.
1077 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1078 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1080 public void WaitForExit ()
1085 public bool WaitForExit(int milliseconds) {
1086 int ms = milliseconds;
1087 if (ms == int.MaxValue)
1091 DateTime start = DateTime.UtcNow;
1092 if (async_output != null && !async_output.IsCompleted) {
1093 if (false == async_output.WaitHandle.WaitOne (ms, false))
1094 return false; // Timed out
1097 DateTime now = DateTime.UtcNow;
1098 ms -= (int) (now - start).TotalMilliseconds;
1105 if (async_error != null && !async_error.IsCompleted) {
1106 if (false == async_error.WaitHandle.WaitOne (ms, false))
1107 return false; // Timed out
1110 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1116 return WaitForExit_internal (process_handle, ms);
1120 public bool WaitForInputIdle() {
1125 public bool WaitForInputIdle(int milliseconds) {
1131 public event DataReceivedEventHandler OutputDataReceived;
1132 public event DataReceivedEventHandler ErrorDataReceived;
1134 void OnOutputDataReceived (string str)
1136 if (OutputDataReceived != null)
1137 OutputDataReceived (this, new DataReceivedEventArgs (str));
1140 void OnErrorDataReceived (string str)
1142 if (ErrorDataReceived != null)
1143 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1151 AsyncOutput = 1 << 2,
1155 [StructLayout (LayoutKind.Sequential)]
1156 sealed class ProcessAsyncReader
1159 The following fields match those of SocketAsyncResult.
1160 This is so that changes needed in the runtime to handle
1161 asynchronous reads are trivial
1163 /* DON'T shuffle fields around. DON'T remove fields */
1165 public IntPtr handle;
1166 public object state;
1167 public AsyncCallback callback;
1168 public ManualResetEvent wait_handle;
1170 public Exception delayedException;
1172 public object EndPoint;
1173 byte [] buffer = new byte [4196];
1176 public int SockFlags;
1178 public object acc_socket;
1180 public bool completed_sync;
1182 bool err_out; // true -> stdout, false -> stderr
1184 public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1188 // These fields are not in SocketAsyncResult
1191 StringBuilder sb = new StringBuilder ();
1192 public AsyncReadHandler ReadHandler;
1194 public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1196 this.process = process;
1197 this.handle = handle;
1198 stream = new FileStream (handle, FileAccess.Read, false);
1199 this.ReadHandler = new AsyncReadHandler (AddInput);
1200 this.err_out = err_out;
1203 public void AddInput ()
1206 int nread = stream.Read (buffer, 0, buffer.Length);
1209 if (wait_handle != null)
1216 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1218 // Just in case the encoding fails...
1219 for (int i = 0; i < nread; i++) {
1220 sb.Append ((char) buffer [i]);
1225 ReadHandler.BeginInvoke (null, this);
1229 void Flush (bool last)
1231 if (sb.Length == 0 ||
1232 (err_out && process.output_canceled) ||
1233 (!err_out && process.error_canceled))
1236 string total = sb.ToString ();
1238 string [] strs = total.Split ('\n');
1239 int len = strs.Length;
1243 for (int i = 0; i < len - 1; i++) {
1245 process.OnOutputDataReceived (strs [i]);
1247 process.OnErrorDataReceived (strs [i]);
1250 string end = strs [len - 1];
1251 if (last || end == "") {
1253 process.OnOutputDataReceived (end);
1255 process.OnErrorDataReceived (end);
1261 public bool IsCompleted {
1262 get { return completed; }
1265 public WaitHandle WaitHandle {
1268 if (wait_handle == null)
1269 wait_handle = new ManualResetEvent (completed);
1276 AsyncModes async_mode;
1277 bool output_canceled;
1278 bool error_canceled;
1279 ProcessAsyncReader async_output;
1280 ProcessAsyncReader async_error;
1281 delegate void AsyncReadHandler ();
1283 [ComVisibleAttribute(false)]
1284 public void BeginOutputReadLine ()
1286 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1287 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1289 if ((async_mode & AsyncModes.SyncOutput) != 0)
1290 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1292 async_mode |= AsyncModes.AsyncOutput;
1293 output_canceled = false;
1294 if (async_output == null) {
1295 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1296 async_output.ReadHandler.BeginInvoke (null, async_output);
1300 [ComVisibleAttribute(false)]
1301 public void CancelOutputRead ()
1303 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1304 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1306 if ((async_mode & AsyncModes.SyncOutput) != 0)
1307 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1309 if (async_output == null)
1310 throw new InvalidOperationException ("No async operation in progress.");
1312 output_canceled = true;
1315 [ComVisibleAttribute(false)]
1316 public void BeginErrorReadLine ()
1318 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1319 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1321 if ((async_mode & AsyncModes.SyncError) != 0)
1322 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1324 async_mode |= AsyncModes.AsyncError;
1325 error_canceled = false;
1326 if (async_error == null) {
1327 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1328 async_error.ReadHandler.BeginInvoke (null, async_error);
1332 [ComVisibleAttribute(false)]
1333 public void CancelErrorRead ()
1335 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1336 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1338 if ((async_mode & AsyncModes.SyncOutput) != 0)
1339 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1341 if (async_error == null)
1342 throw new InvalidOperationException ("No async operation in progress.");
1344 error_canceled = true;
1348 [Category ("Behavior")]
1349 [MonitoringDescription ("Raised when this process exits.")]
1350 public event EventHandler Exited {
1352 if (process_handle != IntPtr.Zero && HasExited) {
1353 value.BeginInvoke (null, null, null, null);
1355 exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1356 if (exited_event != null)
1357 StartExitCallbackIfNeeded ();
1361 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1365 // Closes the system process handle
1366 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1367 private extern void Process_free_internal(IntPtr handle);
1369 private bool disposed = false;
1371 protected override void Dispose(bool disposing) {
1372 // Check to see if Dispose has already been called.
1373 if(this.disposed == false) {
1375 // If this is a call to Dispose,
1376 // dispose all managed resources.
1381 // Release unmanaged resources
1384 if(process_handle!=IntPtr.Zero) {
1386 Process_free_internal(process_handle);
1387 process_handle=IntPtr.Zero;
1390 if (input_stream != null) {
1391 input_stream.Close();
1392 input_stream = null;
1395 if (output_stream != null) {
1396 output_stream.Close();
1397 output_stream = null;
1400 if (error_stream != null) {
1401 error_stream.Close();
1402 error_stream = null;
1406 base.Dispose (disposing);
1414 static void CBOnExit (object state, bool unused)
1416 Process p = (Process) state;
1420 protected void OnExited()
1422 if (exited_event == null)
1425 if (synchronizingObject == null) {
1426 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1428 d (this, EventArgs.Empty);
1434 object [] args = new object [] {this, EventArgs.Empty};
1435 synchronizingObject.BeginInvoke (exited_event, args);
1438 class ProcessWaitHandle : WaitHandle
1440 public ProcessWaitHandle (IntPtr handle)
1445 protected override void Dispose (bool explicitDisposing)
1447 // Do nothing, we don't own the handle and we won't close it.