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() {
757 int pid=GetPid_internal();
758 IntPtr proc=GetProcess_internal(pid);
760 if(proc==IntPtr.Zero) {
761 throw new SystemException("Can't find current process");
764 return(new Process(proc, pid));
767 public static Process GetProcessById(int processId) {
768 IntPtr proc=GetProcess_internal(processId);
770 if(proc==IntPtr.Zero) {
771 throw new ArgumentException("Can't find process with ID " + processId.ToString());
774 return(new Process(proc, processId));
778 public static Process GetProcessById(int processId, string machineName) {
779 throw new NotImplementedException();
782 [MethodImplAttribute(MethodImplOptions.InternalCall)]
783 private extern static int[] GetProcesses_internal();
785 public static Process[] GetProcesses() {
786 int[] pids=GetProcesses_internal();
787 ArrayList proclist=new ArrayList();
789 for(int i=0; i<pids.Length; i++) {
791 proclist.Add(GetProcessById(pids[i]));
792 } catch (SystemException) {
793 /* The process might exit
795 * GetProcesses_internal and
801 return((Process[])proclist.ToArray(typeof(Process)));
805 public static Process[] GetProcesses(string machineName) {
806 throw new NotImplementedException();
809 public static Process[] GetProcessesByName(string processName) {
810 Process[] procs=GetProcesses();
811 ArrayList proclist=new ArrayList();
813 for(int i=0; i<procs.Length; i++) {
815 if(String.Compare(processName,
816 procs[i].ProcessName,
818 proclist.Add(procs[i]);
822 return((Process[])proclist.ToArray(typeof(Process)));
826 public static Process[] GetProcessesByName(string processName, string machineName) {
827 throw new NotImplementedException();
836 public static void LeaveDebugMode() {
840 public void Refresh() {
843 [MethodImplAttribute(MethodImplOptions.InternalCall)]
844 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
845 ref ProcInfo proc_info);
847 [MethodImplAttribute(MethodImplOptions.InternalCall)]
848 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
852 ref ProcInfo proc_info);
854 private static bool Start_shell (ProcessStartInfo startInfo,
857 ProcInfo proc_info=new ProcInfo();
860 if (startInfo.RedirectStandardInput ||
861 startInfo.RedirectStandardOutput ||
862 startInfo.RedirectStandardError) {
863 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
866 if (startInfo.HaveEnvVars) {
867 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
870 ret = ShellExecuteEx_internal (startInfo,
873 throw new Win32Exception (-proc_info.pid);
876 process.process_handle = proc_info.process_handle;
877 process.pid = proc_info.pid;
879 process.StartExitCallbackIfNeeded ();
884 private static bool Start_noshell (ProcessStartInfo startInfo,
887 if (Path.IsPathRooted (startInfo.FileName) && !File.Exists (startInfo.FileName))
888 throw new FileNotFoundException ("Executable not found: " + startInfo.FileName);
889 ProcInfo proc_info=new ProcInfo();
890 IntPtr stdin_rd, stdin_wr;
896 if (startInfo.HaveEnvVars) {
897 string [] strs = new string [startInfo.EnvironmentVariables.Count];
898 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
899 proc_info.envKeys = strs;
901 strs = new string [startInfo.EnvironmentVariables.Count];
902 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
903 proc_info.envValues = strs;
906 if (startInfo.RedirectStandardInput == true) {
907 ret = MonoIO.CreatePipe (out stdin_rd,
910 throw new IOException ("Error creating standard input pipe");
913 stdin_rd = MonoIO.ConsoleInput;
914 /* This is required to stop the
915 * &$*£ing stupid compiler moaning
916 * that stdin_wr is unassigned, below.
918 stdin_wr = (IntPtr)0;
921 if (startInfo.RedirectStandardOutput == true) {
923 ret = MonoIO.CreatePipe (out out_rd,
926 process.stdout_rd = out_rd;
928 if (startInfo.RedirectStandardInput == true) {
929 MonoIO.Close (stdin_rd, out error);
930 MonoIO.Close (stdin_wr, out error);
933 throw new IOException ("Error creating standard output pipe");
936 process.stdout_rd = (IntPtr)0;
937 stdout_wr = MonoIO.ConsoleOutput;
940 if (startInfo.RedirectStandardError == true) {
942 ret = MonoIO.CreatePipe (out err_rd,
945 process.stderr_rd = err_rd;
947 if (startInfo.RedirectStandardInput == true) {
948 MonoIO.Close (stdin_rd, out error);
949 MonoIO.Close (stdin_wr, out error);
951 if (startInfo.RedirectStandardOutput == true) {
952 MonoIO.Close (process.stdout_rd, out error);
953 MonoIO.Close (stdout_wr, out error);
956 throw new IOException ("Error creating standard error pipe");
959 process.stderr_rd = (IntPtr)0;
960 stderr_wr = MonoIO.ConsoleError;
963 ret = CreateProcess_internal (startInfo,
964 stdin_rd, stdout_wr, stderr_wr,
967 if (startInfo.RedirectStandardInput == true) {
968 MonoIO.Close (stdin_rd, out error);
969 MonoIO.Close (stdin_wr, out error);
972 if (startInfo.RedirectStandardOutput == true) {
973 MonoIO.Close (process.stdout_rd, out error);
974 MonoIO.Close (stdout_wr, out error);
977 if (startInfo.RedirectStandardError == true) {
978 MonoIO.Close (process.stderr_rd, out error);
979 MonoIO.Close (stderr_wr, out error);
982 throw new Win32Exception (-proc_info.pid,
983 "ApplicationName='"+startInfo.FileName+
984 "', CommandLine='"+startInfo.Arguments+
985 "', CurrentDirectory='"+startInfo.WorkingDirectory+
986 "', PATH='"+startInfo.EnvironmentVariables["PATH"]+"'");
989 process.process_handle = proc_info.process_handle;
990 process.pid = proc_info.pid;
992 if (startInfo.RedirectStandardInput == true) {
993 MonoIO.Close (stdin_rd, out error);
994 process.input_stream = new StreamWriter (new FileStream (stdin_wr, FileAccess.Write, true));
995 process.input_stream.AutoFlush = true;
998 if (startInfo.RedirectStandardOutput == true) {
999 MonoIO.Close (stdout_wr, out error);
1000 process.output_stream = new StreamReader (new FileStream (process.stdout_rd, FileAccess.Read, true));
1003 if (startInfo.RedirectStandardError == true) {
1004 MonoIO.Close (stderr_wr, out error);
1005 process.error_stream = new StreamReader (new FileStream (process.stderr_rd, FileAccess.Read, true));
1008 process.StartExitCallbackIfNeeded ();
1013 private static bool Start_common (ProcessStartInfo startInfo,
1016 if(startInfo.FileName == null ||
1017 startInfo.FileName == "") {
1018 throw new InvalidOperationException("File name has not been set");
1021 if (startInfo.UseShellExecute) {
1022 return (Start_shell (startInfo, process));
1024 return (Start_noshell (startInfo, process));
1028 public bool Start() {
1031 ret=Start_common(start_info, this);
1036 public static Process Start(ProcessStartInfo startInfo) {
1037 Process process=new Process();
1040 ret=Start_common(startInfo, process);
1049 public static Process Start(string fileName) {
1050 return Start(new ProcessStartInfo(fileName));
1053 public static Process Start(string fileName,
1055 return Start(new ProcessStartInfo(fileName, arguments));
1058 public override string ToString() {
1059 return(base.ToString() +
1060 " (" + this.ProcessName + ")");
1063 /* Waits up to ms milliseconds for process 'handle' to
1064 * exit. ms can be <0 to mean wait forever.
1066 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1067 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1069 public void WaitForExit ()
1074 public bool WaitForExit(int milliseconds) {
1075 int ms = milliseconds;
1076 if (ms == int.MaxValue)
1080 DateTime start = DateTime.UtcNow;
1081 if (async_output != null && !async_output.IsCompleted) {
1082 if (false == async_output.WaitHandle.WaitOne (ms, false))
1083 return false; // Timed out
1086 DateTime now = DateTime.UtcNow;
1087 ms -= (int) (now - start).TotalMilliseconds;
1094 if (async_error != null && !async_error.IsCompleted) {
1095 if (false == async_error.WaitHandle.WaitOne (ms, false))
1096 return false; // Timed out
1099 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1105 return WaitForExit_internal (process_handle, ms);
1109 public bool WaitForInputIdle() {
1114 public bool WaitForInputIdle(int milliseconds) {
1120 public event DataReceivedEventHandler OutputDataReceived;
1121 public event DataReceivedEventHandler ErrorDataReceived;
1123 void OnOutputDataReceived (string str)
1125 if (OutputDataReceived != null)
1126 OutputDataReceived (this, new DataReceivedEventArgs (str));
1129 void OnErrorDataReceived (string str)
1131 if (ErrorDataReceived != null)
1132 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1140 AsyncOutput = 1 << 2,
1144 [StructLayout (LayoutKind.Sequential)]
1145 sealed class ProcessAsyncReader
1148 The following fields match those of SocketAsyncResult.
1149 This is so that changes needed in the runtime to handle
1150 asynchronous reads are trivial
1152 /* DON'T shuffle fields around. DON'T remove fields */
1154 public IntPtr handle;
1155 public object state;
1156 public AsyncCallback callback;
1157 public ManualResetEvent wait_handle;
1159 public Exception delayedException;
1161 public object EndPoint;
1162 byte [] buffer = new byte [4196];
1165 public int SockFlags;
1167 public object acc_socket;
1169 public bool completed_sync;
1171 bool err_out; // true -> stdout, false -> stderr
1173 public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1177 // These fields are not in SocketAsyncResult
1180 StringBuilder sb = new StringBuilder ();
1181 public AsyncReadHandler ReadHandler;
1183 public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1185 this.process = process;
1186 this.handle = handle;
1187 stream = new FileStream (handle, FileAccess.Read, false);
1188 this.ReadHandler = new AsyncReadHandler (AddInput);
1189 this.err_out = err_out;
1192 public void AddInput ()
1195 int nread = stream.Read (buffer, 0, buffer.Length);
1198 if (wait_handle != null)
1205 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1207 // Just in case the encoding fails...
1208 for (int i = 0; i < nread; i++) {
1209 sb.Append ((char) buffer [i]);
1214 ReadHandler.BeginInvoke (null, this);
1218 void Flush (bool last)
1220 if (sb.Length == 0 ||
1221 (err_out && process.output_canceled) ||
1222 (!err_out && process.error_canceled))
1225 string total = sb.ToString ();
1227 string [] strs = total.Split ('\n');
1228 int len = strs.Length;
1232 for (int i = 0; i < len - 1; i++) {
1234 process.OnOutputDataReceived (strs [i]);
1236 process.OnErrorDataReceived (strs [i]);
1239 string end = strs [len - 1];
1240 if (last || end == "") {
1242 process.OnOutputDataReceived (end);
1244 process.OnErrorDataReceived (end);
1250 public bool IsCompleted {
1251 get { return completed; }
1254 public WaitHandle WaitHandle {
1257 if (wait_handle == null)
1258 wait_handle = new ManualResetEvent (completed);
1265 AsyncModes async_mode;
1266 bool output_canceled;
1267 bool error_canceled;
1268 ProcessAsyncReader async_output;
1269 ProcessAsyncReader async_error;
1270 delegate void AsyncReadHandler ();
1272 [ComVisibleAttribute(false)]
1273 public void BeginOutputReadLine ()
1275 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1276 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1278 if ((async_mode & AsyncModes.SyncOutput) != 0)
1279 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1281 async_mode |= AsyncModes.AsyncOutput;
1282 output_canceled = false;
1283 if (async_output == null) {
1284 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1285 async_output.ReadHandler.BeginInvoke (null, async_output);
1289 [ComVisibleAttribute(false)]
1290 public void CancelOutputRead ()
1292 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1293 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1295 if ((async_mode & AsyncModes.SyncOutput) != 0)
1296 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1298 if (async_output == null)
1299 throw new InvalidOperationException ("No async operation in progress.");
1301 output_canceled = true;
1304 [ComVisibleAttribute(false)]
1305 public void BeginErrorReadLine ()
1307 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1308 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1310 if ((async_mode & AsyncModes.SyncError) != 0)
1311 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1313 async_mode |= AsyncModes.AsyncError;
1314 error_canceled = false;
1315 if (async_error == null) {
1316 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1317 async_error.ReadHandler.BeginInvoke (null, async_error);
1321 [ComVisibleAttribute(false)]
1322 public void CancelErrorRead ()
1324 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1325 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1327 if ((async_mode & AsyncModes.SyncOutput) != 0)
1328 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1330 if (async_error == null)
1331 throw new InvalidOperationException ("No async operation in progress.");
1333 error_canceled = true;
1337 [Category ("Behavior")]
1338 [MonitoringDescription ("Raised when this process exits.")]
1339 public event EventHandler Exited {
1341 if (process_handle != IntPtr.Zero && HasExited) {
1342 value.BeginInvoke (null, null, null, null);
1344 exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1345 if (exited_event != null)
1346 StartExitCallbackIfNeeded ();
1350 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1354 // Closes the system process handle
1355 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1356 private extern void Process_free_internal(IntPtr handle);
1358 private bool disposed = false;
1360 protected override void Dispose(bool disposing) {
1361 // Check to see if Dispose has already been called.
1362 if(this.disposed == false) {
1364 // If this is a call to Dispose,
1365 // dispose all managed resources.
1370 // Release unmanaged resources
1373 if(process_handle!=IntPtr.Zero) {
1375 Process_free_internal(process_handle);
1376 process_handle=IntPtr.Zero;
1379 if (input_stream != null) {
1380 input_stream.Close();
1381 input_stream = null;
1384 if (output_stream != null) {
1385 output_stream.Close();
1386 output_stream = null;
1389 if (error_stream != null) {
1390 error_stream.Close();
1391 error_stream = null;
1395 base.Dispose (disposing);
1403 static void CBOnExit (object state, bool unused)
1405 Process p = (Process) state;
1409 protected void OnExited()
1411 if (exited_event == null)
1414 if (synchronizingObject == null) {
1415 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1417 d (this, EventArgs.Empty);
1423 object [] args = new object [] {this, EventArgs.Empty};
1424 synchronizingObject.BeginInvoke (exited_event, args);
1427 class ProcessWaitHandle : WaitHandle
1429 public ProcessWaitHandle (IntPtr handle)
1434 protected override void Dispose (bool explicitDisposing)
1436 // Do nothing, we don't own the handle and we won't close it.