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 {
349 [Obsolete ("Use PagedMemorySize64")]
350 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
351 [MonitoringDescription ("The number of bytes that are paged.")]
352 public int PagedMemorySize {
354 return(int)PagedMemorySize64;
358 [Obsolete ("Use PagedSystemMemorySize64")]
359 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
360 [MonitoringDescription ("The amount of paged system memory in bytes.")]
361 public int PagedSystemMemorySize {
363 return(int)PagedMemorySize64;
368 [Obsolete ("Use PeakPagedMemorySize64")]
369 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
370 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
371 public int PeakPagedMemorySize {
377 [Obsolete ("Use PeakVirtualMemorySize64")]
378 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
379 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
380 public int PeakVirtualMemorySize {
383 return (int)GetProcessData (pid, 8, out error);
387 [Obsolete ("Use PeakWorkingSet64")]
388 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
389 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
390 public int PeakWorkingSet {
393 return (int)GetProcessData (pid, 5, out error);
398 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
399 [MonitoringDescription ("The number of bytes that are not pageable.")]
401 public long NonpagedSystemMemorySize64 {
407 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
408 [MonitoringDescription ("The number of bytes that are paged.")]
410 public long PagedMemorySize64 {
413 return GetProcessData (pid, 12, out error);
417 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
418 [MonitoringDescription ("The amount of paged system memory in bytes.")]
420 public long PagedSystemMemorySize64 {
422 return PagedMemorySize64;
427 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
428 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
430 public long PeakPagedMemorySize64 {
436 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
437 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
439 public long PeakVirtualMemorySize64 {
442 return GetProcessData (pid, 8, out error);
446 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
447 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
449 public long PeakWorkingSet64 {
452 return GetProcessData (pid, 5, out error);
457 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
458 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
459 public bool PriorityBoostEnabled {
467 [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
468 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
469 [MonitoringDescription ("The relative process priority.")]
470 public ProcessPriorityClass PriorityClass {
472 if (process_handle == IntPtr.Zero)
473 throw new InvalidOperationException ("Process has not been started.");
476 int prio = GetPriorityClass (process_handle, out error);
478 throw new Win32Exception (error);
479 return (ProcessPriorityClass) prio;
482 if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
483 throw new InvalidEnumArgumentException (
484 "value", (int) value,
485 typeof (ProcessPriorityClass));
487 if (process_handle == IntPtr.Zero)
488 throw new InvalidOperationException ("Process has not been started.");
491 if (!SetPriorityClass (process_handle, (int) value, out error)) {
493 throw new Win32Exception (error);
498 void CheckExited () {
500 throw new InvalidOperationException (String.Format ("Cannot process request because the process ({0}) has exited.", Id));
503 [MethodImplAttribute(MethodImplOptions.InternalCall)]
504 static extern int GetPriorityClass (IntPtr handle, out int error);
506 [MethodImplAttribute(MethodImplOptions.InternalCall)]
507 static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);
509 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
510 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
511 [Obsolete ("Use PrivateMemorySize64")]
512 public int PrivateMemorySize {
515 return (int)GetProcessData (pid, 6, out error);
519 [MonoNotSupported ("")]
520 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
521 [MonitoringDescription ("The session ID for this process.")]
522 public int SessionId {
523 get { throw new NotImplementedException (); }
526 /* the meaning of type is as follows: 0: user, 1: system, 2: total */
527 [MethodImplAttribute(MethodImplOptions.InternalCall)]
528 private extern static long Times (IntPtr handle, int type);
530 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
531 [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
532 public TimeSpan PrivilegedProcessorTime {
534 return new TimeSpan (Times (process_handle, 1));
538 [MethodImplAttribute(MethodImplOptions.InternalCall)]
539 private extern static string ProcessName_internal(IntPtr handle);
541 private string process_name=null;
543 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
544 [MonitoringDescription ("The name of this process.")]
545 public string ProcessName {
547 if(process_name==null) {
549 if (process_handle == IntPtr.Zero)
550 throw new InvalidOperationException ("No process is associated with this object.");
552 process_name=ProcessName_internal(process_handle);
553 /* If process_name is _still_
554 * null, assume the process
557 if (process_name == null)
558 throw new InvalidOperationException ("Process has exited, so the requested information is not available.");
560 /* Strip the suffix (if it
561 * exists) simplistically
562 * instead of removing any
563 * trailing \.???, so we dont
564 * get stupid results on sane
567 if(process_name.EndsWith(".exe") ||
568 process_name.EndsWith(".bat") ||
569 process_name.EndsWith(".com")) {
570 process_name=process_name.Substring(0, process_name.Length-4);
573 return(process_name);
578 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
579 [MonitoringDescription ("Allowed processor that can be used by this process.")]
580 public IntPtr ProcessorAffinity {
589 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
590 [MonitoringDescription ("Is this process responsive.")]
591 public bool Responding {
597 private StreamReader error_stream=null;
599 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
600 [MonitoringDescription ("The standard error stream of this process.")]
601 public StreamReader StandardError {
603 if (error_stream == null)
604 throw new InvalidOperationException("Standard error has not been redirected");
606 if ((async_mode & AsyncModes.AsyncError) != 0)
607 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
609 async_mode |= AsyncModes.SyncError;
611 return(error_stream);
615 private StreamWriter input_stream=null;
617 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
618 [MonitoringDescription ("The standard input stream of this process.")]
619 public StreamWriter StandardInput {
621 if (input_stream == null)
622 throw new InvalidOperationException("Standard input has not been redirected");
624 return(input_stream);
628 private StreamReader output_stream=null;
630 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
631 [MonitoringDescription ("The standard output stream of this process.")]
632 public StreamReader StandardOutput {
634 if (output_stream == null)
635 throw new InvalidOperationException("Standard output has not been redirected");
637 if ((async_mode & AsyncModes.AsyncOutput) != 0)
638 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
640 async_mode |= AsyncModes.SyncOutput;
642 return(output_stream);
646 private ProcessStartInfo start_info=null;
648 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
649 [MonitoringDescription ("Information for the start of this process.")]
650 public ProcessStartInfo StartInfo {
652 if (start_info == null)
653 start_info = new ProcessStartInfo();
658 throw new ArgumentNullException("value");
663 /* Returns the process start time in Windows file
664 * times (ticks from DateTime(1/1/1601 00:00 GMT))
666 [MethodImplAttribute(MethodImplOptions.InternalCall)]
667 private extern static long StartTime_internal(IntPtr handle);
669 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
670 [MonitoringDescription ("The time this process started.")]
671 public DateTime StartTime {
673 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
677 [DefaultValue (null), Browsable (false)]
678 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
679 public ISynchronizeInvoke SynchronizingObject {
680 get { return synchronizingObject; }
681 set { synchronizingObject = value; }
685 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
686 [MonitoringDescription ("The number of threads of this process.")]
687 public ProcessThreadCollection Threads {
689 // This'll return a correctly-sized array of empty ProcessThreads for now.
691 return new ProcessThreadCollection(new ProcessThread[GetProcessData (pid, 0, out error)]);
695 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
696 [MonitoringDescription ("The total CPU time spent for this process.")]
697 public TimeSpan TotalProcessorTime {
699 return new TimeSpan (Times (process_handle, 2));
703 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
704 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
705 public TimeSpan UserProcessorTime {
707 return new TimeSpan (Times (process_handle, 0));
711 [Obsolete ("Use VirtualMemorySize64")]
712 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
713 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
714 public int VirtualMemorySize {
717 return (int)GetProcessData (pid, 7, out error);
721 [Obsolete ("Use WorkingSet64")]
722 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
723 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
724 public int WorkingSet {
727 return (int)GetProcessData (pid, 4, out error);
731 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
732 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
734 public long PrivateMemorySize64 {
737 return GetProcessData (pid, 6, out error);
741 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
742 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
744 public long VirtualMemorySize64 {
747 return GetProcessData (pid, 7, out error);
751 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
752 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
754 public long WorkingSet64 {
757 return GetProcessData (pid, 4, out error);
766 [MethodImplAttribute(MethodImplOptions.InternalCall)]
767 extern static bool Kill_internal (IntPtr handle, int signo);
769 /* int kill -> 1 KILL, 2 CloseMainWindow */
770 bool Close (int signo)
772 if (process_handle == IntPtr.Zero)
773 throw new SystemException ("No process to kill.");
775 int exitcode = ExitCode_internal (process_handle);
777 throw new InvalidOperationException ("The process already finished.");
779 return Kill_internal (process_handle, signo);
782 public bool CloseMainWindow ()
788 public static void EnterDebugMode() {
791 [MethodImplAttribute(MethodImplOptions.InternalCall)]
792 private extern static IntPtr GetProcess_internal(int pid);
794 [MethodImplAttribute(MethodImplOptions.InternalCall)]
795 private extern static int GetPid_internal();
797 public static Process GetCurrentProcess()
799 int pid = GetPid_internal();
800 IntPtr proc = GetProcess_internal(pid);
802 if (proc == IntPtr.Zero)
803 throw new SystemException("Can't find current process");
805 return (new Process (proc, pid));
808 public static Process GetProcessById(int processId)
810 IntPtr proc = GetProcess_internal(processId);
812 if (proc == IntPtr.Zero)
813 throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
815 return (new Process (proc, processId));
818 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
819 public static Process GetProcessById(int processId, string machineName) {
820 if (machineName == null)
821 throw new ArgumentNullException ("machineName");
823 if (!IsLocalMachine (machineName))
824 throw new NotImplementedException ();
826 return GetProcessById (processId);
829 [MethodImplAttribute(MethodImplOptions.InternalCall)]
830 private extern static int[] GetProcesses_internal();
832 public static Process[] GetProcesses ()
834 int [] pids = GetProcesses_internal ();
836 return new Process [0];
838 var proclist = new List<Process> (pids.Length);
839 for (int i = 0; i < pids.Length; i++) {
841 proclist.Add (GetProcessById (pids [i]));
842 } catch (SystemException) {
843 /* The process might exit
845 * GetProcesses_internal and
851 return proclist.ToArray ();
854 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
855 public static Process[] GetProcesses(string machineName) {
856 if (machineName == null)
857 throw new ArgumentNullException ("machineName");
859 if (!IsLocalMachine (machineName))
860 throw new NotImplementedException ();
862 return GetProcesses ();
865 public static Process[] GetProcessesByName(string processName)
867 int [] pids = GetProcesses_internal ();
869 return new Process [0];
871 var proclist = new List<Process> (pids.Length);
872 for (int i = 0; i < pids.Length; i++) {
874 Process p = GetProcessById (pids [i]);
875 if (String.Compare (processName, p.ProcessName, true) == 0)
877 } catch (SystemException) {
878 /* The process might exit
880 * GetProcesses_internal and
886 return proclist.ToArray ();
890 public static Process[] GetProcessesByName(string processName, string machineName) {
891 throw new NotImplementedException();
900 public static void LeaveDebugMode() {
903 public void Refresh ()
905 // FIXME: should refresh any cached data we might have about
906 // the process (currently we have none).
909 [MethodImplAttribute(MethodImplOptions.InternalCall)]
910 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
911 ref ProcInfo proc_info);
913 [MethodImplAttribute(MethodImplOptions.InternalCall)]
914 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
918 ref ProcInfo proc_info);
920 private static bool Start_shell (ProcessStartInfo startInfo, Process process)
922 ProcInfo proc_info=new ProcInfo();
925 if (startInfo.RedirectStandardInput ||
926 startInfo.RedirectStandardOutput ||
927 startInfo.RedirectStandardError) {
928 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
931 if (startInfo.HaveEnvVars)
932 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
934 FillUserInfo (startInfo, ref proc_info);
936 ret = ShellExecuteEx_internal (startInfo,
939 if (proc_info.Password != IntPtr.Zero)
940 Marshal.ZeroFreeBSTR (proc_info.Password);
941 proc_info.Password = IntPtr.Zero;
944 throw new Win32Exception (-proc_info.pid);
947 process.process_handle = proc_info.process_handle;
948 process.pid = proc_info.pid;
949 process.StartExitCallbackIfNeeded ();
953 private static bool Start_noshell (ProcessStartInfo startInfo,
956 ProcInfo proc_info=new ProcInfo();
957 IntPtr stdin_rd = IntPtr.Zero, stdin_wr = IntPtr.Zero;
963 if (startInfo.HaveEnvVars) {
964 string [] strs = new string [startInfo.EnvironmentVariables.Count];
965 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
966 proc_info.envKeys = strs;
968 strs = new string [startInfo.EnvironmentVariables.Count];
969 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
970 proc_info.envValues = strs;
973 if (startInfo.RedirectStandardInput == true) {
975 int DUPLICATE_SAME_ACCESS = 0x00000002;
978 ret = MonoIO.CreatePipe (out stdin_rd,
981 ret = MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, stdin_wr_tmp,
982 Process.GetCurrentProcess ().Handle, out stdin_wr, 0, 0, DUPLICATE_SAME_ACCESS);
983 MonoIO.Close (stdin_wr_tmp, out error);
988 ret = MonoIO.CreatePipe (out stdin_rd,
992 throw new IOException ("Error creating standard input pipe");
995 stdin_rd = MonoIO.ConsoleInput;
996 /* This is required to stop the
997 * &$*£ing stupid compiler moaning
998 * that stdin_wr is unassigned, below.
1000 stdin_wr = (IntPtr)0;
1003 if (startInfo.RedirectStandardOutput == true) {
1004 IntPtr out_rd = IntPtr.Zero;
1007 int DUPLICATE_SAME_ACCESS = 0x00000002;
1009 ret = MonoIO.CreatePipe (out out_rd_tmp,
1012 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, out_rd_tmp,
1013 Process.GetCurrentProcess ().Handle, out out_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1014 MonoIO.Close (out_rd_tmp, out error);
1018 ret = MonoIO.CreatePipe (out out_rd,
1022 process.stdout_rd = out_rd;
1024 if (startInfo.RedirectStandardInput == true) {
1025 MonoIO.Close (stdin_rd, out error);
1026 MonoIO.Close (stdin_wr, out error);
1029 throw new IOException ("Error creating standard output pipe");
1032 process.stdout_rd = (IntPtr)0;
1033 stdout_wr = MonoIO.ConsoleOutput;
1036 if (startInfo.RedirectStandardError == true) {
1037 IntPtr err_rd = IntPtr.Zero;
1040 int DUPLICATE_SAME_ACCESS = 0x00000002;
1042 ret = MonoIO.CreatePipe (out err_rd_tmp,
1045 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, err_rd_tmp,
1046 Process.GetCurrentProcess ().Handle, out err_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1047 MonoIO.Close (err_rd_tmp, out error);
1051 ret = MonoIO.CreatePipe (out err_rd,
1055 process.stderr_rd = err_rd;
1057 if (startInfo.RedirectStandardInput == true) {
1058 MonoIO.Close (stdin_rd, out error);
1059 MonoIO.Close (stdin_wr, out error);
1061 if (startInfo.RedirectStandardOutput == true) {
1062 MonoIO.Close (process.stdout_rd, out error);
1063 MonoIO.Close (stdout_wr, out error);
1066 throw new IOException ("Error creating standard error pipe");
1069 process.stderr_rd = (IntPtr)0;
1070 stderr_wr = MonoIO.ConsoleError;
1073 FillUserInfo (startInfo, ref proc_info);
1075 ret = CreateProcess_internal (startInfo,
1076 stdin_rd, stdout_wr, stderr_wr,
1079 if (proc_info.Password != IntPtr.Zero)
1080 Marshal.ZeroFreeBSTR (proc_info.Password);
1081 proc_info.Password = IntPtr.Zero;
1084 if (startInfo.RedirectStandardInput == true) {
1085 MonoIO.Close (stdin_rd, out error);
1086 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 if (startInfo.RedirectStandardError == true) {
1095 MonoIO.Close (process.stderr_rd, out error);
1096 MonoIO.Close (stderr_wr, out error);
1099 throw new Win32Exception (-proc_info.pid,
1100 "ApplicationName='" + startInfo.FileName +
1101 "', CommandLine='" + startInfo.Arguments +
1102 "', CurrentDirectory='" + startInfo.WorkingDirectory +
1103 "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
1106 process.process_handle = proc_info.process_handle;
1107 process.pid = proc_info.pid;
1109 if (startInfo.RedirectStandardInput == true) {
1110 MonoIO.Close (stdin_rd, out error);
1111 process.input_stream = new StreamWriter (new MonoSyncFileStream (stdin_wr, FileAccess.Write, true, 8192), Console.Out.Encoding);
1112 process.input_stream.AutoFlush = true;
1115 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1116 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1118 if (startInfo.RedirectStandardOutput == true) {
1119 MonoIO.Close (stdout_wr, out error);
1120 process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding, true, 8192);
1123 if (startInfo.RedirectStandardError == true) {
1124 MonoIO.Close (stderr_wr, out error);
1125 process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding, true, 8192);
1128 process.StartExitCallbackIfNeeded ();
1133 // Note that ProcInfo.Password must be freed.
1134 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1136 if (startInfo.UserName.Length != 0) {
1137 proc_info.UserName = startInfo.UserName;
1138 proc_info.Domain = startInfo.Domain;
1139 if (startInfo.Password != null)
1140 proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1142 proc_info.Password = IntPtr.Zero;
1143 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1147 private static bool Start_common (ProcessStartInfo startInfo,
1150 if (startInfo.FileName.Length == 0)
1151 throw new InvalidOperationException("File name has not been set");
1153 if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1154 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1155 if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1156 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1158 if (startInfo.UseShellExecute) {
1159 if (startInfo.UserName.Length != 0)
1160 throw new InvalidOperationException ("UseShellExecute must be false if an explicit UserName is specified when starting a process");
1161 return (Start_shell (startInfo, process));
1163 return (Start_noshell (startInfo, process));
1167 public bool Start ()
1169 if (process_handle != IntPtr.Zero) {
1170 Process_free_internal (process_handle);
1171 process_handle = IntPtr.Zero;
1173 return Start_common(start_info, this);
1176 public static Process Start (ProcessStartInfo startInfo)
1178 if (startInfo == null)
1179 throw new ArgumentNullException ("startInfo");
1181 Process process = new Process();
1182 process.StartInfo = startInfo;
1183 if (Start_common(startInfo, process) && process.process_handle != IntPtr.Zero)
1188 public static Process Start (string fileName)
1190 return Start (new ProcessStartInfo (fileName));
1193 public static Process Start(string fileName, string arguments)
1195 return Start (new ProcessStartInfo (fileName, arguments));
1198 public static Process Start(string fileName, string username, SecureString password, string domain) {
1199 return Start(fileName, null, username, password, domain);
1202 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1203 ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1204 psi.UserName = username;
1205 psi.Password = password;
1206 psi.Domain = domain;
1207 psi.UseShellExecute = false;
1211 public override string ToString()
1213 return(base.ToString() + " (" + this.ProcessName + ")");
1216 /* Waits up to ms milliseconds for process 'handle' to
1217 * exit. ms can be <0 to mean wait forever.
1219 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1220 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1222 public void WaitForExit ()
1227 public bool WaitForExit(int milliseconds) {
1228 int ms = milliseconds;
1229 if (ms == int.MaxValue)
1232 if (process_handle == IntPtr.Zero)
1233 throw new InvalidOperationException ("No process is associated with this object.");
1236 DateTime start = DateTime.UtcNow;
1237 if (async_output != null && !async_output.IsCompleted) {
1238 if (false == async_output.WaitHandle.WaitOne (ms, false))
1239 return false; // Timed out
1242 DateTime now = DateTime.UtcNow;
1243 ms -= (int) (now - start).TotalMilliseconds;
1250 if (async_error != null && !async_error.IsCompleted) {
1251 if (false == async_error.WaitHandle.WaitOne (ms, false))
1252 return false; // Timed out
1255 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1260 return WaitForExit_internal (process_handle, ms);
1263 /* Waits up to ms milliseconds for process 'handle' to
1264 * wait for input. ms can be <0 to mean wait forever.
1266 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1267 private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
1269 // The internal call is only implemented properly on Windows.
1271 public bool WaitForInputIdle() {
1272 return WaitForInputIdle (-1);
1275 // The internal call is only implemented properly on Windows.
1277 public bool WaitForInputIdle(int milliseconds) {
1278 return WaitForInputIdle_internal (process_handle, milliseconds);
1281 private static bool IsLocalMachine (string machineName)
1283 if (machineName == "." || machineName.Length == 0)
1286 return (string.Compare (machineName, Environment.MachineName, true) == 0);
1290 [MonitoringDescription ("Raised when it receives output data")]
1291 public event DataReceivedEventHandler OutputDataReceived;
1293 [MonitoringDescription ("Raised when it receives error data")]
1294 public event DataReceivedEventHandler ErrorDataReceived;
1296 void OnOutputDataReceived (string str)
1298 if (OutputDataReceived != null)
1299 OutputDataReceived (this, new DataReceivedEventArgs (str));
1302 void OnErrorDataReceived (string str)
1304 if (ErrorDataReceived != null)
1305 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1313 AsyncOutput = 1 << 2,
1317 [StructLayout (LayoutKind.Sequential)]
1318 sealed class ProcessAsyncReader
1321 The following fields match those of SocketAsyncResult.
1322 This is so that changes needed in the runtime to handle
1323 asynchronous reads are trivial
1324 Keep this in sync with SocketAsyncResult in
1325 ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
1326 in metadata/socket-io.h.
1328 /* DON'T shuffle fields around. DON'T remove fields */
1330 public IntPtr handle;
1331 public object state;
1332 public AsyncCallback callback;
1333 public ManualResetEvent wait_handle;
1335 public Exception delayedException;
1337 public object EndPoint;
1338 byte [] buffer = new byte [4196];
1341 public int SockFlags;
1343 public object AcceptSocket;
1344 public object[] Addresses;
1346 public object Buffers; // Reserve this slot in older profiles
1347 public bool ReuseSocket; // Disconnect
1348 public object acc_socket;
1350 public bool completed_sync;
1352 bool err_out; // true -> stdout, false -> stderr
1354 public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1356 public int EndCalled;
1358 // These fields are not in SocketAsyncResult
1361 StringBuilder sb = new StringBuilder ();
1362 public AsyncReadHandler ReadHandler;
1364 public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1366 this.process = process;
1367 this.handle = handle;
1368 stream = new FileStream (handle, FileAccess.Read, false);
1369 this.ReadHandler = new AsyncReadHandler (AddInput);
1370 this.err_out = err_out;
1373 public void AddInput ()
1376 int nread = stream.Read (buffer, 0, buffer.Length);
1379 if (wait_handle != null)
1386 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1388 // Just in case the encoding fails...
1389 for (int i = 0; i < nread; i++) {
1390 sb.Append ((char) buffer [i]);
1395 ReadHandler.BeginInvoke (null, this);
1403 process.OnOutputDataReceived (null);
1405 process.OnErrorDataReceived (null);
1409 void Flush (bool last)
1411 if (sb.Length == 0 ||
1412 (err_out && process.output_canceled) ||
1413 (!err_out && process.error_canceled))
1416 string total = sb.ToString ();
1418 string [] strs = total.Split ('\n');
1419 int len = strs.Length;
1423 for (int i = 0; i < len - 1; i++) {
1425 process.OnOutputDataReceived (strs [i]);
1427 process.OnErrorDataReceived (strs [i]);
1430 string end = strs [len - 1];
1431 if (last || (len == 1 && end == "")) {
1433 process.OnOutputDataReceived (end);
1435 process.OnErrorDataReceived (end);
1442 public bool IsCompleted {
1443 get { return completed; }
1446 public WaitHandle WaitHandle {
1449 if (wait_handle == null)
1450 wait_handle = new ManualResetEvent (completed);
1456 public void Close () {
1461 AsyncModes async_mode;
1462 bool output_canceled;
1463 bool error_canceled;
1464 ProcessAsyncReader async_output;
1465 ProcessAsyncReader async_error;
1466 delegate void AsyncReadHandler ();
1468 [ComVisibleAttribute(false)]
1469 public void BeginOutputReadLine ()
1471 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1472 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1474 if ((async_mode & AsyncModes.SyncOutput) != 0)
1475 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1477 async_mode |= AsyncModes.AsyncOutput;
1478 output_canceled = false;
1479 if (async_output == null) {
1480 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1481 async_output.ReadHandler.BeginInvoke (null, async_output);
1485 [ComVisibleAttribute(false)]
1486 public void CancelOutputRead ()
1488 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1489 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1491 if ((async_mode & AsyncModes.SyncOutput) != 0)
1492 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1494 if (async_output == null)
1495 throw new InvalidOperationException ("No async operation in progress.");
1497 output_canceled = true;
1500 [ComVisibleAttribute(false)]
1501 public void BeginErrorReadLine ()
1503 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1504 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1506 if ((async_mode & AsyncModes.SyncError) != 0)
1507 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1509 async_mode |= AsyncModes.AsyncError;
1510 error_canceled = false;
1511 if (async_error == null) {
1512 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1513 async_error.ReadHandler.BeginInvoke (null, async_error);
1517 [ComVisibleAttribute(false)]
1518 public void CancelErrorRead ()
1520 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1521 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1523 if ((async_mode & AsyncModes.SyncOutput) != 0)
1524 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1526 if (async_error == null)
1527 throw new InvalidOperationException ("No async operation in progress.");
1529 error_canceled = true;
1532 [Category ("Behavior")]
1533 [MonitoringDescription ("Raised when this process exits.")]
1534 public event EventHandler Exited {
1536 if (process_handle != IntPtr.Zero && HasExited) {
1537 value.BeginInvoke (null, null, null, null);
1539 exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1540 if (exited_event != null)
1541 StartExitCallbackIfNeeded ();
1545 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1549 // Closes the system process handle
1550 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1551 private extern void Process_free_internal(IntPtr handle);
1553 private bool disposed = false;
1555 protected override void Dispose(bool disposing) {
1556 // Check to see if Dispose has already been called.
1557 if(this.disposed == false) {
1559 // If this is a call to Dispose,
1560 // dispose all managed resources.
1564 /* These have open FileStreams on the pipes we are about to close */
1565 if (async_output != null)
1566 async_output.Close ();
1567 if (async_error != null)
1568 async_error.Close ();
1570 if (input_stream != null) {
1571 input_stream.Close();
1572 input_stream = null;
1575 if (output_stream != null) {
1576 output_stream.Close();
1577 output_stream = null;
1580 if (error_stream != null) {
1581 error_stream.Close();
1582 error_stream = null;
1587 // Release unmanaged resources
1590 if(process_handle!=IntPtr.Zero) {
1591 Process_free_internal(process_handle);
1592 process_handle=IntPtr.Zero;
1596 base.Dispose (disposing);
1604 static void CBOnExit (object state, bool unused)
1606 Process p = (Process) state;
1607 p.already_waiting = false;
1611 protected void OnExited()
1613 if (exited_event == null)
1616 if (synchronizingObject == null) {
1617 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1619 d (this, EventArgs.Empty);
1625 object [] args = new object [] {this, EventArgs.Empty};
1626 synchronizingObject.BeginInvoke (exited_event, args);
1629 static bool IsWindows
1633 PlatformID platform = Environment.OSVersion.Platform;
1634 if (platform == PlatformID.Win32S ||
1635 platform == PlatformID.Win32Windows ||
1636 platform == PlatformID.Win32NT ||
1637 platform == PlatformID.WinCE) {
1644 class ProcessWaitHandle : WaitHandle
1646 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1647 private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1649 public ProcessWaitHandle (IntPtr handle)
1651 // Need to keep a reference to this handle,
1652 // in case the Process object is collected
1653 Handle = ProcessHandle_duplicate (handle);
1655 // When the wait handle is disposed, the duplicated handle will be
1656 // closed, so no need to override dispose (bug #464628).