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.Runtime.Remoting.Messaging;
42 using System.Security.Permissions;
43 using System.Collections.Generic;
44 using System.Security;
45 using System.Threading;
47 namespace System.Diagnostics {
49 [DefaultEvent ("Exited"), DefaultProperty ("StartInfo")]
50 [Designer ("System.Diagnostics.Design.ProcessDesigner, " + Consts.AssemblySystem_Design)]
51 [PermissionSet (SecurityAction.LinkDemand, Unrestricted = true)]
52 [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
53 [MonitoringDescription ("Represents a system process")]
54 public class Process : Component
56 [StructLayout(LayoutKind.Sequential)]
57 private struct ProcInfo
59 public IntPtr process_handle;
60 /* If thread_handle is ever needed for
61 * something, take out the CloseHandle() in
62 * the Start_internal icall in
63 * mono/metadata/process.c
65 public IntPtr thread_handle;
66 public int pid; // Contains -GetLastError () on failure.
68 public string [] envKeys;
69 public string [] envValues;
70 public string UserName;
72 public IntPtr Password;
73 public bool LoadUserProfile;
76 IntPtr process_handle;
78 bool enableRaisingEvents;
79 RegisteredWaitHandle exitWaitHandle;
80 ISynchronizeInvoke synchronizingObject;
81 EventHandler exited_event;
85 object thisLock = new Object ();
87 /* Private constructor called from other methods */
88 private Process(IntPtr handle, int id) {
89 process_handle=handle;
98 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
99 [MonitoringDescription ("Base process priority.")]
100 public int BasePriority {
106 void StartExitCallbackIfNeeded ()
109 bool start = (exitWaitHandle == null && enableRaisingEvents && exited_event != null);
110 if (start && process_handle != IntPtr.Zero) {
111 WaitOrTimerCallback cb = new WaitOrTimerCallback (CBOnExit);
112 ProcessWaitHandle h = new ProcessWaitHandle (process_handle);
113 exitWaitHandle = ThreadPool.RegisterWaitForSingleObject (h, cb, this, -1, true);
118 void UnregisterExitCallback ()
121 if (exitWaitHandle != null) {
122 exitWaitHandle.Unregister (null);
123 exitWaitHandle = null;
128 bool IsExitCallbackPending ()
131 return exitWaitHandle != null;
135 [DefaultValue (false), Browsable (false)]
136 [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
137 public bool EnableRaisingEvents {
139 return enableRaisingEvents;
142 bool prev = enableRaisingEvents;
143 enableRaisingEvents = value;
144 if (enableRaisingEvents && !prev)
145 StartExitCallbackIfNeeded ();
150 [MethodImplAttribute(MethodImplOptions.InternalCall)]
151 private extern static int ExitCode_internal(IntPtr handle);
153 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
154 [MonitoringDescription ("The exit code of the process.")]
155 public int ExitCode {
157 if (process_handle == IntPtr.Zero)
158 throw new InvalidOperationException ("Process has not been started.");
160 int code = ExitCode_internal (process_handle);
162 throw new InvalidOperationException ("The process must exit before " +
163 "getting the requested information.");
169 /* Returns the process start time in Windows file
170 * times (ticks from DateTime(1/1/1601 00:00 GMT))
172 [MethodImplAttribute(MethodImplOptions.InternalCall)]
173 private extern static long ExitTime_internal(IntPtr handle);
175 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
176 [MonitoringDescription ("The exit time of the process.")]
177 public DateTime ExitTime {
179 if (process_handle == IntPtr.Zero)
180 throw new InvalidOperationException ("Process has not been started.");
183 throw new InvalidOperationException ("The process must exit before " +
184 "getting the requested information.");
186 return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
190 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
191 [MonitoringDescription ("Handle for this process.")]
192 public IntPtr Handle {
194 if (process_handle == IntPtr.Zero)
195 throw new InvalidOperationException ("No process is associated with this object.");
196 return(process_handle);
201 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
202 [MonitoringDescription ("Handles for this process.")]
203 public int HandleCount {
209 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
210 [MonitoringDescription ("Determines if the process is still running.")]
211 public bool HasExited {
213 if (process_handle == IntPtr.Zero)
214 throw new InvalidOperationException ("Process has not been started.");
216 int exitcode = ExitCode_internal (process_handle);
227 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
228 [MonitoringDescription ("Process identifier.")]
232 throw new InvalidOperationException ("Process ID has not been set.");
239 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
240 [MonitoringDescription ("The name of the computer running the process.")]
241 public string MachineName {
247 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
248 [MonitoringDescription ("The main module of the process.")]
249 public ProcessModule MainModule {
251 return(this.Modules[0]);
256 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
257 [MonitoringDescription ("The handle of the main window of the process.")]
258 public IntPtr MainWindowHandle {
265 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
266 [MonitoringDescription ("The title of the main window of the process.")]
267 public string MainWindowTitle {
273 [MethodImplAttribute(MethodImplOptions.InternalCall)]
274 private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
275 [MethodImplAttribute(MethodImplOptions.InternalCall)]
276 private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);
278 /* LAMESPEC: why is this an IntPtr not a plain int? */
279 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
280 [MonitoringDescription ("The maximum working set for this process.")]
281 public IntPtr MaxWorkingSet {
284 throw new InvalidOperationException(
285 "The process " + ProcessName +
286 " (ID " + Id + ") has exited");
290 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
292 throw new Win32Exception();
299 throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
302 bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
304 throw new Win32Exception();
309 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
310 [MonitoringDescription ("The minimum working set for this process.")]
311 public IntPtr MinWorkingSet {
314 throw new InvalidOperationException(
315 "The process " + ProcessName +
316 " (ID " + Id + ") has exited");
320 bool ok= GetWorkingSet_internal (process_handle, out min, out max);
322 throw new Win32Exception();
323 return ((IntPtr) min);
327 throw new InvalidOperationException(
328 "The process " + ProcessName +
329 " (ID " + Id + ") has exited");
331 bool ok = SetWorkingSet_internal (process_handle, value.ToInt32(), 0, true);
333 throw new Win32Exception();
337 /* Returns the list of process modules. The main module is
340 [MethodImplAttribute(MethodImplOptions.InternalCall)]
341 private extern ProcessModule[] GetModules_internal(IntPtr handle);
343 private ProcessModuleCollection module_collection;
345 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
346 [MonitoringDescription ("The modules that are loaded as part of this process.")]
347 public ProcessModuleCollection Modules {
349 if (module_collection == null)
350 module_collection = new ProcessModuleCollection(
351 GetModules_internal (process_handle));
352 return(module_collection);
356 /* data type is from the MonoProcessData enum in mono-proclib.h in the runtime */
357 [MethodImplAttribute(MethodImplOptions.InternalCall)]
358 private extern static long GetProcessData (int pid, int data_type, out int error);
361 [Obsolete ("Use NonpagedSystemMemorySize64")]
362 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
363 [MonitoringDescription ("The number of bytes that are not pageable.")]
364 public int NonpagedSystemMemorySize {
370 [Obsolete ("Use PagedMemorySize64")]
371 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
372 [MonitoringDescription ("The number of bytes that are paged.")]
373 public int PagedMemorySize {
375 return(int)PagedMemorySize64;
379 [Obsolete ("Use PagedSystemMemorySize64")]
380 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
381 [MonitoringDescription ("The amount of paged system memory in bytes.")]
382 public int PagedSystemMemorySize {
384 return(int)PagedMemorySize64;
389 [Obsolete ("Use PeakPagedMemorySize64")]
390 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
391 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
392 public int PeakPagedMemorySize {
398 [Obsolete ("Use PeakVirtualMemorySize64")]
399 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
400 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
401 public int PeakVirtualMemorySize {
404 return (int)GetProcessData (pid, 8, out error);
408 [Obsolete ("Use PeakWorkingSet64")]
409 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
410 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
411 public int PeakWorkingSet {
414 return (int)GetProcessData (pid, 5, out error);
419 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
420 [MonitoringDescription ("The number of bytes that are not pageable.")]
422 public long NonpagedSystemMemorySize64 {
428 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
429 [MonitoringDescription ("The number of bytes that are paged.")]
431 public long PagedMemorySize64 {
434 return GetProcessData (pid, 12, out error);
438 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
439 [MonitoringDescription ("The amount of paged system memory in bytes.")]
441 public long PagedSystemMemorySize64 {
443 return PagedMemorySize64;
448 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
449 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
451 public long PeakPagedMemorySize64 {
457 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
458 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
460 public long PeakVirtualMemorySize64 {
463 return GetProcessData (pid, 8, out error);
467 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
468 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
470 public long PeakWorkingSet64 {
473 return GetProcessData (pid, 5, out error);
478 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
479 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
480 public bool PriorityBoostEnabled {
488 [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
489 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
490 [MonitoringDescription ("The relative process priority.")]
491 public ProcessPriorityClass PriorityClass {
493 if (process_handle == IntPtr.Zero)
494 throw new InvalidOperationException ("Process has not been started.");
497 int prio = GetPriorityClass (process_handle, out error);
499 throw new Win32Exception (error);
500 return (ProcessPriorityClass) prio;
503 if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
504 throw new InvalidEnumArgumentException (
505 "value", (int) value,
506 typeof (ProcessPriorityClass));
508 if (process_handle == IntPtr.Zero)
509 throw new InvalidOperationException ("Process has not been started.");
512 if (!SetPriorityClass (process_handle, (int) value, out error)) {
514 throw new Win32Exception (error);
519 void CheckExited () {
521 throw new InvalidOperationException (String.Format ("Cannot process request because the process ({0}) has exited.", Id));
524 [MethodImplAttribute(MethodImplOptions.InternalCall)]
525 static extern int GetPriorityClass (IntPtr handle, out int error);
527 [MethodImplAttribute(MethodImplOptions.InternalCall)]
528 static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);
530 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
531 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
532 [Obsolete ("Use PrivateMemorySize64")]
533 public int PrivateMemorySize {
536 return (int)GetProcessData (pid, 6, out error);
540 [MonoNotSupported ("")]
541 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
542 [MonitoringDescription ("The session ID for this process.")]
543 public int SessionId {
544 get { throw new NotImplementedException (); }
547 /* the meaning of type is as follows: 0: user, 1: system, 2: total */
548 [MethodImplAttribute(MethodImplOptions.InternalCall)]
549 private extern static long Times (IntPtr handle, int type);
551 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
552 [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
553 public TimeSpan PrivilegedProcessorTime {
555 return new TimeSpan (Times (process_handle, 1));
559 [MethodImplAttribute(MethodImplOptions.InternalCall)]
560 private extern static string ProcessName_internal(IntPtr handle);
562 private string process_name=null;
564 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
565 [MonitoringDescription ("The name of this process.")]
566 public string ProcessName {
568 if(process_name==null) {
570 if (process_handle == IntPtr.Zero)
571 throw new InvalidOperationException ("No process is associated with this object.");
573 process_name=ProcessName_internal(process_handle);
574 /* If process_name is _still_
575 * null, assume the process
578 if (process_name == null)
579 throw new InvalidOperationException ("Process has exited, so the requested information is not available.");
581 /* Strip the suffix (if it
582 * exists) simplistically
583 * instead of removing any
584 * trailing \.???, so we dont
585 * get stupid results on sane
588 if(process_name.EndsWith(".exe") ||
589 process_name.EndsWith(".bat") ||
590 process_name.EndsWith(".com")) {
591 process_name=process_name.Substring(0, process_name.Length-4);
594 return(process_name);
599 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
600 [MonitoringDescription ("Allowed processor that can be used by this process.")]
601 public IntPtr ProcessorAffinity {
610 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
611 [MonitoringDescription ("Is this process responsive.")]
612 public bool Responding {
618 private StreamReader error_stream=null;
619 bool error_stream_exposed;
621 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
622 [MonitoringDescription ("The standard error stream of this process.")]
623 public StreamReader StandardError {
625 if (error_stream == null)
626 throw new InvalidOperationException("Standard error has not been redirected");
628 if ((async_mode & AsyncModes.AsyncError) != 0)
629 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
631 async_mode |= AsyncModes.SyncError;
633 error_stream_exposed = true;
634 return(error_stream);
638 private StreamWriter input_stream=null;
639 bool input_stream_exposed;
641 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
642 [MonitoringDescription ("The standard input stream of this process.")]
643 public StreamWriter StandardInput {
645 if (input_stream == null)
646 throw new InvalidOperationException("Standard input has not been redirected");
648 input_stream_exposed = true;
649 return(input_stream);
653 private StreamReader output_stream=null;
654 bool output_stream_exposed;
656 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
657 [MonitoringDescription ("The standard output stream of this process.")]
658 public StreamReader StandardOutput {
660 if (output_stream == null)
661 throw new InvalidOperationException("Standard output has not been redirected");
663 if ((async_mode & AsyncModes.AsyncOutput) != 0)
664 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
666 async_mode |= AsyncModes.SyncOutput;
668 output_stream_exposed = true;
669 return(output_stream);
673 private ProcessStartInfo start_info=null;
675 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
676 [MonitoringDescription ("Information for the start of this process.")]
677 public ProcessStartInfo StartInfo {
679 if (start_info == null)
680 start_info = new ProcessStartInfo();
685 throw new ArgumentNullException("value");
690 /* Returns the process start time in Windows file
691 * times (ticks from DateTime(1/1/1601 00:00 GMT))
693 [MethodImplAttribute(MethodImplOptions.InternalCall)]
694 private extern static long StartTime_internal(IntPtr handle);
696 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
697 [MonitoringDescription ("The time this process started.")]
698 public DateTime StartTime {
700 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
704 [DefaultValue (null), Browsable (false)]
705 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
706 public ISynchronizeInvoke SynchronizingObject {
707 get { return synchronizingObject; }
708 set { synchronizingObject = value; }
712 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
713 [MonitoringDescription ("The number of threads of this process.")]
714 public ProcessThreadCollection Threads {
716 // This'll return a correctly-sized array of empty ProcessThreads for now.
718 return new ProcessThreadCollection(new ProcessThread[GetProcessData (pid, 0, out error)]);
722 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
723 [MonitoringDescription ("The total CPU time spent for this process.")]
724 public TimeSpan TotalProcessorTime {
726 return new TimeSpan (Times (process_handle, 2));
730 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
731 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
732 public TimeSpan UserProcessorTime {
734 return new TimeSpan (Times (process_handle, 0));
738 [Obsolete ("Use VirtualMemorySize64")]
739 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
740 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
741 public int VirtualMemorySize {
744 return (int)GetProcessData (pid, 7, out error);
748 [Obsolete ("Use WorkingSet64")]
749 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
750 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
751 public int WorkingSet {
754 return (int)GetProcessData (pid, 4, out error);
758 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
759 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
761 public long PrivateMemorySize64 {
764 return GetProcessData (pid, 6, out error);
768 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
769 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
771 public long VirtualMemorySize64 {
774 return GetProcessData (pid, 7, out error);
778 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
779 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
781 public long WorkingSet64 {
784 return GetProcessData (pid, 4, out error);
793 [MethodImplAttribute(MethodImplOptions.InternalCall)]
794 extern static bool Kill_internal (IntPtr handle, int signo);
796 /* int kill -> 1 KILL, 2 CloseMainWindow */
797 bool Close (int signo)
799 if (process_handle == IntPtr.Zero)
800 throw new SystemException ("No process to kill.");
802 int exitcode = ExitCode_internal (process_handle);
804 throw new InvalidOperationException ("The process already finished.");
806 return Kill_internal (process_handle, signo);
809 public bool CloseMainWindow ()
815 public static void EnterDebugMode() {
818 [MethodImplAttribute(MethodImplOptions.InternalCall)]
819 private extern static IntPtr GetProcess_internal(int pid);
821 [MethodImplAttribute(MethodImplOptions.InternalCall)]
822 private extern static int GetPid_internal();
824 public static Process GetCurrentProcess()
826 int pid = GetPid_internal();
827 IntPtr proc = GetProcess_internal(pid);
829 if (proc == IntPtr.Zero)
830 throw new SystemException("Can't find current process");
832 return (new Process (proc, pid));
835 public static Process GetProcessById(int processId)
837 IntPtr proc = GetProcess_internal(processId);
839 if (proc == IntPtr.Zero)
840 throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
842 return (new Process (proc, processId));
845 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
846 public static Process GetProcessById(int processId, string machineName) {
847 if (machineName == null)
848 throw new ArgumentNullException ("machineName");
850 if (!IsLocalMachine (machineName))
851 throw new NotImplementedException ();
853 return GetProcessById (processId);
856 [MethodImplAttribute(MethodImplOptions.InternalCall)]
857 private extern static int[] GetProcesses_internal();
859 public static Process[] GetProcesses ()
861 int [] pids = GetProcesses_internal ();
863 return new Process [0];
865 var proclist = new List<Process> (pids.Length);
866 for (int i = 0; i < pids.Length; i++) {
868 proclist.Add (GetProcessById (pids [i]));
869 } catch (SystemException) {
870 /* The process might exit
872 * GetProcesses_internal and
878 return proclist.ToArray ();
881 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
882 public static Process[] GetProcesses(string machineName) {
883 if (machineName == null)
884 throw new ArgumentNullException ("machineName");
886 if (!IsLocalMachine (machineName))
887 throw new NotImplementedException ();
889 return GetProcesses ();
892 public static Process[] GetProcessesByName(string processName)
894 int [] pids = GetProcesses_internal ();
896 return new Process [0];
898 var proclist = new List<Process> (pids.Length);
899 for (int i = 0; i < pids.Length; i++) {
901 Process p = GetProcessById (pids [i]);
902 if (String.Compare (processName, p.ProcessName, true) == 0)
904 } catch (SystemException) {
905 /* The process might exit
907 * GetProcesses_internal and
913 return proclist.ToArray ();
917 public static Process[] GetProcessesByName(string processName, string machineName) {
918 throw new NotImplementedException();
927 public static void LeaveDebugMode() {
930 public void Refresh ()
932 // FIXME: should refresh any cached data we might have about
933 // the process (currently we have none).
936 [MethodImplAttribute(MethodImplOptions.InternalCall)]
937 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
938 ref ProcInfo proc_info);
940 [MethodImplAttribute(MethodImplOptions.InternalCall)]
941 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
945 ref ProcInfo proc_info);
947 private static bool Start_shell (ProcessStartInfo startInfo, Process process)
949 ProcInfo proc_info=new ProcInfo();
952 if (startInfo.RedirectStandardInput ||
953 startInfo.RedirectStandardOutput ||
954 startInfo.RedirectStandardError) {
955 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
958 if (startInfo.HaveEnvVars)
959 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
961 FillUserInfo (startInfo, ref proc_info);
963 ret = ShellExecuteEx_internal (startInfo,
966 if (proc_info.Password != IntPtr.Zero)
967 Marshal.ZeroFreeBSTR (proc_info.Password);
968 proc_info.Password = IntPtr.Zero;
971 throw new Win32Exception (-proc_info.pid);
974 process.process_handle = proc_info.process_handle;
975 process.pid = proc_info.pid;
976 process.StartExitCallbackIfNeeded ();
980 private static bool Start_noshell (ProcessStartInfo startInfo,
983 ProcInfo proc_info=new ProcInfo();
984 IntPtr stdin_rd = IntPtr.Zero, stdin_wr = IntPtr.Zero;
990 if (startInfo.HaveEnvVars) {
991 string [] strs = new string [startInfo.EnvironmentVariables.Count];
992 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
993 proc_info.envKeys = strs;
995 strs = new string [startInfo.EnvironmentVariables.Count];
996 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
997 proc_info.envValues = strs;
1000 if (startInfo.RedirectStandardInput == true) {
1002 int DUPLICATE_SAME_ACCESS = 0x00000002;
1003 IntPtr stdin_wr_tmp;
1005 ret = MonoIO.CreatePipe (out stdin_rd,
1008 ret = MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, stdin_wr_tmp,
1009 Process.GetCurrentProcess ().Handle, out stdin_wr, 0, 0, DUPLICATE_SAME_ACCESS);
1010 MonoIO.Close (stdin_wr_tmp, out error);
1015 ret = MonoIO.CreatePipe (out stdin_rd,
1019 throw new IOException ("Error creating standard input pipe");
1022 stdin_rd = MonoIO.ConsoleInput;
1023 /* This is required to stop the
1024 * &$*£ing stupid compiler moaning
1025 * that stdin_wr is unassigned, below.
1027 stdin_wr = (IntPtr)0;
1030 if (startInfo.RedirectStandardOutput == true) {
1031 IntPtr out_rd = IntPtr.Zero;
1034 int DUPLICATE_SAME_ACCESS = 0x00000002;
1036 ret = MonoIO.CreatePipe (out out_rd_tmp,
1039 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, out_rd_tmp,
1040 Process.GetCurrentProcess ().Handle, out out_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1041 MonoIO.Close (out_rd_tmp, out error);
1045 ret = MonoIO.CreatePipe (out out_rd,
1049 process.stdout_rd = out_rd;
1051 if (startInfo.RedirectStandardInput == true) {
1052 MonoIO.Close (stdin_rd, out error);
1053 MonoIO.Close (stdin_wr, out error);
1056 throw new IOException ("Error creating standard output pipe");
1059 process.stdout_rd = (IntPtr)0;
1060 stdout_wr = MonoIO.ConsoleOutput;
1063 if (startInfo.RedirectStandardError == true) {
1064 IntPtr err_rd = IntPtr.Zero;
1067 int DUPLICATE_SAME_ACCESS = 0x00000002;
1069 ret = MonoIO.CreatePipe (out err_rd_tmp,
1072 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, err_rd_tmp,
1073 Process.GetCurrentProcess ().Handle, out err_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1074 MonoIO.Close (err_rd_tmp, out error);
1078 ret = MonoIO.CreatePipe (out err_rd,
1082 process.stderr_rd = err_rd;
1084 if (startInfo.RedirectStandardInput == true) {
1085 MonoIO.Close (stdin_rd, out error);
1086 MonoIO.Close (stdin_wr, out error);
1088 if (startInfo.RedirectStandardOutput == true) {
1089 MonoIO.Close (process.stdout_rd, out error);
1090 MonoIO.Close (stdout_wr, out error);
1093 throw new IOException ("Error creating standard error pipe");
1096 process.stderr_rd = (IntPtr)0;
1097 stderr_wr = MonoIO.ConsoleError;
1100 FillUserInfo (startInfo, ref proc_info);
1102 ret = CreateProcess_internal (startInfo,
1103 stdin_rd, stdout_wr, stderr_wr,
1106 if (proc_info.Password != IntPtr.Zero)
1107 Marshal.ZeroFreeBSTR (proc_info.Password);
1108 proc_info.Password = IntPtr.Zero;
1111 if (startInfo.RedirectStandardInput == true) {
1112 MonoIO.Close (stdin_rd, out error);
1113 MonoIO.Close (stdin_wr, out error);
1116 if (startInfo.RedirectStandardOutput == true) {
1117 MonoIO.Close (process.stdout_rd, out error);
1118 MonoIO.Close (stdout_wr, out error);
1121 if (startInfo.RedirectStandardError == true) {
1122 MonoIO.Close (process.stderr_rd, out error);
1123 MonoIO.Close (stderr_wr, out error);
1126 throw new Win32Exception (-proc_info.pid,
1127 "ApplicationName='" + startInfo.FileName +
1128 "', CommandLine='" + startInfo.Arguments +
1129 "', CurrentDirectory='" + startInfo.WorkingDirectory +
1130 "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
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;
1142 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1143 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1145 if (startInfo.RedirectStandardOutput == true) {
1146 MonoIO.Close (stdout_wr, out error);
1147 process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding, true, 8192);
1150 if (startInfo.RedirectStandardError == true) {
1151 MonoIO.Close (stderr_wr, out error);
1152 process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding, true, 8192);
1155 process.StartExitCallbackIfNeeded ();
1160 // Note that ProcInfo.Password must be freed.
1161 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1163 if (startInfo.UserName.Length != 0) {
1164 proc_info.UserName = startInfo.UserName;
1165 proc_info.Domain = startInfo.Domain;
1166 if (startInfo.Password != null)
1167 proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1169 proc_info.Password = IntPtr.Zero;
1170 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1174 private static bool Start_common (ProcessStartInfo startInfo,
1177 if (startInfo.FileName.Length == 0)
1178 throw new InvalidOperationException("File name has not been set");
1180 if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1181 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1182 if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1183 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1185 if (startInfo.UseShellExecute) {
1186 if (startInfo.UserName.Length != 0)
1187 throw new InvalidOperationException ("UseShellExecute must be false if an explicit UserName is specified when starting a process");
1188 return (Start_shell (startInfo, process));
1190 return (Start_noshell (startInfo, process));
1194 public bool Start ()
1196 if (process_handle != IntPtr.Zero) {
1197 Process_free_internal (process_handle);
1198 process_handle = IntPtr.Zero;
1200 return Start_common(start_info, this);
1203 public static Process Start (ProcessStartInfo startInfo)
1205 if (startInfo == null)
1206 throw new ArgumentNullException ("startInfo");
1208 Process process = new Process();
1209 process.StartInfo = startInfo;
1210 if (Start_common(startInfo, process) && process.process_handle != IntPtr.Zero)
1215 public static Process Start (string fileName)
1217 return Start (new ProcessStartInfo (fileName));
1220 public static Process Start(string fileName, string arguments)
1222 return Start (new ProcessStartInfo (fileName, arguments));
1225 public static Process Start(string fileName, string username, SecureString password, string domain) {
1226 return Start(fileName, null, username, password, domain);
1229 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1230 ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1231 psi.UserName = username;
1232 psi.Password = password;
1233 psi.Domain = domain;
1234 psi.UseShellExecute = false;
1238 public override string ToString()
1240 return(base.ToString() + " (" + this.ProcessName + ")");
1243 /* Waits up to ms milliseconds for process 'handle' to
1244 * exit. ms can be <0 to mean wait forever.
1246 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1247 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1249 public void WaitForExit ()
1254 public bool WaitForExit(int milliseconds) {
1255 int ms = milliseconds;
1256 if (ms == int.MaxValue)
1259 if (process_handle == IntPtr.Zero)
1260 throw new InvalidOperationException ("No process is associated with this object.");
1263 DateTime start = DateTime.UtcNow;
1264 if (async_output != null && !async_output.IsCompleted) {
1265 if (false == async_output.WaitHandle.WaitOne (ms, false))
1266 return false; // Timed out
1269 DateTime now = DateTime.UtcNow;
1270 ms -= (int) (now - start).TotalMilliseconds;
1277 if (async_error != null && !async_error.IsCompleted) {
1278 if (false == async_error.WaitHandle.WaitOne (ms, false))
1279 return false; // Timed out
1282 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1288 bool exited = WaitForExit_internal (process_handle, ms);
1296 /* Waits up to ms milliseconds for process 'handle' to
1297 * wait for input. ms can be <0 to mean wait forever.
1299 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1300 private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
1302 // The internal call is only implemented properly on Windows.
1304 public bool WaitForInputIdle() {
1305 return WaitForInputIdle (-1);
1308 // The internal call is only implemented properly on Windows.
1310 public bool WaitForInputIdle(int milliseconds) {
1311 return WaitForInputIdle_internal (process_handle, milliseconds);
1314 private static bool IsLocalMachine (string machineName)
1316 if (machineName == "." || machineName.Length == 0)
1319 return (string.Compare (machineName, Environment.MachineName, true) == 0);
1323 [MonitoringDescription ("Raised when it receives output data")]
1324 public event DataReceivedEventHandler OutputDataReceived;
1326 [MonitoringDescription ("Raised when it receives error data")]
1327 public event DataReceivedEventHandler ErrorDataReceived;
1329 void OnOutputDataReceived (string str)
1331 if (OutputDataReceived != null)
1332 OutputDataReceived (this, new DataReceivedEventArgs (str));
1335 void OnErrorDataReceived (string str)
1337 if (ErrorDataReceived != null)
1338 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1346 AsyncOutput = 1 << 2,
1350 [StructLayout (LayoutKind.Sequential)]
1351 sealed class ProcessAsyncReader : IThreadPoolWorkItem
1354 The following fields match those of SocketAsyncResult.
1355 This is so that changes needed in the runtime to handle
1356 asynchronous reads are trivial
1357 Keep this in sync with SocketAsyncResult in
1358 ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
1359 in metadata/socket-io.h.
1361 /* DON'T shuffle fields around. DON'T remove fields */
1363 public IntPtr handle;
1364 public object state;
1365 public AsyncCallback callback;
1366 public ManualResetEvent wait_handle;
1368 public Exception delayedException;
1370 public object EndPoint;
1371 byte [] buffer = new byte [4196];
1374 public int SockFlags;
1376 public object AcceptSocket;
1377 public object[] Addresses;
1379 public object Buffers; // Reserve this slot in older profiles
1380 public bool ReuseSocket; // Disconnect
1381 public object acc_socket;
1383 public bool completed_sync;
1385 bool err_out; // true -> stdout, false -> stderr
1387 public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1388 public AsyncResult async_result;
1389 public int EndCalled;
1391 // These fields are not in SocketAsyncResult
1394 StringBuilder sb = new StringBuilder ();
1395 public AsyncReadHandler ReadHandler;
1397 public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1399 this.process = process;
1400 this.handle = handle;
1401 stream = new FileStream (handle, FileAccess.Read, false);
1402 this.ReadHandler = new AsyncReadHandler (AddInput);
1403 this.err_out = err_out;
1406 public void AddInput ()
1409 int nread = stream.Read (buffer, 0, buffer.Length);
1412 if (wait_handle != null)
1419 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1421 // Just in case the encoding fails...
1422 for (int i = 0; i < nread; i++) {
1423 sb.Append ((char) buffer [i]);
1428 ReadHandler.BeginInvoke (null, this);
1436 process.OnOutputDataReceived (null);
1438 process.OnErrorDataReceived (null);
1442 void Flush (bool last)
1444 if (sb.Length == 0 ||
1445 (err_out && process.output_canceled) ||
1446 (!err_out && process.error_canceled))
1449 string total = sb.ToString ();
1451 string [] strs = total.Split ('\n');
1452 int len = strs.Length;
1456 for (int i = 0; i < len - 1; i++) {
1458 process.OnOutputDataReceived (strs [i]);
1460 process.OnErrorDataReceived (strs [i]);
1463 string end = strs [len - 1];
1464 if (last || (len == 1 && end == "")) {
1466 process.OnOutputDataReceived (end);
1468 process.OnErrorDataReceived (end);
1475 public bool IsCompleted {
1476 get { return completed; }
1479 public WaitHandle WaitHandle {
1482 if (wait_handle == null)
1483 wait_handle = new ManualResetEvent (completed);
1489 public void Close () {
1493 void IThreadPoolWorkItem.ExecuteWorkItem()
1495 async_result.Invoke ();
1498 void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae)
1503 AsyncModes async_mode;
1504 bool output_canceled;
1505 bool error_canceled;
1506 ProcessAsyncReader async_output;
1507 ProcessAsyncReader async_error;
1508 delegate void AsyncReadHandler ();
1510 [ComVisibleAttribute(false)]
1511 public void BeginOutputReadLine ()
1513 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1514 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1516 if ((async_mode & AsyncModes.SyncOutput) != 0)
1517 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1519 async_mode |= AsyncModes.AsyncOutput;
1520 output_canceled = false;
1521 if (async_output == null) {
1522 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1523 async_output.ReadHandler.BeginInvoke (null, async_output);
1527 [ComVisibleAttribute(false)]
1528 public void CancelOutputRead ()
1530 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1531 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1533 if ((async_mode & AsyncModes.SyncOutput) != 0)
1534 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1536 if (async_output == null)
1537 throw new InvalidOperationException ("No async operation in progress.");
1539 output_canceled = true;
1542 [ComVisibleAttribute(false)]
1543 public void BeginErrorReadLine ()
1545 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1546 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1548 if ((async_mode & AsyncModes.SyncError) != 0)
1549 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1551 async_mode |= AsyncModes.AsyncError;
1552 error_canceled = false;
1553 if (async_error == null) {
1554 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1555 async_error.ReadHandler.BeginInvoke (null, async_error);
1559 [ComVisibleAttribute(false)]
1560 public void CancelErrorRead ()
1562 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1563 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1565 if ((async_mode & AsyncModes.SyncOutput) != 0)
1566 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1568 if (async_error == null)
1569 throw new InvalidOperationException ("No async operation in progress.");
1571 error_canceled = true;
1574 [Category ("Behavior")]
1575 [MonitoringDescription ("Raised when this process exits.")]
1576 public event EventHandler Exited {
1578 if (process_handle != IntPtr.Zero && HasExited) {
1579 value.BeginInvoke (null, null, null, null);
1581 exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1582 if (exited_event != null)
1583 StartExitCallbackIfNeeded ();
1587 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1591 // Closes the system process handle
1592 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1593 private extern void Process_free_internal(IntPtr handle);
1595 private bool disposed = false;
1597 protected override void Dispose(bool disposing) {
1598 // Check to see if Dispose has already been called.
1599 if(this.disposed == false) {
1601 // If this is a call to Dispose,
1602 // dispose all managed resources.
1606 /* These have open FileStreams on the pipes we are about to close */
1607 if (async_output != null)
1608 async_output.Close ();
1609 if (async_error != null)
1610 async_error.Close ();
1612 if (input_stream != null) {
1613 if (!input_stream_exposed)
1614 input_stream.Close ();
1615 input_stream = null;
1617 if (output_stream != null) {
1618 if (!output_stream_exposed)
1619 output_stream.Close ();
1620 output_stream = null;
1622 if (error_stream != null) {
1623 if (!error_stream_exposed)
1624 error_stream.Close ();
1625 error_stream = null;
1630 // Release unmanaged resources
1633 if(process_handle!=IntPtr.Zero) {
1634 Process_free_internal(process_handle);
1635 process_handle=IntPtr.Zero;
1639 base.Dispose (disposing);
1647 static void CBOnExit (object state, bool unused)
1649 Process p = (Process) state;
1651 if (!p.IsExitCallbackPending ())
1655 p.UnregisterExitCallback ();
1656 p.StartExitCallbackIfNeeded ();
1663 int on_exited_called = 0;
1665 protected void OnExited()
1667 if (exited_event == null)
1670 if (on_exited_called != 0 || Interlocked.CompareExchange (ref on_exited_called, 1, 0) != 0)
1673 UnregisterExitCallback ();
1675 if (synchronizingObject == null) {
1676 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1678 d (this, EventArgs.Empty);
1684 object [] args = new object [] {this, EventArgs.Empty};
1685 synchronizingObject.BeginInvoke (exited_event, args);
1688 static bool IsWindows
1692 PlatformID platform = Environment.OSVersion.Platform;
1693 if (platform == PlatformID.Win32S ||
1694 platform == PlatformID.Win32Windows ||
1695 platform == PlatformID.Win32NT ||
1696 platform == PlatformID.WinCE) {
1703 class ProcessWaitHandle : WaitHandle
1705 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1706 private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1708 public ProcessWaitHandle (IntPtr handle)
1710 // Need to keep a reference to this handle,
1711 // in case the Process object is collected
1712 Handle = ProcessHandle_duplicate (handle);
1714 // When the wait handle is disposed, the duplicated handle will be
1715 // closed, so no need to override dispose (bug #464628).