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.Security;
44 using System.Threading;
46 namespace System.Diagnostics {
48 [DefaultEvent ("Exited"), DefaultProperty ("StartInfo")]
49 [Designer ("System.Diagnostics.Design.ProcessDesigner, " + Consts.AssemblySystem_Design)]
50 [PermissionSet (SecurityAction.LinkDemand, Unrestricted = true)]
51 [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
53 [MonitoringDescription ("Represents a system process")]
55 public class Process : Component
57 [StructLayout(LayoutKind.Sequential)]
58 private struct ProcInfo
60 public IntPtr process_handle;
61 /* If thread_handle is ever needed for
62 * something, take out the CloseHandle() in
63 * the Start_internal icall in
64 * mono/metadata/process.c
66 public IntPtr thread_handle;
67 public int pid; // Contains -GetLastError () on failure.
69 public string [] envKeys;
70 public string [] envValues;
71 public string UserName;
73 public IntPtr Password;
74 public bool LoadUserProfile;
77 IntPtr process_handle;
79 bool enableRaisingEvents;
81 ISynchronizeInvoke synchronizingObject;
82 EventHandler exited_event;
86 /* Private constructor called from other methods */
87 private Process(IntPtr handle, int id) {
88 process_handle=handle;
97 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
98 [MonitoringDescription ("Base process priority.")]
99 public int BasePriority {
105 void StartExitCallbackIfNeeded ()
108 bool start = (!already_waiting && enableRaisingEvents && exited_event != null);
109 if (start && process_handle != IntPtr.Zero) {
110 WaitOrTimerCallback cb = new WaitOrTimerCallback (CBOnExit);
111 ProcessWaitHandle h = new ProcessWaitHandle (process_handle);
112 ThreadPool.RegisterWaitForSingleObject (h, cb, this, -1, true);
113 already_waiting = true;
118 [DefaultValue (false), Browsable (false)]
119 [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
120 public bool EnableRaisingEvents {
122 return enableRaisingEvents;
125 bool prev = enableRaisingEvents;
126 enableRaisingEvents = value;
127 if (enableRaisingEvents && !prev)
128 StartExitCallbackIfNeeded ();
133 [MethodImplAttribute(MethodImplOptions.InternalCall)]
134 private extern static int ExitCode_internal(IntPtr handle);
136 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
137 [MonitoringDescription ("The exit code of the process.")]
138 public int ExitCode {
140 if (process_handle == IntPtr.Zero)
141 throw new InvalidOperationException ("Process has not been started.");
143 int code = ExitCode_internal (process_handle);
145 throw new InvalidOperationException ("The process must exit before " +
146 "getting the requested information.");
152 /* Returns the process start time in Windows file
153 * times (ticks from DateTime(1/1/1601 00:00 GMT))
155 [MethodImplAttribute(MethodImplOptions.InternalCall)]
156 private extern static long ExitTime_internal(IntPtr handle);
158 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
159 [MonitoringDescription ("The exit time of the process.")]
160 public DateTime ExitTime {
162 if (process_handle == IntPtr.Zero)
163 throw new InvalidOperationException ("Process has not been started.");
166 throw new InvalidOperationException ("The process must exit before " +
167 "getting the requested information.");
169 return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
173 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
174 [MonitoringDescription ("Handle for this process.")]
175 public IntPtr Handle {
177 return(process_handle);
182 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
183 [MonitoringDescription ("Handles for this process.")]
184 public int HandleCount {
190 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
191 [MonitoringDescription ("Determines if the process is still running.")]
192 public bool HasExited {
194 if (process_handle == IntPtr.Zero)
195 throw new InvalidOperationException ("Process has not been started.");
197 int exitcode = ExitCode_internal (process_handle);
208 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
209 [MonitoringDescription ("Process identifier.")]
213 throw new InvalidOperationException ("Process ID has not been set.");
220 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
221 [MonitoringDescription ("The name of the computer running the process.")]
222 public string MachineName {
228 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
229 [MonitoringDescription ("The main module of the process.")]
230 public ProcessModule MainModule {
232 return(this.Modules[0]);
237 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
238 [MonitoringDescription ("The handle of the main window of the process.")]
239 public IntPtr MainWindowHandle {
246 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
247 [MonitoringDescription ("The title of the main window of the process.")]
248 public string MainWindowTitle {
254 [MethodImplAttribute(MethodImplOptions.InternalCall)]
255 private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
256 [MethodImplAttribute(MethodImplOptions.InternalCall)]
257 private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);
259 /* LAMESPEC: why is this an IntPtr not a plain int? */
260 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
261 [MonitoringDescription ("The maximum working set for this process.")]
262 public IntPtr MaxWorkingSet {
265 throw new InvalidOperationException(
266 "The process " + ProcessName +
267 " (ID " + Id + ") has exited");
271 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
273 throw new Win32Exception();
280 throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
283 bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
285 throw new Win32Exception();
290 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
291 [MonitoringDescription ("The minimum working set for this process.")]
292 public IntPtr MinWorkingSet {
295 throw new InvalidOperationException(
296 "The process " + ProcessName +
297 " (ID " + Id + ") has exited");
301 bool ok= GetWorkingSet_internal (process_handle, out min, out max);
303 throw new Win32Exception();
304 return ((IntPtr) min);
308 throw new InvalidOperationException(
309 "The process " + ProcessName +
310 " (ID " + Id + ") has exited");
312 bool ok = SetWorkingSet_internal (process_handle, value.ToInt32(), 0, true);
314 throw new Win32Exception();
318 /* Returns the list of process modules. The main module is
321 [MethodImplAttribute(MethodImplOptions.InternalCall)]
322 private extern ProcessModule[] GetModules_internal(IntPtr handle);
324 private ProcessModuleCollection module_collection;
326 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
327 [MonitoringDescription ("The modules that are loaded as part of this process.")]
328 public ProcessModuleCollection Modules {
330 if (module_collection == null)
331 module_collection = new ProcessModuleCollection(
332 GetModules_internal (process_handle));
333 return(module_collection);
337 /* data type is from the MonoProcessData enum in mono-proclib.h in the runtime */
338 [MethodImplAttribute(MethodImplOptions.InternalCall)]
339 private extern static long GetProcessData (int pid, int data_type, out int error);
343 [Obsolete ("Use NonpagedSystemMemorySize64")]
345 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
346 [MonitoringDescription ("The number of bytes that are not pageable.")]
347 public int NonpagedSystemMemorySize {
355 [Obsolete ("Use PagedMemorySize64")]
357 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
358 [MonitoringDescription ("The number of bytes that are paged.")]
359 public int PagedMemorySize {
367 [Obsolete ("Use PagedSystemMemorySize64")]
369 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
370 [MonitoringDescription ("The amount of paged system memory in bytes.")]
371 public int PagedSystemMemorySize {
379 [Obsolete ("Use PeakPagedMemorySize64")]
381 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
382 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
383 public int PeakPagedMemorySize {
390 [Obsolete ("Use PeakVirtualMemorySize64")]
392 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
393 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
394 public int PeakVirtualMemorySize {
397 return (int)GetProcessData (pid, 8, out error);
402 [Obsolete ("Use PeakWorkingSet64")]
404 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
405 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
406 public int PeakWorkingSet {
409 return (int)GetProcessData (pid, 5, out error);
415 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
416 [MonitoringDescription ("The number of bytes that are not pageable.")]
418 public long NonpagedSystemMemorySize64 {
425 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
426 [MonitoringDescription ("The number of bytes that are paged.")]
428 public long PagedMemorySize64 {
435 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
436 [MonitoringDescription ("The amount of paged system memory in bytes.")]
438 public long PagedSystemMemorySize64 {
445 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
446 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
448 public long PeakPagedMemorySize64 {
454 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
455 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
457 public long PeakVirtualMemorySize64 {
460 return GetProcessData (pid, 8, out error);
464 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
465 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
467 public long PeakWorkingSet64 {
470 return GetProcessData (pid, 5, out error);
476 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
477 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
478 public bool PriorityBoostEnabled {
486 [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
487 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
488 [MonitoringDescription ("The relative process priority.")]
489 public ProcessPriorityClass PriorityClass {
491 if (process_handle == IntPtr.Zero)
492 throw new InvalidOperationException ("Process has not been started.");
495 int prio = GetPriorityClass (process_handle, out error);
497 throw new Win32Exception (error);
498 return (ProcessPriorityClass) prio;
501 if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
502 throw new InvalidEnumArgumentException (
503 "value", (int) value,
504 typeof (ProcessPriorityClass));
506 if (process_handle == IntPtr.Zero)
507 throw new InvalidOperationException ("Process has not been started.");
510 if (!SetPriorityClass (process_handle, (int) value, out error))
511 throw new Win32Exception (error);
515 [MethodImplAttribute(MethodImplOptions.InternalCall)]
516 static extern int GetPriorityClass (IntPtr handle, out int error);
518 [MethodImplAttribute(MethodImplOptions.InternalCall)]
519 static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);
521 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
522 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
524 [Obsolete ("Use PrivateMemorySize64")]
526 public int PrivateMemorySize {
529 return (int)GetProcessData (pid, 6, out error);
534 [MonoNotSupported ("")]
535 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
536 [MonitoringDescription ("The session ID for this process.")]
537 public int SessionId {
538 get { throw new NotImplementedException (); }
542 /* the meaning of type is as follows: 0: user, 1: system, 2: total */
543 [MethodImplAttribute(MethodImplOptions.InternalCall)]
544 private extern static long Times (IntPtr handle, int type);
546 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
547 [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
548 public TimeSpan PrivilegedProcessorTime {
550 return new TimeSpan (Times (process_handle, 1));
554 [MethodImplAttribute(MethodImplOptions.InternalCall)]
555 private extern static string ProcessName_internal(IntPtr handle);
557 private string process_name=null;
559 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
560 [MonitoringDescription ("The name of this process.")]
561 public string ProcessName {
563 if(process_name==null) {
565 if (process_handle == IntPtr.Zero)
566 throw new InvalidOperationException ("No process is associated with this object.");
568 process_name=ProcessName_internal(process_handle);
569 /* If process_name is _still_
570 * null, assume the process
573 if (process_name == null)
574 throw new InvalidOperationException ("Process has exited, so the requested information is not available.");
576 /* Strip the suffix (if it
577 * exists) simplistically
578 * instead of removing any
579 * trailing \.???, so we dont
580 * get stupid results on sane
583 if(process_name.EndsWith(".exe") ||
584 process_name.EndsWith(".bat") ||
585 process_name.EndsWith(".com")) {
586 process_name=process_name.Substring(0, process_name.Length-4);
589 return(process_name);
594 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
595 [MonitoringDescription ("Allowed processor that can be used by this process.")]
596 public IntPtr ProcessorAffinity {
605 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
606 [MonitoringDescription ("Is this process responsive.")]
607 public bool Responding {
613 private StreamReader error_stream=null;
615 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
616 [MonitoringDescription ("The standard error stream of this process.")]
617 public StreamReader StandardError {
619 if (error_stream == null)
620 throw new InvalidOperationException("Standard error has not been redirected");
623 if ((async_mode & AsyncModes.AsyncError) != 0)
624 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
626 async_mode |= AsyncModes.SyncError;
629 return(error_stream);
633 private StreamWriter input_stream=null;
635 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
636 [MonitoringDescription ("The standard input stream of this process.")]
637 public StreamWriter StandardInput {
639 if (input_stream == null)
640 throw new InvalidOperationException("Standard input has not been redirected");
642 return(input_stream);
646 private StreamReader output_stream=null;
648 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
649 [MonitoringDescription ("The standard output stream of this process.")]
650 public StreamReader StandardOutput {
652 if (output_stream == null)
653 throw new InvalidOperationException("Standard output has not been redirected");
656 if ((async_mode & AsyncModes.AsyncOutput) != 0)
657 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
659 async_mode |= AsyncModes.SyncOutput;
662 return(output_stream);
666 private ProcessStartInfo start_info=null;
668 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
669 [MonitoringDescription ("Information for the start of this process.")]
670 public ProcessStartInfo StartInfo {
672 if (start_info == null)
673 start_info = new ProcessStartInfo();
678 throw new ArgumentNullException("value");
683 /* Returns the process start time in Windows file
684 * times (ticks from DateTime(1/1/1601 00:00 GMT))
686 [MethodImplAttribute(MethodImplOptions.InternalCall)]
687 private extern static long StartTime_internal(IntPtr handle);
689 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
690 [MonitoringDescription ("The time this process started.")]
691 public DateTime StartTime {
693 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
697 [DefaultValue (null), Browsable (false)]
698 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
699 public ISynchronizeInvoke SynchronizingObject {
700 get { return synchronizingObject; }
701 set { synchronizingObject = value; }
705 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
706 [MonitoringDescription ("The number of threads of this process.")]
707 public ProcessThreadCollection Threads {
709 return ProcessThreadCollection.GetEmpty ();
713 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
714 [MonitoringDescription ("The total CPU time spent for this process.")]
715 public TimeSpan TotalProcessorTime {
717 return new TimeSpan (Times (process_handle, 2));
721 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
722 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
723 public TimeSpan UserProcessorTime {
725 return new TimeSpan (Times (process_handle, 0));
730 [Obsolete ("Use VirtualMemorySize64")]
732 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
733 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
734 public int VirtualMemorySize {
737 return (int)GetProcessData (pid, 7, out error);
742 [Obsolete ("Use WorkingSet64")]
744 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
745 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
746 public int WorkingSet {
749 return (int)GetProcessData (pid, 4, out error);
754 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
755 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
757 public long PrivateMemorySize64 {
760 return GetProcessData (pid, 6, out error);
764 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
765 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
767 public long VirtualMemorySize64 {
770 return GetProcessData (pid, 7, out error);
774 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
775 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
777 public long WorkingSet64 {
780 return GetProcessData (pid, 4, out error);
790 [MethodImplAttribute(MethodImplOptions.InternalCall)]
791 extern static bool Kill_internal (IntPtr handle, int signo);
793 /* int kill -> 1 KILL, 2 CloseMainWindow */
794 bool Close (int signo)
796 if (process_handle == IntPtr.Zero)
797 throw new SystemException ("No process to kill.");
799 int exitcode = ExitCode_internal (process_handle);
801 throw new InvalidOperationException ("The process already finished.");
803 return Kill_internal (process_handle, signo);
806 public bool CloseMainWindow ()
812 public static void EnterDebugMode() {
815 [MethodImplAttribute(MethodImplOptions.InternalCall)]
816 private extern static IntPtr GetProcess_internal(int pid);
818 [MethodImplAttribute(MethodImplOptions.InternalCall)]
819 private extern static int GetPid_internal();
821 public static Process GetCurrentProcess()
823 int pid = GetPid_internal();
824 IntPtr proc = GetProcess_internal(pid);
826 if (proc == IntPtr.Zero)
827 throw new SystemException("Can't find current process");
829 return (new Process (proc, pid));
832 public static Process GetProcessById(int processId)
834 IntPtr proc = GetProcess_internal(processId);
836 if (proc == IntPtr.Zero)
837 throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
839 return (new Process (proc, processId));
842 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
843 public static Process GetProcessById(int processId, string machineName) {
844 if (machineName == null)
845 throw new ArgumentNullException ("machineName");
847 if (!IsLocalMachine (machineName))
848 throw new NotImplementedException ();
850 return GetProcessById (processId);
853 [MethodImplAttribute(MethodImplOptions.InternalCall)]
854 private extern static int[] GetProcesses_internal();
856 public static Process[] GetProcesses()
858 int [] pids = GetProcesses_internal ();
859 ArrayList proclist = new ArrayList ();
861 for (int i = 0; i < pids.Length; i++) {
863 proclist.Add (GetProcessById (pids [i]));
864 } catch (SystemException) {
865 /* The process might exit
867 * GetProcesses_internal and
873 return ((Process []) proclist.ToArray (typeof (Process)));
876 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
877 public static Process[] GetProcesses(string machineName) {
878 if (machineName == null)
879 throw new ArgumentNullException ("machineName");
881 if (!IsLocalMachine (machineName))
882 throw new NotImplementedException ();
884 return GetProcesses ();
887 public static Process[] GetProcessesByName(string processName)
889 Process [] procs = GetProcesses();
890 ArrayList proclist = new ArrayList();
892 for (int i = 0; i < procs.Length; i++) {
894 if (String.Compare (processName,
895 procs [i].ProcessName,
897 proclist.Add (procs [i]);
901 return ((Process[]) proclist.ToArray (typeof(Process)));
905 public static Process[] GetProcessesByName(string processName, string machineName) {
906 throw new NotImplementedException();
915 public static void LeaveDebugMode() {
918 public void Refresh ()
920 // FIXME: should refresh any cached data we might have about
921 // the process (currently we have none).
924 [MethodImplAttribute(MethodImplOptions.InternalCall)]
925 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
926 ref ProcInfo proc_info);
928 [MethodImplAttribute(MethodImplOptions.InternalCall)]
929 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
933 ref ProcInfo proc_info);
935 private static bool Start_shell (ProcessStartInfo startInfo,
938 ProcInfo proc_info=new ProcInfo();
941 if (startInfo.RedirectStandardInput ||
942 startInfo.RedirectStandardOutput ||
943 startInfo.RedirectStandardError) {
944 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
947 if (startInfo.HaveEnvVars)
948 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
950 FillUserInfo (startInfo, ref proc_info);
952 ret = ShellExecuteEx_internal (startInfo,
955 if (proc_info.Password != IntPtr.Zero)
956 Marshal.FreeBSTR (proc_info.Password);
957 proc_info.Password = IntPtr.Zero;
960 throw new Win32Exception (-proc_info.pid);
963 process.process_handle = proc_info.process_handle;
964 process.pid = proc_info.pid;
966 process.StartExitCallbackIfNeeded ();
971 private static bool Start_noshell (ProcessStartInfo startInfo,
974 ProcInfo proc_info=new ProcInfo();
975 IntPtr stdin_rd = IntPtr.Zero, stdin_wr = IntPtr.Zero;
981 if (startInfo.HaveEnvVars) {
982 string [] strs = new string [startInfo.EnvironmentVariables.Count];
983 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
984 proc_info.envKeys = strs;
986 strs = new string [startInfo.EnvironmentVariables.Count];
987 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
988 proc_info.envValues = strs;
991 if (startInfo.RedirectStandardInput == true) {
993 int DUPLICATE_SAME_ACCESS = 0x00000002;
996 ret = MonoIO.CreatePipe (out stdin_rd,
999 ret = MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, stdin_wr_tmp,
1000 Process.GetCurrentProcess ().Handle, out stdin_wr, 0, 0, DUPLICATE_SAME_ACCESS);
1001 MonoIO.Close (stdin_wr_tmp, out error);
1006 ret = MonoIO.CreatePipe (out stdin_rd,
1010 throw new IOException ("Error creating standard input pipe");
1013 stdin_rd = MonoIO.ConsoleInput;
1014 /* This is required to stop the
1015 * &$*£ing stupid compiler moaning
1016 * that stdin_wr is unassigned, below.
1018 stdin_wr = (IntPtr)0;
1021 if (startInfo.RedirectStandardOutput == true) {
1022 IntPtr out_rd = IntPtr.Zero;
1025 int DUPLICATE_SAME_ACCESS = 0x00000002;
1027 ret = MonoIO.CreatePipe (out out_rd_tmp,
1030 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, out_rd_tmp,
1031 Process.GetCurrentProcess ().Handle, out out_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1032 MonoIO.Close (out_rd_tmp, out error);
1036 ret = MonoIO.CreatePipe (out out_rd,
1040 process.stdout_rd = out_rd;
1042 if (startInfo.RedirectStandardInput == true) {
1043 MonoIO.Close (stdin_rd, out error);
1044 MonoIO.Close (stdin_wr, out error);
1047 throw new IOException ("Error creating standard output pipe");
1050 process.stdout_rd = (IntPtr)0;
1051 stdout_wr = MonoIO.ConsoleOutput;
1054 if (startInfo.RedirectStandardError == true) {
1055 IntPtr err_rd = IntPtr.Zero;
1058 int DUPLICATE_SAME_ACCESS = 0x00000002;
1060 ret = MonoIO.CreatePipe (out err_rd_tmp,
1063 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, err_rd_tmp,
1064 Process.GetCurrentProcess ().Handle, out err_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1065 MonoIO.Close (err_rd_tmp, out error);
1069 ret = MonoIO.CreatePipe (out err_rd,
1073 process.stderr_rd = err_rd;
1075 if (startInfo.RedirectStandardInput == true) {
1076 MonoIO.Close (stdin_rd, out error);
1077 MonoIO.Close (stdin_wr, out error);
1079 if (startInfo.RedirectStandardOutput == true) {
1080 MonoIO.Close (process.stdout_rd, out error);
1081 MonoIO.Close (stdout_wr, out error);
1084 throw new IOException ("Error creating standard error pipe");
1087 process.stderr_rd = (IntPtr)0;
1088 stderr_wr = MonoIO.ConsoleError;
1091 FillUserInfo (startInfo, ref proc_info);
1093 ret = CreateProcess_internal (startInfo,
1094 stdin_rd, stdout_wr, stderr_wr,
1097 if (proc_info.Password != IntPtr.Zero)
1098 Marshal.FreeBSTR (proc_info.Password);
1099 proc_info.Password = IntPtr.Zero;
1102 if (startInfo.RedirectStandardInput == true) {
1103 MonoIO.Close (stdin_rd, out error);
1104 MonoIO.Close (stdin_wr, out error);
1107 if (startInfo.RedirectStandardOutput == true) {
1108 MonoIO.Close (process.stdout_rd, out error);
1109 MonoIO.Close (stdout_wr, out error);
1112 if (startInfo.RedirectStandardError == true) {
1113 MonoIO.Close (process.stderr_rd, out error);
1114 MonoIO.Close (stderr_wr, out error);
1117 throw new Win32Exception (-proc_info.pid,
1118 "ApplicationName='" + startInfo.FileName +
1119 "', CommandLine='" + startInfo.Arguments +
1120 "', CurrentDirectory='" + startInfo.WorkingDirectory + "'");
1123 process.process_handle = proc_info.process_handle;
1124 process.pid = proc_info.pid;
1126 if (startInfo.RedirectStandardInput == true) {
1127 MonoIO.Close (stdin_rd, out error);
1128 process.input_stream = new StreamWriter (new MonoSyncFileStream (stdin_wr, FileAccess.Write, true, 8192), Console.Out.Encoding);
1129 process.input_stream.AutoFlush = true;
1133 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1134 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1136 Encoding stdoutEncoding = Console.Out.Encoding;
1137 Encoding stderrEncoding = stdoutEncoding;
1140 if (startInfo.RedirectStandardOutput == true) {
1141 MonoIO.Close (stdout_wr, out error);
1142 process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding, true, 8192);
1145 if (startInfo.RedirectStandardError == true) {
1146 MonoIO.Close (stderr_wr, out error);
1147 process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding, true, 8192);
1150 process.StartExitCallbackIfNeeded ();
1155 // Note that ProcInfo.Password must be freed.
1156 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1159 if (startInfo.UserName != null) {
1160 proc_info.UserName = startInfo.UserName;
1161 proc_info.Domain = startInfo.Domain;
1162 if (startInfo.Password != null)
1163 proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1165 proc_info.Password = IntPtr.Zero;
1166 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1171 private static bool Start_common (ProcessStartInfo startInfo,
1174 if (startInfo.FileName == null || startInfo.FileName.Length == 0)
1175 throw new InvalidOperationException("File name has not been set");
1178 if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1179 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1180 if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1181 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1184 if (startInfo.UseShellExecute) {
1186 if (!String.IsNullOrEmpty (startInfo.UserName))
1187 throw new InvalidOperationException ("UserShellExecute must be false if an explicit UserName is specified when starting a process");
1189 return (Start_shell (startInfo, process));
1191 return (Start_noshell (startInfo, process));
1195 public bool Start ()
1197 if (process_handle != IntPtr.Zero) {
1198 Process_free_internal (process_handle);
1199 process_handle = IntPtr.Zero;
1201 return Start_common(start_info, this);
1204 public static Process Start (ProcessStartInfo startInfo)
1206 if (startInfo == null)
1207 throw new ArgumentNullException ("startInfo");
1209 Process process=new Process();
1210 process.StartInfo = startInfo;
1211 if (Start_common(startInfo, process))
1216 public static Process Start (string fileName)
1218 return Start (new ProcessStartInfo (fileName));
1221 public static Process Start(string fileName, string arguments)
1223 return Start (new ProcessStartInfo (fileName, arguments));
1227 public static Process Start(string fileName, string username, SecureString password, string domain) {
1228 return Start(fileName, null, username, password, domain);
1231 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1232 ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1233 psi.UserName = username;
1234 psi.Password = password;
1235 psi.Domain = domain;
1236 psi.UseShellExecute = false;
1241 public override string ToString()
1243 return(base.ToString() + " (" + this.ProcessName + ")");
1246 /* Waits up to ms milliseconds for process 'handle' to
1247 * exit. ms can be <0 to mean wait forever.
1249 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1250 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1252 public void WaitForExit ()
1257 public bool WaitForExit(int milliseconds) {
1258 int ms = milliseconds;
1259 if (ms == int.MaxValue)
1263 DateTime start = DateTime.UtcNow;
1264 if (async_output != null && !async_output.IsCompleted) {
1265 if (false == async_output.WaitHandle.WaitOne (ms, false))
1266 return false; // Timed out
1269 DateTime now = DateTime.UtcNow;
1270 ms -= (int) (now - start).TotalMilliseconds;
1277 if (async_error != null && !async_error.IsCompleted) {
1278 if (false == async_error.WaitHandle.WaitOne (ms, false))
1279 return false; // Timed out
1282 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1288 return WaitForExit_internal (process_handle, ms);
1291 /* Waits up to ms milliseconds for process 'handle' to
1292 * wait for input. ms can be <0 to mean wait forever.
1294 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1295 private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
1297 // The internal call is only implemented properly on Windows.
1299 public bool WaitForInputIdle() {
1300 return WaitForInputIdle (-1);
1303 // The internal call is only implemented properly on Windows.
1305 public bool WaitForInputIdle(int milliseconds) {
1306 return WaitForInputIdle_internal (process_handle, milliseconds);
1309 private static bool IsLocalMachine (string machineName)
1311 if (machineName == "." || machineName.Length == 0)
1314 return (string.Compare (machineName, Environment.MachineName, true) == 0);
1319 [MonitoringDescription ("Raised when it receives output data")]
1320 public event DataReceivedEventHandler OutputDataReceived;
1322 [MonitoringDescription ("Raised when it receives error data")]
1323 public event DataReceivedEventHandler ErrorDataReceived;
1325 void OnOutputDataReceived (string str)
1327 if (OutputDataReceived != null)
1328 OutputDataReceived (this, new DataReceivedEventArgs (str));
1331 void OnErrorDataReceived (string str)
1333 if (ErrorDataReceived != null)
1334 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1342 AsyncOutput = 1 << 2,
1346 [StructLayout (LayoutKind.Sequential)]
1347 sealed class ProcessAsyncReader
1350 The following fields match those of SocketAsyncResult.
1351 This is so that changes needed in the runtime to handle
1352 asynchronous reads are trivial
1353 Keep this in sync with SocketAsyncResult in
1354 ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
1355 in metadata/socket-io.h.
1357 /* DON'T shuffle fields around. DON'T remove fields */
1359 public IntPtr handle;
1360 public object state;
1361 public AsyncCallback callback;
1362 public ManualResetEvent wait_handle;
1364 public Exception delayedException;
1366 public object EndPoint;
1367 byte [] buffer = new byte [4196];
1370 public int SockFlags;
1372 public object AcceptSocket;
1373 public object[] Addresses;
1375 public object Buffers; // Reserve this slot in older profiles
1376 public bool ReuseSocket; // Disconnect
1377 public object acc_socket;
1379 public bool completed_sync;
1381 bool err_out; // true -> stdout, false -> stderr
1383 public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1387 // These fields are not in SocketAsyncResult
1390 StringBuilder sb = new StringBuilder ();
1391 public AsyncReadHandler ReadHandler;
1393 public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1395 this.process = process;
1396 this.handle = handle;
1397 stream = new FileStream (handle, FileAccess.Read, false);
1398 this.ReadHandler = new AsyncReadHandler (AddInput);
1399 this.err_out = err_out;
1402 public void AddInput ()
1405 int nread = stream.Read (buffer, 0, buffer.Length);
1408 if (wait_handle != null)
1415 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1417 // Just in case the encoding fails...
1418 for (int i = 0; i < nread; i++) {
1419 sb.Append ((char) buffer [i]);
1424 ReadHandler.BeginInvoke (null, this);
1432 process.OnOutputDataReceived (null);
1434 process.OnErrorDataReceived (null);
1438 void Flush (bool last)
1440 if (sb.Length == 0 ||
1441 (err_out && process.output_canceled) ||
1442 (!err_out && process.error_canceled))
1445 string total = sb.ToString ();
1447 string [] strs = total.Split ('\n');
1448 int len = strs.Length;
1452 for (int i = 0; i < len - 1; i++) {
1454 process.OnOutputDataReceived (strs [i]);
1456 process.OnErrorDataReceived (strs [i]);
1459 string end = strs [len - 1];
1460 if (last || (len == 1 && end == "")) {
1462 process.OnOutputDataReceived (end);
1464 process.OnErrorDataReceived (end);
1471 public bool IsCompleted {
1472 get { return completed; }
1475 public WaitHandle WaitHandle {
1478 if (wait_handle == null)
1479 wait_handle = new ManualResetEvent (completed);
1486 AsyncModes async_mode;
1487 bool output_canceled;
1488 bool error_canceled;
1489 ProcessAsyncReader async_output;
1490 ProcessAsyncReader async_error;
1491 delegate void AsyncReadHandler ();
1493 [ComVisibleAttribute(false)]
1494 public void BeginOutputReadLine ()
1496 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1497 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1499 if ((async_mode & AsyncModes.SyncOutput) != 0)
1500 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1502 async_mode |= AsyncModes.AsyncOutput;
1503 output_canceled = false;
1504 if (async_output == null) {
1505 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1506 async_output.ReadHandler.BeginInvoke (null, async_output);
1510 [ComVisibleAttribute(false)]
1511 public void CancelOutputRead ()
1513 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1514 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1516 if ((async_mode & AsyncModes.SyncOutput) != 0)
1517 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1519 if (async_output == null)
1520 throw new InvalidOperationException ("No async operation in progress.");
1522 output_canceled = true;
1525 [ComVisibleAttribute(false)]
1526 public void BeginErrorReadLine ()
1528 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1529 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1531 if ((async_mode & AsyncModes.SyncError) != 0)
1532 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1534 async_mode |= AsyncModes.AsyncError;
1535 error_canceled = false;
1536 if (async_error == null) {
1537 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1538 async_error.ReadHandler.BeginInvoke (null, async_error);
1542 [ComVisibleAttribute(false)]
1543 public void CancelErrorRead ()
1545 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1546 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1548 if ((async_mode & AsyncModes.SyncOutput) != 0)
1549 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1551 if (async_error == null)
1552 throw new InvalidOperationException ("No async operation in progress.");
1554 error_canceled = true;
1558 [Category ("Behavior")]
1559 [MonitoringDescription ("Raised when this process exits.")]
1560 public event EventHandler Exited {
1562 if (process_handle != IntPtr.Zero && HasExited) {
1563 value.BeginInvoke (null, null, null, null);
1565 exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1566 if (exited_event != null)
1567 StartExitCallbackIfNeeded ();
1571 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1575 // Closes the system process handle
1576 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1577 private extern void Process_free_internal(IntPtr handle);
1579 private bool disposed = false;
1581 protected override void Dispose(bool disposing) {
1582 // Check to see if Dispose has already been called.
1583 if(this.disposed == false) {
1585 // If this is a call to Dispose,
1586 // dispose all managed resources.
1591 // Release unmanaged resources
1594 if(process_handle!=IntPtr.Zero) {
1595 Process_free_internal(process_handle);
1596 process_handle=IntPtr.Zero;
1599 if (input_stream != null) {
1600 input_stream.Close();
1601 input_stream = null;
1604 if (output_stream != null) {
1605 output_stream.Close();
1606 output_stream = null;
1609 if (error_stream != null) {
1610 error_stream.Close();
1611 error_stream = null;
1615 base.Dispose (disposing);
1623 static void CBOnExit (object state, bool unused)
1625 Process p = (Process) state;
1629 protected void OnExited()
1631 if (exited_event == null)
1634 if (synchronizingObject == null) {
1635 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1637 d (this, EventArgs.Empty);
1643 object [] args = new object [] {this, EventArgs.Empty};
1644 synchronizingObject.BeginInvoke (exited_event, args);
1647 static bool IsWindows
1651 PlatformID platform = Environment.OSVersion.Platform;
1652 if (platform == PlatformID.Win32S ||
1653 platform == PlatformID.Win32Windows ||
1654 platform == PlatformID.Win32NT ||
1655 platform == PlatformID.WinCE) {
1662 class ProcessWaitHandle : WaitHandle
1664 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1665 private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1667 public ProcessWaitHandle (IntPtr handle)
1669 // Need to keep a reference to this handle,
1670 // in case the Process object is collected
1671 Handle = ProcessHandle_duplicate (handle);
1673 // When the wait handle is disposed, the duplicated handle will be
1674 // closed, so no need to override dispose (bug #464628).