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 ();
862 return new Process [0];
864 for (int i = 0; i < pids.Length; i++) {
866 proclist.Add (GetProcessById (pids [i]));
867 } catch (SystemException) {
868 /* The process might exit
870 * GetProcesses_internal and
876 return ((Process []) proclist.ToArray (typeof (Process)));
879 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
880 public static Process[] GetProcesses(string machineName) {
881 if (machineName == null)
882 throw new ArgumentNullException ("machineName");
884 if (!IsLocalMachine (machineName))
885 throw new NotImplementedException ();
887 return GetProcesses ();
890 public static Process[] GetProcessesByName(string processName)
892 int [] pids = GetProcesses_internal ();
894 return new Process [0];
896 ArrayList proclist = new ArrayList ();
897 for (int i = 0; i < pids.Length; i++) {
899 Process p = GetProcessById (pids [i]);
900 if (String.Compare (processName, p.ProcessName, true) == 0)
902 } catch (SystemException) {
903 /* The process might exit
905 * GetProcesses_internal and
911 return ((Process []) proclist.ToArray (typeof (Process)));
915 public static Process[] GetProcessesByName(string processName, string machineName) {
916 throw new NotImplementedException();
925 public static void LeaveDebugMode() {
928 public void Refresh ()
930 // FIXME: should refresh any cached data we might have about
931 // the process (currently we have none).
934 [MethodImplAttribute(MethodImplOptions.InternalCall)]
935 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
936 ref ProcInfo proc_info);
938 [MethodImplAttribute(MethodImplOptions.InternalCall)]
939 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
943 ref ProcInfo proc_info);
945 private static bool Start_shell (ProcessStartInfo startInfo,
948 ProcInfo proc_info=new ProcInfo();
951 if (startInfo.RedirectStandardInput ||
952 startInfo.RedirectStandardOutput ||
953 startInfo.RedirectStandardError) {
954 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
957 if (startInfo.HaveEnvVars)
958 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
960 FillUserInfo (startInfo, ref proc_info);
962 ret = ShellExecuteEx_internal (startInfo,
965 if (proc_info.Password != IntPtr.Zero)
966 Marshal.FreeBSTR (proc_info.Password);
967 proc_info.Password = IntPtr.Zero;
970 throw new Win32Exception (-proc_info.pid);
973 process.process_handle = proc_info.process_handle;
974 process.pid = proc_info.pid;
976 process.StartExitCallbackIfNeeded ();
981 private static bool Start_noshell (ProcessStartInfo startInfo,
984 ProcInfo proc_info=new ProcInfo();
985 IntPtr stdin_rd = IntPtr.Zero, stdin_wr = IntPtr.Zero;
991 if (startInfo.HaveEnvVars) {
992 string [] strs = new string [startInfo.EnvironmentVariables.Count];
993 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
994 proc_info.envKeys = strs;
996 strs = new string [startInfo.EnvironmentVariables.Count];
997 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
998 proc_info.envValues = strs;
1001 if (startInfo.RedirectStandardInput == true) {
1003 int DUPLICATE_SAME_ACCESS = 0x00000002;
1004 IntPtr stdin_wr_tmp;
1006 ret = MonoIO.CreatePipe (out stdin_rd,
1009 ret = MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, stdin_wr_tmp,
1010 Process.GetCurrentProcess ().Handle, out stdin_wr, 0, 0, DUPLICATE_SAME_ACCESS);
1011 MonoIO.Close (stdin_wr_tmp, out error);
1016 ret = MonoIO.CreatePipe (out stdin_rd,
1020 throw new IOException ("Error creating standard input pipe");
1023 stdin_rd = MonoIO.ConsoleInput;
1024 /* This is required to stop the
1025 * &$*£ing stupid compiler moaning
1026 * that stdin_wr is unassigned, below.
1028 stdin_wr = (IntPtr)0;
1031 if (startInfo.RedirectStandardOutput == true) {
1032 IntPtr out_rd = IntPtr.Zero;
1035 int DUPLICATE_SAME_ACCESS = 0x00000002;
1037 ret = MonoIO.CreatePipe (out out_rd_tmp,
1040 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, out_rd_tmp,
1041 Process.GetCurrentProcess ().Handle, out out_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1042 MonoIO.Close (out_rd_tmp, out error);
1046 ret = MonoIO.CreatePipe (out out_rd,
1050 process.stdout_rd = out_rd;
1052 if (startInfo.RedirectStandardInput == true) {
1053 MonoIO.Close (stdin_rd, out error);
1054 MonoIO.Close (stdin_wr, out error);
1057 throw new IOException ("Error creating standard output pipe");
1060 process.stdout_rd = (IntPtr)0;
1061 stdout_wr = MonoIO.ConsoleOutput;
1064 if (startInfo.RedirectStandardError == true) {
1065 IntPtr err_rd = IntPtr.Zero;
1068 int DUPLICATE_SAME_ACCESS = 0x00000002;
1070 ret = MonoIO.CreatePipe (out err_rd_tmp,
1073 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, err_rd_tmp,
1074 Process.GetCurrentProcess ().Handle, out err_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1075 MonoIO.Close (err_rd_tmp, out error);
1079 ret = MonoIO.CreatePipe (out err_rd,
1083 process.stderr_rd = err_rd;
1085 if (startInfo.RedirectStandardInput == true) {
1086 MonoIO.Close (stdin_rd, out error);
1087 MonoIO.Close (stdin_wr, out error);
1089 if (startInfo.RedirectStandardOutput == true) {
1090 MonoIO.Close (process.stdout_rd, out error);
1091 MonoIO.Close (stdout_wr, out error);
1094 throw new IOException ("Error creating standard error pipe");
1097 process.stderr_rd = (IntPtr)0;
1098 stderr_wr = MonoIO.ConsoleError;
1101 FillUserInfo (startInfo, ref proc_info);
1103 ret = CreateProcess_internal (startInfo,
1104 stdin_rd, stdout_wr, stderr_wr,
1107 if (proc_info.Password != IntPtr.Zero)
1108 Marshal.FreeBSTR (proc_info.Password);
1109 proc_info.Password = IntPtr.Zero;
1112 if (startInfo.RedirectStandardInput == true) {
1113 MonoIO.Close (stdin_rd, out error);
1114 MonoIO.Close (stdin_wr, out error);
1117 if (startInfo.RedirectStandardOutput == true) {
1118 MonoIO.Close (process.stdout_rd, out error);
1119 MonoIO.Close (stdout_wr, out error);
1122 if (startInfo.RedirectStandardError == true) {
1123 MonoIO.Close (process.stderr_rd, out error);
1124 MonoIO.Close (stderr_wr, out error);
1127 throw new Win32Exception (-proc_info.pid,
1128 "ApplicationName='" + startInfo.FileName +
1129 "', CommandLine='" + startInfo.Arguments +
1130 "', CurrentDirectory='" + startInfo.WorkingDirectory + "'");
1133 process.process_handle = proc_info.process_handle;
1134 process.pid = proc_info.pid;
1136 if (startInfo.RedirectStandardInput == true) {
1137 MonoIO.Close (stdin_rd, out error);
1138 process.input_stream = new StreamWriter (new MonoSyncFileStream (stdin_wr, FileAccess.Write, true, 8192), Console.Out.Encoding);
1139 process.input_stream.AutoFlush = true;
1143 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1144 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1146 Encoding stdoutEncoding = Console.Out.Encoding;
1147 Encoding stderrEncoding = stdoutEncoding;
1150 if (startInfo.RedirectStandardOutput == true) {
1151 MonoIO.Close (stdout_wr, out error);
1152 process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding, true, 8192);
1155 if (startInfo.RedirectStandardError == true) {
1156 MonoIO.Close (stderr_wr, out error);
1157 process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding, true, 8192);
1160 process.StartExitCallbackIfNeeded ();
1165 // Note that ProcInfo.Password must be freed.
1166 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1169 if (startInfo.UserName != null) {
1170 proc_info.UserName = startInfo.UserName;
1171 proc_info.Domain = startInfo.Domain;
1172 if (startInfo.Password != null)
1173 proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1175 proc_info.Password = IntPtr.Zero;
1176 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1181 private static bool Start_common (ProcessStartInfo startInfo,
1184 if (startInfo.FileName == null || startInfo.FileName.Length == 0)
1185 throw new InvalidOperationException("File name has not been set");
1188 if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1189 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1190 if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1191 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1194 if (startInfo.UseShellExecute) {
1196 if (!String.IsNullOrEmpty (startInfo.UserName))
1197 throw new InvalidOperationException ("UserShellExecute must be false if an explicit UserName is specified when starting a process");
1199 return (Start_shell (startInfo, process));
1201 return (Start_noshell (startInfo, process));
1205 public bool Start ()
1207 if (process_handle != IntPtr.Zero) {
1208 Process_free_internal (process_handle);
1209 process_handle = IntPtr.Zero;
1211 return Start_common(start_info, this);
1214 public static Process Start (ProcessStartInfo startInfo)
1216 if (startInfo == null)
1217 throw new ArgumentNullException ("startInfo");
1219 Process process=new Process();
1220 process.StartInfo = startInfo;
1221 if (Start_common(startInfo, process))
1226 public static Process Start (string fileName)
1228 return Start (new ProcessStartInfo (fileName));
1231 public static Process Start(string fileName, string arguments)
1233 return Start (new ProcessStartInfo (fileName, arguments));
1237 public static Process Start(string fileName, string username, SecureString password, string domain) {
1238 return Start(fileName, null, username, password, domain);
1241 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1242 ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1243 psi.UserName = username;
1244 psi.Password = password;
1245 psi.Domain = domain;
1246 psi.UseShellExecute = false;
1251 public override string ToString()
1253 return(base.ToString() + " (" + this.ProcessName + ")");
1256 /* Waits up to ms milliseconds for process 'handle' to
1257 * exit. ms can be <0 to mean wait forever.
1259 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1260 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1262 public void WaitForExit ()
1267 public bool WaitForExit(int milliseconds) {
1268 int ms = milliseconds;
1269 if (ms == int.MaxValue)
1273 DateTime start = DateTime.UtcNow;
1274 if (async_output != null && !async_output.IsCompleted) {
1275 if (false == async_output.WaitHandle.WaitOne (ms, false))
1276 return false; // Timed out
1279 DateTime now = DateTime.UtcNow;
1280 ms -= (int) (now - start).TotalMilliseconds;
1287 if (async_error != null && !async_error.IsCompleted) {
1288 if (false == async_error.WaitHandle.WaitOne (ms, false))
1289 return false; // Timed out
1292 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1298 return WaitForExit_internal (process_handle, ms);
1301 /* Waits up to ms milliseconds for process 'handle' to
1302 * wait for input. ms can be <0 to mean wait forever.
1304 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1305 private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
1307 // The internal call is only implemented properly on Windows.
1309 public bool WaitForInputIdle() {
1310 return WaitForInputIdle (-1);
1313 // The internal call is only implemented properly on Windows.
1315 public bool WaitForInputIdle(int milliseconds) {
1316 return WaitForInputIdle_internal (process_handle, milliseconds);
1319 private static bool IsLocalMachine (string machineName)
1321 if (machineName == "." || machineName.Length == 0)
1324 return (string.Compare (machineName, Environment.MachineName, true) == 0);
1329 [MonitoringDescription ("Raised when it receives output data")]
1330 public event DataReceivedEventHandler OutputDataReceived;
1332 [MonitoringDescription ("Raised when it receives error data")]
1333 public event DataReceivedEventHandler ErrorDataReceived;
1335 void OnOutputDataReceived (string str)
1337 if (OutputDataReceived != null)
1338 OutputDataReceived (this, new DataReceivedEventArgs (str));
1341 void OnErrorDataReceived (string str)
1343 if (ErrorDataReceived != null)
1344 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1352 AsyncOutput = 1 << 2,
1356 [StructLayout (LayoutKind.Sequential)]
1357 sealed class ProcessAsyncReader
1360 The following fields match those of SocketAsyncResult.
1361 This is so that changes needed in the runtime to handle
1362 asynchronous reads are trivial
1363 Keep this in sync with SocketAsyncResult in
1364 ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
1365 in metadata/socket-io.h.
1367 /* DON'T shuffle fields around. DON'T remove fields */
1369 public IntPtr handle;
1370 public object state;
1371 public AsyncCallback callback;
1372 public ManualResetEvent wait_handle;
1374 public Exception delayedException;
1376 public object EndPoint;
1377 byte [] buffer = new byte [4196];
1380 public int SockFlags;
1382 public object AcceptSocket;
1383 public object[] Addresses;
1385 public object Buffers; // Reserve this slot in older profiles
1386 public bool ReuseSocket; // Disconnect
1387 public object acc_socket;
1389 public bool completed_sync;
1391 bool err_out; // true -> stdout, false -> stderr
1393 public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1395 public int EndCalled;
1397 // These fields are not in SocketAsyncResult
1400 StringBuilder sb = new StringBuilder ();
1401 public AsyncReadHandler ReadHandler;
1403 public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1405 this.process = process;
1406 this.handle = handle;
1407 stream = new FileStream (handle, FileAccess.Read, false);
1408 this.ReadHandler = new AsyncReadHandler (AddInput);
1409 this.err_out = err_out;
1412 public void AddInput ()
1415 int nread = stream.Read (buffer, 0, buffer.Length);
1418 if (wait_handle != null)
1425 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1427 // Just in case the encoding fails...
1428 for (int i = 0; i < nread; i++) {
1429 sb.Append ((char) buffer [i]);
1434 ReadHandler.BeginInvoke (null, this);
1442 process.OnOutputDataReceived (null);
1444 process.OnErrorDataReceived (null);
1448 void Flush (bool last)
1450 if (sb.Length == 0 ||
1451 (err_out && process.output_canceled) ||
1452 (!err_out && process.error_canceled))
1455 string total = sb.ToString ();
1457 string [] strs = total.Split ('\n');
1458 int len = strs.Length;
1462 for (int i = 0; i < len - 1; i++) {
1464 process.OnOutputDataReceived (strs [i]);
1466 process.OnErrorDataReceived (strs [i]);
1469 string end = strs [len - 1];
1470 if (last || (len == 1 && end == "")) {
1472 process.OnOutputDataReceived (end);
1474 process.OnErrorDataReceived (end);
1481 public bool IsCompleted {
1482 get { return completed; }
1485 public WaitHandle WaitHandle {
1488 if (wait_handle == null)
1489 wait_handle = new ManualResetEvent (completed);
1495 public void Close () {
1500 AsyncModes async_mode;
1501 bool output_canceled;
1502 bool error_canceled;
1503 ProcessAsyncReader async_output;
1504 ProcessAsyncReader async_error;
1505 delegate void AsyncReadHandler ();
1507 [ComVisibleAttribute(false)]
1508 public void BeginOutputReadLine ()
1510 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1511 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1513 if ((async_mode & AsyncModes.SyncOutput) != 0)
1514 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1516 async_mode |= AsyncModes.AsyncOutput;
1517 output_canceled = false;
1518 if (async_output == null) {
1519 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1520 async_output.ReadHandler.BeginInvoke (null, async_output);
1524 [ComVisibleAttribute(false)]
1525 public void CancelOutputRead ()
1527 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1528 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1530 if ((async_mode & AsyncModes.SyncOutput) != 0)
1531 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1533 if (async_output == null)
1534 throw new InvalidOperationException ("No async operation in progress.");
1536 output_canceled = true;
1539 [ComVisibleAttribute(false)]
1540 public void BeginErrorReadLine ()
1542 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1543 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1545 if ((async_mode & AsyncModes.SyncError) != 0)
1546 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1548 async_mode |= AsyncModes.AsyncError;
1549 error_canceled = false;
1550 if (async_error == null) {
1551 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1552 async_error.ReadHandler.BeginInvoke (null, async_error);
1556 [ComVisibleAttribute(false)]
1557 public void CancelErrorRead ()
1559 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1560 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1562 if ((async_mode & AsyncModes.SyncOutput) != 0)
1563 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1565 if (async_error == null)
1566 throw new InvalidOperationException ("No async operation in progress.");
1568 error_canceled = true;
1572 [Category ("Behavior")]
1573 [MonitoringDescription ("Raised when this process exits.")]
1574 public event EventHandler Exited {
1576 if (process_handle != IntPtr.Zero && HasExited) {
1577 value.BeginInvoke (null, null, null, null);
1579 exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1580 if (exited_event != null)
1581 StartExitCallbackIfNeeded ();
1585 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1589 // Closes the system process handle
1590 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1591 private extern void Process_free_internal(IntPtr handle);
1593 private bool disposed = false;
1595 protected override void Dispose(bool disposing) {
1596 // Check to see if Dispose has already been called.
1597 if(this.disposed == false) {
1599 // If this is a call to Dispose,
1600 // dispose all managed resources.
1604 /* These have open FileStreams on the pipes we are about to close */
1605 if (async_output != null)
1606 async_output.Close ();
1607 if (async_error != null)
1608 async_error.Close ();
1612 // Release unmanaged resources
1615 if(process_handle!=IntPtr.Zero) {
1616 Process_free_internal(process_handle);
1617 process_handle=IntPtr.Zero;
1620 if (input_stream != null) {
1621 input_stream.Close();
1622 input_stream = null;
1625 if (output_stream != null) {
1626 output_stream.Close();
1627 output_stream = null;
1630 if (error_stream != null) {
1631 error_stream.Close();
1632 error_stream = null;
1636 base.Dispose (disposing);
1644 static void CBOnExit (object state, bool unused)
1646 Process p = (Process) state;
1647 p.already_waiting = false;
1651 protected void OnExited()
1653 if (exited_event == null)
1656 if (synchronizingObject == null) {
1657 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1659 d (this, EventArgs.Empty);
1665 object [] args = new object [] {this, EventArgs.Empty};
1666 synchronizingObject.BeginInvoke (exited_event, args);
1669 static bool IsWindows
1673 PlatformID platform = Environment.OSVersion.Platform;
1674 if (platform == PlatformID.Win32S ||
1675 platform == PlatformID.Win32Windows ||
1676 platform == PlatformID.Win32NT ||
1677 platform == PlatformID.WinCE) {
1684 class ProcessWaitHandle : WaitHandle
1686 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1687 private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1689 public ProcessWaitHandle (IntPtr handle)
1691 // Need to keep a reference to this handle,
1692 // in case the Process object is collected
1693 Handle = ProcessHandle_duplicate (handle);
1695 // When the wait handle is disposed, the duplicated handle will be
1696 // closed, so no need to override dispose (bug #464628).