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.Generic;
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)]
52 [MonitoringDescription ("Represents a system process")]
53 public class Process : Component
55 [StructLayout(LayoutKind.Sequential)]
56 private struct ProcInfo
58 public IntPtr process_handle;
59 /* If thread_handle is ever needed for
60 * something, take out the CloseHandle() in
61 * the Start_internal icall in
62 * mono/metadata/process.c
64 public IntPtr thread_handle;
65 public int pid; // Contains -GetLastError () on failure.
67 public string [] envKeys;
68 public string [] envValues;
69 public string UserName;
71 public IntPtr Password;
72 public bool LoadUserProfile;
75 IntPtr process_handle;
77 bool enableRaisingEvents;
79 ISynchronizeInvoke synchronizingObject;
80 EventHandler exited_event;
84 /* Private constructor called from other methods */
85 private Process(IntPtr handle, int id) {
86 process_handle=handle;
95 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
96 [MonitoringDescription ("Base process priority.")]
97 public int BasePriority {
103 void StartExitCallbackIfNeeded ()
105 bool start = (!already_waiting && enableRaisingEvents && exited_event != null);
106 if (start && process_handle != IntPtr.Zero) {
107 WaitOrTimerCallback cb = new WaitOrTimerCallback (CBOnExit);
108 ProcessWaitHandle h = new ProcessWaitHandle (process_handle);
109 ThreadPool.RegisterWaitForSingleObject (h, cb, this, -1, true);
110 already_waiting = true;
114 [DefaultValue (false), Browsable (false)]
115 [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
116 public bool EnableRaisingEvents {
118 return enableRaisingEvents;
121 bool prev = enableRaisingEvents;
122 enableRaisingEvents = value;
123 if (enableRaisingEvents && !prev)
124 StartExitCallbackIfNeeded ();
129 [MethodImplAttribute(MethodImplOptions.InternalCall)]
130 private extern static int ExitCode_internal(IntPtr handle);
132 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
133 [MonitoringDescription ("The exit code of the process.")]
134 public int ExitCode {
136 if (process_handle == IntPtr.Zero)
137 throw new InvalidOperationException ("Process has not been started.");
139 int code = ExitCode_internal (process_handle);
141 throw new InvalidOperationException ("The process must exit before " +
142 "getting the requested information.");
148 /* Returns the process start time in Windows file
149 * times (ticks from DateTime(1/1/1601 00:00 GMT))
151 [MethodImplAttribute(MethodImplOptions.InternalCall)]
152 private extern static long ExitTime_internal(IntPtr handle);
154 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
155 [MonitoringDescription ("The exit time of the process.")]
156 public DateTime ExitTime {
158 if (process_handle == IntPtr.Zero)
159 throw new InvalidOperationException ("Process has not been started.");
162 throw new InvalidOperationException ("The process must exit before " +
163 "getting the requested information.");
165 return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
169 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
170 [MonitoringDescription ("Handle for this process.")]
171 public IntPtr Handle {
173 if (process_handle == IntPtr.Zero)
174 throw new InvalidOperationException ("No process is associated with this object.");
175 return(process_handle);
180 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
181 [MonitoringDescription ("Handles for this process.")]
182 public int HandleCount {
188 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
189 [MonitoringDescription ("Determines if the process is still running.")]
190 public bool HasExited {
192 if (process_handle == IntPtr.Zero)
193 throw new InvalidOperationException ("Process has not been started.");
195 int exitcode = ExitCode_internal (process_handle);
206 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
207 [MonitoringDescription ("Process identifier.")]
211 throw new InvalidOperationException ("Process ID has not been set.");
218 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
219 [MonitoringDescription ("The name of the computer running the process.")]
220 public string MachineName {
226 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
227 [MonitoringDescription ("The main module of the process.")]
228 public ProcessModule MainModule {
230 return(this.Modules[0]);
235 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
236 [MonitoringDescription ("The handle of the main window of the process.")]
237 public IntPtr MainWindowHandle {
244 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
245 [MonitoringDescription ("The title of the main window of the process.")]
246 public string MainWindowTitle {
252 [MethodImplAttribute(MethodImplOptions.InternalCall)]
253 private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
254 [MethodImplAttribute(MethodImplOptions.InternalCall)]
255 private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);
257 /* LAMESPEC: why is this an IntPtr not a plain int? */
258 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
259 [MonitoringDescription ("The maximum working set for this process.")]
260 public IntPtr MaxWorkingSet {
263 throw new InvalidOperationException(
264 "The process " + ProcessName +
265 " (ID " + Id + ") has exited");
269 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
271 throw new Win32Exception();
278 throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
281 bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
283 throw new Win32Exception();
288 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
289 [MonitoringDescription ("The minimum working set for this process.")]
290 public IntPtr MinWorkingSet {
293 throw new InvalidOperationException(
294 "The process " + ProcessName +
295 " (ID " + Id + ") has exited");
299 bool ok= GetWorkingSet_internal (process_handle, out min, out max);
301 throw new Win32Exception();
302 return ((IntPtr) min);
306 throw new InvalidOperationException(
307 "The process " + ProcessName +
308 " (ID " + Id + ") has exited");
310 bool ok = SetWorkingSet_internal (process_handle, value.ToInt32(), 0, true);
312 throw new Win32Exception();
316 /* Returns the list of process modules. The main module is
319 [MethodImplAttribute(MethodImplOptions.InternalCall)]
320 private extern ProcessModule[] GetModules_internal(IntPtr handle);
322 private ProcessModuleCollection module_collection;
324 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
325 [MonitoringDescription ("The modules that are loaded as part of this process.")]
326 public ProcessModuleCollection Modules {
328 if (module_collection == null)
329 module_collection = new ProcessModuleCollection(
330 GetModules_internal (process_handle));
331 return(module_collection);
335 /* data type is from the MonoProcessData enum in mono-proclib.h in the runtime */
336 [MethodImplAttribute(MethodImplOptions.InternalCall)]
337 private extern static long GetProcessData (int pid, int data_type, out int error);
340 [Obsolete ("Use NonpagedSystemMemorySize64")]
341 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
342 [MonitoringDescription ("The number of bytes that are not pageable.")]
343 public int NonpagedSystemMemorySize {
350 [Obsolete ("Use PagedMemorySize64")]
351 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
352 [MonitoringDescription ("The number of bytes that are paged.")]
353 public int PagedMemorySize {
360 [Obsolete ("Use PagedSystemMemorySize64")]
361 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
362 [MonitoringDescription ("The amount of paged system memory in bytes.")]
363 public int PagedSystemMemorySize {
370 [Obsolete ("Use PeakPagedMemorySize64")]
371 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
372 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
373 public int PeakPagedMemorySize {
379 [Obsolete ("Use PeakVirtualMemorySize64")]
380 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
381 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
382 public int PeakVirtualMemorySize {
385 return (int)GetProcessData (pid, 8, out error);
389 [Obsolete ("Use PeakWorkingSet64")]
390 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
391 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
392 public int PeakWorkingSet {
395 return (int)GetProcessData (pid, 5, out error);
400 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
401 [MonitoringDescription ("The number of bytes that are not pageable.")]
403 public long NonpagedSystemMemorySize64 {
410 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
411 [MonitoringDescription ("The number of bytes that are paged.")]
413 public long PagedMemorySize64 {
420 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
421 [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.")]
433 public long PeakPagedMemorySize64 {
439 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
440 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
442 public long PeakVirtualMemorySize64 {
445 return GetProcessData (pid, 8, out error);
449 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
450 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
452 public long PeakWorkingSet64 {
455 return GetProcessData (pid, 5, out error);
460 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
461 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
462 public bool PriorityBoostEnabled {
470 [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
471 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
472 [MonitoringDescription ("The relative process priority.")]
473 public ProcessPriorityClass PriorityClass {
475 if (process_handle == IntPtr.Zero)
476 throw new InvalidOperationException ("Process has not been started.");
479 int prio = GetPriorityClass (process_handle, out error);
481 throw new Win32Exception (error);
482 return (ProcessPriorityClass) prio;
485 if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
486 throw new InvalidEnumArgumentException (
487 "value", (int) value,
488 typeof (ProcessPriorityClass));
490 if (process_handle == IntPtr.Zero)
491 throw new InvalidOperationException ("Process has not been started.");
494 if (!SetPriorityClass (process_handle, (int) value, out error)) {
496 throw new Win32Exception (error);
501 void CheckExited () {
503 throw new InvalidOperationException (String.Format ("Cannot process request because the process ({0}) has exited.", Id));
506 [MethodImplAttribute(MethodImplOptions.InternalCall)]
507 static extern int GetPriorityClass (IntPtr handle, out int error);
509 [MethodImplAttribute(MethodImplOptions.InternalCall)]
510 static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);
512 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
513 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
514 [Obsolete ("Use PrivateMemorySize64")]
515 public int PrivateMemorySize {
518 return (int)GetProcessData (pid, 6, out error);
522 [MonoNotSupported ("")]
523 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
524 [MonitoringDescription ("The session ID for this process.")]
525 public int SessionId {
526 get { throw new NotImplementedException (); }
529 /* the meaning of type is as follows: 0: user, 1: system, 2: total */
530 [MethodImplAttribute(MethodImplOptions.InternalCall)]
531 private extern static long Times (IntPtr handle, int type);
533 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
534 [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
535 public TimeSpan PrivilegedProcessorTime {
537 return new TimeSpan (Times (process_handle, 1));
541 [MethodImplAttribute(MethodImplOptions.InternalCall)]
542 private extern static string ProcessName_internal(IntPtr handle);
544 private string process_name=null;
546 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
547 [MonitoringDescription ("The name of this process.")]
548 public string ProcessName {
550 if(process_name==null) {
552 if (process_handle == IntPtr.Zero)
553 throw new InvalidOperationException ("No process is associated with this object.");
555 process_name=ProcessName_internal(process_handle);
556 /* If process_name is _still_
557 * null, assume the process
560 if (process_name == null)
561 throw new InvalidOperationException ("Process has exited, so the requested information is not available.");
563 /* Strip the suffix (if it
564 * exists) simplistically
565 * instead of removing any
566 * trailing \.???, so we dont
567 * get stupid results on sane
570 if(process_name.EndsWith(".exe") ||
571 process_name.EndsWith(".bat") ||
572 process_name.EndsWith(".com")) {
573 process_name=process_name.Substring(0, process_name.Length-4);
576 return(process_name);
581 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
582 [MonitoringDescription ("Allowed processor that can be used by this process.")]
583 public IntPtr ProcessorAffinity {
592 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
593 [MonitoringDescription ("Is this process responsive.")]
594 public bool Responding {
600 private StreamReader error_stream=null;
602 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
603 [MonitoringDescription ("The standard error stream of this process.")]
604 public StreamReader StandardError {
606 if (error_stream == null)
607 throw new InvalidOperationException("Standard error has not been redirected");
609 if ((async_mode & AsyncModes.AsyncError) != 0)
610 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
612 async_mode |= AsyncModes.SyncError;
614 return(error_stream);
618 private StreamWriter input_stream=null;
620 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
621 [MonitoringDescription ("The standard input stream of this process.")]
622 public StreamWriter StandardInput {
624 if (input_stream == null)
625 throw new InvalidOperationException("Standard input has not been redirected");
627 return(input_stream);
631 private StreamReader output_stream=null;
633 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
634 [MonitoringDescription ("The standard output stream of this process.")]
635 public StreamReader StandardOutput {
637 if (output_stream == null)
638 throw new InvalidOperationException("Standard output has not been redirected");
640 if ((async_mode & AsyncModes.AsyncOutput) != 0)
641 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
643 async_mode |= AsyncModes.SyncOutput;
645 return(output_stream);
649 private ProcessStartInfo start_info=null;
651 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
652 [MonitoringDescription ("Information for the start of this process.")]
653 public ProcessStartInfo StartInfo {
655 if (start_info == null)
656 start_info = new ProcessStartInfo();
661 throw new ArgumentNullException("value");
666 /* Returns the process start time in Windows file
667 * times (ticks from DateTime(1/1/1601 00:00 GMT))
669 [MethodImplAttribute(MethodImplOptions.InternalCall)]
670 private extern static long StartTime_internal(IntPtr handle);
672 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
673 [MonitoringDescription ("The time this process started.")]
674 public DateTime StartTime {
676 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
680 [DefaultValue (null), Browsable (false)]
681 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
682 public ISynchronizeInvoke SynchronizingObject {
683 get { return synchronizingObject; }
684 set { synchronizingObject = value; }
688 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
689 [MonitoringDescription ("The number of threads of this process.")]
690 public ProcessThreadCollection Threads {
692 // This'll return a correctly-sized array of empty ProcessThreads for now.
694 return new ProcessThreadCollection(new ProcessThread[GetProcessData (pid, 0, out error)]);
698 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
699 [MonitoringDescription ("The total CPU time spent for this process.")]
700 public TimeSpan TotalProcessorTime {
702 return new TimeSpan (Times (process_handle, 2));
706 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
707 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
708 public TimeSpan UserProcessorTime {
710 return new TimeSpan (Times (process_handle, 0));
714 [Obsolete ("Use VirtualMemorySize64")]
715 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
716 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
717 public int VirtualMemorySize {
720 return (int)GetProcessData (pid, 7, out error);
724 [Obsolete ("Use WorkingSet64")]
725 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
726 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
727 public int WorkingSet {
730 return (int)GetProcessData (pid, 4, out error);
734 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
735 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
737 public long PrivateMemorySize64 {
740 return GetProcessData (pid, 6, out error);
744 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
745 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
747 public long VirtualMemorySize64 {
750 return GetProcessData (pid, 7, out error);
754 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
755 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
757 public long WorkingSet64 {
760 return GetProcessData (pid, 4, out error);
769 [MethodImplAttribute(MethodImplOptions.InternalCall)]
770 extern static bool Kill_internal (IntPtr handle, int signo);
772 /* int kill -> 1 KILL, 2 CloseMainWindow */
773 bool Close (int signo)
775 if (process_handle == IntPtr.Zero)
776 throw new SystemException ("No process to kill.");
778 int exitcode = ExitCode_internal (process_handle);
780 throw new InvalidOperationException ("The process already finished.");
782 return Kill_internal (process_handle, signo);
785 public bool CloseMainWindow ()
791 public static void EnterDebugMode() {
794 [MethodImplAttribute(MethodImplOptions.InternalCall)]
795 private extern static IntPtr GetProcess_internal(int pid);
797 [MethodImplAttribute(MethodImplOptions.InternalCall)]
798 private extern static int GetPid_internal();
800 public static Process GetCurrentProcess()
802 int pid = GetPid_internal();
803 IntPtr proc = GetProcess_internal(pid);
805 if (proc == IntPtr.Zero)
806 throw new SystemException("Can't find current process");
808 return (new Process (proc, pid));
811 public static Process GetProcessById(int processId)
813 IntPtr proc = GetProcess_internal(processId);
815 if (proc == IntPtr.Zero)
816 throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
818 return (new Process (proc, processId));
821 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
822 public static Process GetProcessById(int processId, string machineName) {
823 if (machineName == null)
824 throw new ArgumentNullException ("machineName");
826 if (!IsLocalMachine (machineName))
827 throw new NotImplementedException ();
829 return GetProcessById (processId);
832 [MethodImplAttribute(MethodImplOptions.InternalCall)]
833 private extern static int[] GetProcesses_internal();
835 public static Process[] GetProcesses ()
837 int [] pids = GetProcesses_internal ();
839 return new Process [0];
841 var proclist = new List<Process> (pids.Length);
842 for (int i = 0; i < pids.Length; i++) {
844 proclist.Add (GetProcessById (pids [i]));
845 } catch (SystemException) {
846 /* The process might exit
848 * GetProcesses_internal and
854 return proclist.ToArray ();
857 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
858 public static Process[] GetProcesses(string machineName) {
859 if (machineName == null)
860 throw new ArgumentNullException ("machineName");
862 if (!IsLocalMachine (machineName))
863 throw new NotImplementedException ();
865 return GetProcesses ();
868 public static Process[] GetProcessesByName(string processName)
870 int [] pids = GetProcesses_internal ();
872 return new Process [0];
874 var proclist = new List<Process> (pids.Length);
875 for (int i = 0; i < pids.Length; i++) {
877 Process p = GetProcessById (pids [i]);
878 if (String.Compare (processName, p.ProcessName, true) == 0)
880 } catch (SystemException) {
881 /* The process might exit
883 * GetProcesses_internal and
889 return proclist.ToArray ();
893 public static Process[] GetProcessesByName(string processName, string machineName) {
894 throw new NotImplementedException();
903 public static void LeaveDebugMode() {
906 public void Refresh ()
908 // FIXME: should refresh any cached data we might have about
909 // the process (currently we have none).
912 [MethodImplAttribute(MethodImplOptions.InternalCall)]
913 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
914 ref ProcInfo proc_info);
916 [MethodImplAttribute(MethodImplOptions.InternalCall)]
917 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
921 ref ProcInfo proc_info);
923 private static bool Start_shell (ProcessStartInfo startInfo, Process process)
925 ProcInfo proc_info=new ProcInfo();
928 if (startInfo.RedirectStandardInput ||
929 startInfo.RedirectStandardOutput ||
930 startInfo.RedirectStandardError) {
931 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
934 if (startInfo.HaveEnvVars)
935 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
937 FillUserInfo (startInfo, ref proc_info);
939 ret = ShellExecuteEx_internal (startInfo,
942 if (proc_info.Password != IntPtr.Zero)
943 Marshal.ZeroFreeBSTR (proc_info.Password);
944 proc_info.Password = IntPtr.Zero;
947 throw new Win32Exception (-proc_info.pid);
950 process.process_handle = proc_info.process_handle;
951 process.pid = proc_info.pid;
952 process.StartExitCallbackIfNeeded ();
956 private static bool Start_noshell (ProcessStartInfo startInfo,
959 ProcInfo proc_info=new ProcInfo();
960 IntPtr stdin_rd = IntPtr.Zero, stdin_wr = IntPtr.Zero;
966 if (startInfo.HaveEnvVars) {
967 string [] strs = new string [startInfo.EnvironmentVariables.Count];
968 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
969 proc_info.envKeys = strs;
971 strs = new string [startInfo.EnvironmentVariables.Count];
972 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
973 proc_info.envValues = strs;
976 if (startInfo.RedirectStandardInput == true) {
978 int DUPLICATE_SAME_ACCESS = 0x00000002;
981 ret = MonoIO.CreatePipe (out stdin_rd,
984 ret = MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, stdin_wr_tmp,
985 Process.GetCurrentProcess ().Handle, out stdin_wr, 0, 0, DUPLICATE_SAME_ACCESS);
986 MonoIO.Close (stdin_wr_tmp, out error);
991 ret = MonoIO.CreatePipe (out stdin_rd,
995 throw new IOException ("Error creating standard input pipe");
998 stdin_rd = MonoIO.ConsoleInput;
999 /* This is required to stop the
1000 * &$*£ing stupid compiler moaning
1001 * that stdin_wr is unassigned, below.
1003 stdin_wr = (IntPtr)0;
1006 if (startInfo.RedirectStandardOutput == true) {
1007 IntPtr out_rd = IntPtr.Zero;
1010 int DUPLICATE_SAME_ACCESS = 0x00000002;
1012 ret = MonoIO.CreatePipe (out out_rd_tmp,
1015 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, out_rd_tmp,
1016 Process.GetCurrentProcess ().Handle, out out_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1017 MonoIO.Close (out_rd_tmp, out error);
1021 ret = MonoIO.CreatePipe (out out_rd,
1025 process.stdout_rd = out_rd;
1027 if (startInfo.RedirectStandardInput == true) {
1028 MonoIO.Close (stdin_rd, out error);
1029 MonoIO.Close (stdin_wr, out error);
1032 throw new IOException ("Error creating standard output pipe");
1035 process.stdout_rd = (IntPtr)0;
1036 stdout_wr = MonoIO.ConsoleOutput;
1039 if (startInfo.RedirectStandardError == true) {
1040 IntPtr err_rd = IntPtr.Zero;
1043 int DUPLICATE_SAME_ACCESS = 0x00000002;
1045 ret = MonoIO.CreatePipe (out err_rd_tmp,
1048 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, err_rd_tmp,
1049 Process.GetCurrentProcess ().Handle, out err_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1050 MonoIO.Close (err_rd_tmp, out error);
1054 ret = MonoIO.CreatePipe (out err_rd,
1058 process.stderr_rd = err_rd;
1060 if (startInfo.RedirectStandardInput == true) {
1061 MonoIO.Close (stdin_rd, out error);
1062 MonoIO.Close (stdin_wr, out error);
1064 if (startInfo.RedirectStandardOutput == true) {
1065 MonoIO.Close (process.stdout_rd, out error);
1066 MonoIO.Close (stdout_wr, out error);
1069 throw new IOException ("Error creating standard error pipe");
1072 process.stderr_rd = (IntPtr)0;
1073 stderr_wr = MonoIO.ConsoleError;
1076 FillUserInfo (startInfo, ref proc_info);
1078 ret = CreateProcess_internal (startInfo,
1079 stdin_rd, stdout_wr, stderr_wr,
1082 if (proc_info.Password != IntPtr.Zero)
1083 Marshal.ZeroFreeBSTR (proc_info.Password);
1084 proc_info.Password = IntPtr.Zero;
1087 if (startInfo.RedirectStandardInput == true) {
1088 MonoIO.Close (stdin_rd, out error);
1089 MonoIO.Close (stdin_wr, out error);
1092 if (startInfo.RedirectStandardOutput == true) {
1093 MonoIO.Close (process.stdout_rd, out error);
1094 MonoIO.Close (stdout_wr, out error);
1097 if (startInfo.RedirectStandardError == true) {
1098 MonoIO.Close (process.stderr_rd, out error);
1099 MonoIO.Close (stderr_wr, out error);
1102 throw new Win32Exception (-proc_info.pid,
1103 "ApplicationName='" + startInfo.FileName +
1104 "', CommandLine='" + startInfo.Arguments +
1105 "', CurrentDirectory='" + startInfo.WorkingDirectory +
1106 "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
1109 process.process_handle = proc_info.process_handle;
1110 process.pid = proc_info.pid;
1112 if (startInfo.RedirectStandardInput == true) {
1113 MonoIO.Close (stdin_rd, out error);
1114 process.input_stream = new StreamWriter (new MonoSyncFileStream (stdin_wr, FileAccess.Write, true, 8192), Console.Out.Encoding);
1115 process.input_stream.AutoFlush = true;
1118 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1119 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1121 if (startInfo.RedirectStandardOutput == true) {
1122 MonoIO.Close (stdout_wr, out error);
1123 process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding, true, 8192);
1126 if (startInfo.RedirectStandardError == true) {
1127 MonoIO.Close (stderr_wr, out error);
1128 process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding, true, 8192);
1131 process.StartExitCallbackIfNeeded ();
1136 // Note that ProcInfo.Password must be freed.
1137 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1139 if (startInfo.UserName != null) {
1140 proc_info.UserName = startInfo.UserName;
1141 proc_info.Domain = startInfo.Domain;
1142 if (startInfo.Password != null)
1143 proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1145 proc_info.Password = IntPtr.Zero;
1146 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1150 private static bool Start_common (ProcessStartInfo startInfo,
1153 if (startInfo.FileName == null || startInfo.FileName.Length == 0)
1154 throw new InvalidOperationException("File name has not been set");
1156 if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1157 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1158 if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1159 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1161 if (startInfo.UseShellExecute) {
1162 if (!String.IsNullOrEmpty (startInfo.UserName))
1163 throw new InvalidOperationException ("UseShellExecute must be false if an explicit UserName is specified when starting a process");
1164 return (Start_shell (startInfo, process));
1166 return (Start_noshell (startInfo, process));
1170 public bool Start ()
1172 if (process_handle != IntPtr.Zero) {
1173 Process_free_internal (process_handle);
1174 process_handle = IntPtr.Zero;
1176 return Start_common(start_info, this);
1179 public static Process Start (ProcessStartInfo startInfo)
1181 if (startInfo == null)
1182 throw new ArgumentNullException ("startInfo");
1184 Process process = new Process();
1185 process.StartInfo = startInfo;
1186 if (Start_common(startInfo, process) && process.process_handle != IntPtr.Zero)
1191 public static Process Start (string fileName)
1193 return Start (new ProcessStartInfo (fileName));
1196 public static Process Start(string fileName, string arguments)
1198 return Start (new ProcessStartInfo (fileName, arguments));
1201 public static Process Start(string fileName, string username, SecureString password, string domain) {
1202 return Start(fileName, null, username, password, domain);
1205 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1206 ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1207 psi.UserName = username;
1208 psi.Password = password;
1209 psi.Domain = domain;
1210 psi.UseShellExecute = false;
1214 public override string ToString()
1216 return(base.ToString() + " (" + this.ProcessName + ")");
1219 /* Waits up to ms milliseconds for process 'handle' to
1220 * exit. ms can be <0 to mean wait forever.
1222 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1223 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1225 public void WaitForExit ()
1230 public bool WaitForExit(int milliseconds) {
1231 int ms = milliseconds;
1232 if (ms == int.MaxValue)
1235 if (process_handle == IntPtr.Zero)
1236 throw new InvalidOperationException ("No process is associated with this object.");
1239 DateTime start = DateTime.UtcNow;
1240 if (async_output != null && !async_output.IsCompleted) {
1241 if (false == async_output.WaitHandle.WaitOne (ms, false))
1242 return false; // Timed out
1245 DateTime now = DateTime.UtcNow;
1246 ms -= (int) (now - start).TotalMilliseconds;
1253 if (async_error != null && !async_error.IsCompleted) {
1254 if (false == async_error.WaitHandle.WaitOne (ms, false))
1255 return false; // Timed out
1258 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1263 return WaitForExit_internal (process_handle, ms);
1266 /* Waits up to ms milliseconds for process 'handle' to
1267 * wait for input. ms can be <0 to mean wait forever.
1269 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1270 private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
1272 // The internal call is only implemented properly on Windows.
1274 public bool WaitForInputIdle() {
1275 return WaitForInputIdle (-1);
1278 // The internal call is only implemented properly on Windows.
1280 public bool WaitForInputIdle(int milliseconds) {
1281 return WaitForInputIdle_internal (process_handle, milliseconds);
1284 private static bool IsLocalMachine (string machineName)
1286 if (machineName == "." || machineName.Length == 0)
1289 return (string.Compare (machineName, Environment.MachineName, true) == 0);
1293 [MonitoringDescription ("Raised when it receives output data")]
1294 public event DataReceivedEventHandler OutputDataReceived;
1296 [MonitoringDescription ("Raised when it receives error data")]
1297 public event DataReceivedEventHandler ErrorDataReceived;
1299 void OnOutputDataReceived (string str)
1301 if (OutputDataReceived != null)
1302 OutputDataReceived (this, new DataReceivedEventArgs (str));
1305 void OnErrorDataReceived (string str)
1307 if (ErrorDataReceived != null)
1308 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1316 AsyncOutput = 1 << 2,
1320 [StructLayout (LayoutKind.Sequential)]
1321 sealed class ProcessAsyncReader
1324 The following fields match those of SocketAsyncResult.
1325 This is so that changes needed in the runtime to handle
1326 asynchronous reads are trivial
1327 Keep this in sync with SocketAsyncResult in
1328 ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
1329 in metadata/socket-io.h.
1331 /* DON'T shuffle fields around. DON'T remove fields */
1333 public IntPtr handle;
1334 public object state;
1335 public AsyncCallback callback;
1336 public ManualResetEvent wait_handle;
1338 public Exception delayedException;
1340 public object EndPoint;
1341 byte [] buffer = new byte [4196];
1344 public int SockFlags;
1346 public object AcceptSocket;
1347 public object[] Addresses;
1349 public object Buffers; // Reserve this slot in older profiles
1350 public bool ReuseSocket; // Disconnect
1351 public object acc_socket;
1353 public bool completed_sync;
1355 bool err_out; // true -> stdout, false -> stderr
1357 public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1359 public int EndCalled;
1361 // These fields are not in SocketAsyncResult
1364 StringBuilder sb = new StringBuilder ();
1365 public AsyncReadHandler ReadHandler;
1367 public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1369 this.process = process;
1370 this.handle = handle;
1371 stream = new FileStream (handle, FileAccess.Read, false);
1372 this.ReadHandler = new AsyncReadHandler (AddInput);
1373 this.err_out = err_out;
1376 public void AddInput ()
1379 int nread = stream.Read (buffer, 0, buffer.Length);
1382 if (wait_handle != null)
1389 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1391 // Just in case the encoding fails...
1392 for (int i = 0; i < nread; i++) {
1393 sb.Append ((char) buffer [i]);
1398 ReadHandler.BeginInvoke (null, this);
1406 process.OnOutputDataReceived (null);
1408 process.OnErrorDataReceived (null);
1412 void Flush (bool last)
1414 if (sb.Length == 0 ||
1415 (err_out && process.output_canceled) ||
1416 (!err_out && process.error_canceled))
1419 string total = sb.ToString ();
1421 string [] strs = total.Split ('\n');
1422 int len = strs.Length;
1426 for (int i = 0; i < len - 1; i++) {
1428 process.OnOutputDataReceived (strs [i]);
1430 process.OnErrorDataReceived (strs [i]);
1433 string end = strs [len - 1];
1434 if (last || (len == 1 && end == "")) {
1436 process.OnOutputDataReceived (end);
1438 process.OnErrorDataReceived (end);
1445 public bool IsCompleted {
1446 get { return completed; }
1449 public WaitHandle WaitHandle {
1452 if (wait_handle == null)
1453 wait_handle = new ManualResetEvent (completed);
1459 public void Close () {
1464 AsyncModes async_mode;
1465 bool output_canceled;
1466 bool error_canceled;
1467 ProcessAsyncReader async_output;
1468 ProcessAsyncReader async_error;
1469 delegate void AsyncReadHandler ();
1471 [ComVisibleAttribute(false)]
1472 public void BeginOutputReadLine ()
1474 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1475 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1477 if ((async_mode & AsyncModes.SyncOutput) != 0)
1478 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1480 async_mode |= AsyncModes.AsyncOutput;
1481 output_canceled = false;
1482 if (async_output == null) {
1483 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1484 async_output.ReadHandler.BeginInvoke (null, async_output);
1488 [ComVisibleAttribute(false)]
1489 public void CancelOutputRead ()
1491 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1492 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1494 if ((async_mode & AsyncModes.SyncOutput) != 0)
1495 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1497 if (async_output == null)
1498 throw new InvalidOperationException ("No async operation in progress.");
1500 output_canceled = true;
1503 [ComVisibleAttribute(false)]
1504 public void BeginErrorReadLine ()
1506 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1507 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1509 if ((async_mode & AsyncModes.SyncError) != 0)
1510 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1512 async_mode |= AsyncModes.AsyncError;
1513 error_canceled = false;
1514 if (async_error == null) {
1515 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1516 async_error.ReadHandler.BeginInvoke (null, async_error);
1520 [ComVisibleAttribute(false)]
1521 public void CancelErrorRead ()
1523 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1524 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1526 if ((async_mode & AsyncModes.SyncOutput) != 0)
1527 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1529 if (async_error == null)
1530 throw new InvalidOperationException ("No async operation in progress.");
1532 error_canceled = true;
1535 [Category ("Behavior")]
1536 [MonitoringDescription ("Raised when this process exits.")]
1537 public event EventHandler Exited {
1539 if (process_handle != IntPtr.Zero && HasExited) {
1540 value.BeginInvoke (null, null, null, null);
1542 exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1543 if (exited_event != null)
1544 StartExitCallbackIfNeeded ();
1548 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1552 // Closes the system process handle
1553 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1554 private extern void Process_free_internal(IntPtr handle);
1556 private bool disposed = false;
1558 protected override void Dispose(bool disposing) {
1559 // Check to see if Dispose has already been called.
1560 if(this.disposed == false) {
1562 // If this is a call to Dispose,
1563 // dispose all managed resources.
1567 /* These have open FileStreams on the pipes we are about to close */
1568 if (async_output != null)
1569 async_output.Close ();
1570 if (async_error != null)
1571 async_error.Close ();
1573 if (input_stream != null) {
1574 input_stream.Close();
1575 input_stream = null;
1578 if (output_stream != null) {
1579 output_stream.Close();
1580 output_stream = null;
1583 if (error_stream != null) {
1584 error_stream.Close();
1585 error_stream = null;
1590 // Release unmanaged resources
1593 if(process_handle!=IntPtr.Zero) {
1594 Process_free_internal(process_handle);
1595 process_handle=IntPtr.Zero;
1599 base.Dispose (disposing);
1607 static void CBOnExit (object state, bool unused)
1609 Process p = (Process) state;
1610 p.already_waiting = false;
1614 protected void OnExited()
1616 if (exited_event == null)
1619 if (synchronizingObject == null) {
1620 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1622 d (this, EventArgs.Empty);
1628 object [] args = new object [] {this, EventArgs.Empty};
1629 synchronizingObject.BeginInvoke (exited_event, args);
1632 static bool IsWindows
1636 PlatformID platform = Environment.OSVersion.Platform;
1637 if (platform == PlatformID.Win32S ||
1638 platform == PlatformID.Win32Windows ||
1639 platform == PlatformID.Win32NT ||
1640 platform == PlatformID.WinCE) {
1647 class ProcessWaitHandle : WaitHandle
1649 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1650 private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1652 public ProcessWaitHandle (IntPtr handle)
1654 // Need to keep a reference to this handle,
1655 // in case the Process object is collected
1656 Handle = ProcessHandle_duplicate (handle);
1658 // When the wait handle is disposed, the duplicated handle will be
1659 // closed, so no need to override dispose (bug #464628).