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;
46 using Microsoft.Win32.SafeHandles;
48 namespace System.Diagnostics {
50 [DefaultEvent ("Exited"), DefaultProperty ("StartInfo")]
51 [Designer ("System.Diagnostics.Design.ProcessDesigner, " + Consts.AssemblySystem_Design)]
52 [PermissionSet (SecurityAction.LinkDemand, Unrestricted = true)]
53 [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
54 [MonitoringDescription ("Represents a system process")]
55 public class Process : Component
57 [StructLayout(LayoutKind.Sequential)]
58 private struct ProcInfo
60 public IntPtr process_handle;
61 /* If thread_handle is ever needed for
62 * something, take out the CloseHandle() in
63 * the Start_internal icall in
64 * mono/metadata/process.c
66 public IntPtr thread_handle;
67 public int pid; // Contains -GetLastError () on failure.
69 public string [] envKeys;
70 public string [] envValues;
71 public string UserName;
73 public IntPtr Password;
74 public bool LoadUserProfile;
77 IntPtr process_handle;
79 bool enableRaisingEvents;
80 RegisteredWaitHandle exitWaitHandle;
81 ISynchronizeInvoke synchronizingObject;
82 EventHandler exited_event;
86 object thisLock = new Object ();
88 /* Private constructor called from other methods */
89 private Process(IntPtr handle, int id) {
90 process_handle=handle;
99 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
100 [MonitoringDescription ("Base process priority.")]
101 public int BasePriority {
107 void StartExitCallbackIfNeeded ()
110 bool start = (exitWaitHandle == null && enableRaisingEvents && exited_event != null);
111 if (start && process_handle != IntPtr.Zero) {
112 WaitOrTimerCallback cb = new WaitOrTimerCallback (CBOnExit);
113 ProcessWaitHandle h = new ProcessWaitHandle (process_handle);
114 exitWaitHandle = ThreadPool.RegisterWaitForSingleObject (h, cb, this, -1, true);
119 void UnregisterExitCallback ()
122 if (exitWaitHandle != null) {
123 exitWaitHandle.Unregister (null);
124 exitWaitHandle = null;
129 bool IsExitCallbackPending ()
132 return exitWaitHandle != null;
136 [DefaultValue (false), Browsable (false)]
137 [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
138 public bool EnableRaisingEvents {
140 return enableRaisingEvents;
143 bool prev = enableRaisingEvents;
144 enableRaisingEvents = value;
145 if (enableRaisingEvents && !prev)
146 StartExitCallbackIfNeeded ();
151 [MethodImplAttribute(MethodImplOptions.InternalCall)]
152 private extern static int ExitCode_internal(IntPtr handle);
154 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
155 [MonitoringDescription ("The exit code of the process.")]
156 public int ExitCode {
158 if (process_handle == IntPtr.Zero)
159 throw new InvalidOperationException ("Process has not been started.");
161 int code = ExitCode_internal (process_handle);
163 throw new InvalidOperationException ("The process must exit before " +
164 "getting the requested information.");
170 /* Returns the process start time in Windows file
171 * times (ticks from DateTime(1/1/1601 00:00 GMT))
173 [MethodImplAttribute(MethodImplOptions.InternalCall)]
174 private extern static long ExitTime_internal(IntPtr handle);
176 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
177 [MonitoringDescription ("The exit time of the process.")]
178 public DateTime ExitTime {
180 if (process_handle == IntPtr.Zero)
181 throw new InvalidOperationException ("Process has not been started.");
184 throw new InvalidOperationException ("The process must exit before " +
185 "getting the requested information.");
187 return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
191 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
192 [MonitoringDescription ("Handle for this process.")]
193 public IntPtr Handle {
195 if (process_handle == IntPtr.Zero)
196 throw new InvalidOperationException ("No process is associated with this object.");
197 return(process_handle);
202 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
203 [MonitoringDescription ("Handles for this process.")]
204 public int HandleCount {
210 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
211 [MonitoringDescription ("Determines if the process is still running.")]
212 public bool HasExited {
214 if (process_handle == IntPtr.Zero)
215 throw new InvalidOperationException ("Process has not been started.");
217 int exitcode = ExitCode_internal (process_handle);
228 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
229 [MonitoringDescription ("Process identifier.")]
233 throw new InvalidOperationException ("Process ID has not been set.");
240 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
241 [MonitoringDescription ("The name of the computer running the process.")]
242 public string MachineName {
248 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
249 [MonitoringDescription ("The main module of the process.")]
250 public ProcessModule MainModule {
252 return(this.Modules[0]);
257 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
258 [MonitoringDescription ("The handle of the main window of the process.")]
259 public IntPtr MainWindowHandle {
266 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
267 [MonitoringDescription ("The title of the main window of the process.")]
268 public string MainWindowTitle {
274 [MethodImplAttribute(MethodImplOptions.InternalCall)]
275 private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
276 [MethodImplAttribute(MethodImplOptions.InternalCall)]
277 private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);
279 /* LAMESPEC: why is this an IntPtr not a plain int? */
280 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
281 [MonitoringDescription ("The maximum working set for this process.")]
282 public IntPtr MaxWorkingSet {
285 throw new InvalidOperationException(
286 "The process " + ProcessName +
287 " (ID " + Id + ") has exited");
291 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
293 throw new Win32Exception();
300 throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
303 bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
305 throw new Win32Exception();
310 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
311 [MonitoringDescription ("The minimum working set for this process.")]
312 public IntPtr MinWorkingSet {
315 throw new InvalidOperationException(
316 "The process " + ProcessName +
317 " (ID " + Id + ") has exited");
321 bool ok= GetWorkingSet_internal (process_handle, out min, out max);
323 throw new Win32Exception();
324 return ((IntPtr) min);
328 throw new InvalidOperationException(
329 "The process " + ProcessName +
330 " (ID " + Id + ") has exited");
332 bool ok = SetWorkingSet_internal (process_handle, value.ToInt32(), 0, true);
334 throw new Win32Exception();
338 /* Returns the list of process modules. The main module is
341 [MethodImplAttribute(MethodImplOptions.InternalCall)]
342 private extern ProcessModule[] GetModules_internal(IntPtr handle);
344 private ProcessModuleCollection module_collection;
346 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
347 [MonitoringDescription ("The modules that are loaded as part of this process.")]
348 public ProcessModuleCollection Modules {
350 if (module_collection == null)
351 module_collection = new ProcessModuleCollection(
352 GetModules_internal (process_handle));
353 return(module_collection);
357 /* data type is from the MonoProcessData enum in mono-proclib.h in the runtime */
358 [MethodImplAttribute(MethodImplOptions.InternalCall)]
359 private extern static long GetProcessData (int pid, int data_type, out int error);
362 [Obsolete ("Use NonpagedSystemMemorySize64")]
363 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
364 [MonitoringDescription ("The number of bytes that are not pageable.")]
365 public int NonpagedSystemMemorySize {
371 [Obsolete ("Use PagedMemorySize64")]
372 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
373 [MonitoringDescription ("The number of bytes that are paged.")]
374 public int PagedMemorySize {
376 return(int)PagedMemorySize64;
380 [Obsolete ("Use PagedSystemMemorySize64")]
381 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
382 [MonitoringDescription ("The amount of paged system memory in bytes.")]
383 public int PagedSystemMemorySize {
385 return(int)PagedMemorySize64;
390 [Obsolete ("Use PeakPagedMemorySize64")]
391 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
392 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
393 public int PeakPagedMemorySize {
399 [Obsolete ("Use PeakVirtualMemorySize64")]
400 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
401 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
402 public int PeakVirtualMemorySize {
405 return (int)GetProcessData (pid, 8, out error);
409 [Obsolete ("Use PeakWorkingSet64")]
410 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
411 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
412 public int PeakWorkingSet {
415 return (int)GetProcessData (pid, 5, out error);
420 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
421 [MonitoringDescription ("The number of bytes that are not pageable.")]
423 public long NonpagedSystemMemorySize64 {
429 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
430 [MonitoringDescription ("The number of bytes that are paged.")]
432 public long PagedMemorySize64 {
435 return GetProcessData (pid, 12, out error);
439 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
440 [MonitoringDescription ("The amount of paged system memory in bytes.")]
442 public long PagedSystemMemorySize64 {
444 return PagedMemorySize64;
449 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
450 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
452 public long PeakPagedMemorySize64 {
458 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
459 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
461 public long PeakVirtualMemorySize64 {
464 return GetProcessData (pid, 8, out error);
468 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
469 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
471 public long PeakWorkingSet64 {
474 return GetProcessData (pid, 5, out error);
479 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
480 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
481 public bool PriorityBoostEnabled {
489 [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
490 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
491 [MonitoringDescription ("The relative process priority.")]
492 public ProcessPriorityClass PriorityClass {
494 if (process_handle == IntPtr.Zero)
495 throw new InvalidOperationException ("Process has not been started.");
498 int prio = GetPriorityClass (process_handle, out error);
500 throw new Win32Exception (error);
501 return (ProcessPriorityClass) prio;
504 if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
505 throw new InvalidEnumArgumentException (
506 "value", (int) value,
507 typeof (ProcessPriorityClass));
509 if (process_handle == IntPtr.Zero)
510 throw new InvalidOperationException ("Process has not been started.");
513 if (!SetPriorityClass (process_handle, (int) value, out error)) {
515 throw new Win32Exception (error);
520 void CheckExited () {
522 throw new InvalidOperationException (String.Format ("Cannot process request because the process ({0}) has exited.", Id));
525 [MethodImplAttribute(MethodImplOptions.InternalCall)]
526 static extern int GetPriorityClass (IntPtr handle, out int error);
528 [MethodImplAttribute(MethodImplOptions.InternalCall)]
529 static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);
531 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
532 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
533 [Obsolete ("Use PrivateMemorySize64")]
534 public int PrivateMemorySize {
537 return (int)GetProcessData (pid, 6, out error);
541 [MonoNotSupported ("")]
542 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
543 [MonitoringDescription ("The session ID for this process.")]
544 public int SessionId {
545 get { throw new NotImplementedException (); }
548 /* the meaning of type is as follows: 0: user, 1: system, 2: total */
549 [MethodImplAttribute(MethodImplOptions.InternalCall)]
550 private extern static long Times (IntPtr handle, int type);
552 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
553 [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
554 public TimeSpan PrivilegedProcessorTime {
556 return new TimeSpan (Times (process_handle, 1));
560 [MethodImplAttribute(MethodImplOptions.InternalCall)]
561 private extern static string ProcessName_internal(IntPtr handle);
563 private string process_name=null;
565 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
566 [MonitoringDescription ("The name of this process.")]
567 public string ProcessName {
569 if(process_name==null) {
571 if (process_handle == IntPtr.Zero)
572 throw new InvalidOperationException ("No process is associated with this object.");
574 process_name=ProcessName_internal(process_handle);
575 /* If process_name is _still_
576 * null, assume the process
579 if (process_name == null)
580 throw new InvalidOperationException ("Process has exited, so the requested information is not available.");
582 /* Strip the suffix (if it
583 * exists) simplistically
584 * instead of removing any
585 * trailing \.???, so we dont
586 * get stupid results on sane
589 if(process_name.EndsWith(".exe") ||
590 process_name.EndsWith(".bat") ||
591 process_name.EndsWith(".com")) {
592 process_name=process_name.Substring(0, process_name.Length-4);
595 return(process_name);
600 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
601 [MonitoringDescription ("Allowed processor that can be used by this process.")]
602 public IntPtr ProcessorAffinity {
611 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
612 [MonitoringDescription ("Is this process responsive.")]
613 public bool Responding {
619 private StreamReader error_stream=null;
620 bool error_stream_exposed;
622 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
623 [MonitoringDescription ("The standard error stream of this process.")]
624 public StreamReader StandardError {
626 if (error_stream == null)
627 throw new InvalidOperationException("Standard error has not been redirected");
629 if ((async_mode & AsyncModes.AsyncError) != 0)
630 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
632 async_mode |= AsyncModes.SyncError;
634 error_stream_exposed = true;
635 return(error_stream);
639 private StreamWriter input_stream=null;
640 bool input_stream_exposed;
642 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
643 [MonitoringDescription ("The standard input stream of this process.")]
644 public StreamWriter StandardInput {
646 if (input_stream == null)
647 throw new InvalidOperationException("Standard input has not been redirected");
649 input_stream_exposed = true;
650 return(input_stream);
654 private StreamReader output_stream=null;
655 bool output_stream_exposed;
657 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
658 [MonitoringDescription ("The standard output stream of this process.")]
659 public StreamReader StandardOutput {
661 if (output_stream == null)
662 throw new InvalidOperationException("Standard output has not been redirected");
664 if ((async_mode & AsyncModes.AsyncOutput) != 0)
665 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
667 async_mode |= AsyncModes.SyncOutput;
669 output_stream_exposed = true;
670 return(output_stream);
674 private ProcessStartInfo start_info=null;
676 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
677 [MonitoringDescription ("Information for the start of this process.")]
678 public ProcessStartInfo StartInfo {
680 if (start_info == null)
681 start_info = new ProcessStartInfo();
686 throw new ArgumentNullException("value");
691 /* Returns the process start time in Windows file
692 * times (ticks from DateTime(1/1/1601 00:00 GMT))
694 [MethodImplAttribute(MethodImplOptions.InternalCall)]
695 private extern static long StartTime_internal(IntPtr handle);
697 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
698 [MonitoringDescription ("The time this process started.")]
699 public DateTime StartTime {
701 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
705 [DefaultValue (null), Browsable (false)]
706 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
707 public ISynchronizeInvoke SynchronizingObject {
708 get { return synchronizingObject; }
709 set { synchronizingObject = value; }
713 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
714 [MonitoringDescription ("The number of threads of this process.")]
715 public ProcessThreadCollection Threads {
717 // This'll return a correctly-sized array of empty ProcessThreads for now.
719 return new ProcessThreadCollection(new ProcessThread[GetProcessData (pid, 0, out error)]);
723 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
724 [MonitoringDescription ("The total CPU time spent for this process.")]
725 public TimeSpan TotalProcessorTime {
727 return new TimeSpan (Times (process_handle, 2));
731 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
732 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
733 public TimeSpan UserProcessorTime {
735 return new TimeSpan (Times (process_handle, 0));
739 [Obsolete ("Use VirtualMemorySize64")]
740 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
741 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
742 public int VirtualMemorySize {
745 return (int)GetProcessData (pid, 7, out error);
749 [Obsolete ("Use WorkingSet64")]
750 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
751 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
752 public int WorkingSet {
755 return (int)GetProcessData (pid, 4, out error);
759 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
760 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
762 public long PrivateMemorySize64 {
765 return GetProcessData (pid, 6, out error);
769 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
770 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
772 public long VirtualMemorySize64 {
775 return GetProcessData (pid, 7, out error);
779 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
780 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
782 public long WorkingSet64 {
785 return GetProcessData (pid, 4, out error);
794 [MethodImplAttribute(MethodImplOptions.InternalCall)]
795 extern static bool Kill_internal (IntPtr handle, int signo);
797 /* int kill -> 1 KILL, 2 CloseMainWindow */
798 bool Close (int signo)
800 if (process_handle == IntPtr.Zero)
801 throw new SystemException ("No process to kill.");
803 int exitcode = ExitCode_internal (process_handle);
805 throw new InvalidOperationException ("The process already finished.");
807 return Kill_internal (process_handle, signo);
810 public bool CloseMainWindow ()
816 public static void EnterDebugMode() {
819 [MethodImplAttribute(MethodImplOptions.InternalCall)]
820 private extern static IntPtr GetProcess_internal(int pid);
822 [MethodImplAttribute(MethodImplOptions.InternalCall)]
823 private extern static int GetPid_internal();
825 public static Process GetCurrentProcess()
827 int pid = GetPid_internal();
828 IntPtr proc = GetProcess_internal(pid);
830 if (proc == IntPtr.Zero)
831 throw new SystemException("Can't find current process");
833 return (new Process (proc, pid));
836 public static Process GetProcessById(int processId)
838 IntPtr proc = GetProcess_internal(processId);
840 if (proc == IntPtr.Zero)
841 throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
843 return (new Process (proc, processId));
846 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
847 public static Process GetProcessById(int processId, string machineName) {
848 if (machineName == null)
849 throw new ArgumentNullException ("machineName");
851 if (!IsLocalMachine (machineName))
852 throw new NotImplementedException ();
854 return GetProcessById (processId);
857 [MethodImplAttribute(MethodImplOptions.InternalCall)]
858 private extern static int[] GetProcesses_internal();
860 public static Process[] GetProcesses ()
862 int [] pids = GetProcesses_internal ();
864 return new Process [0];
866 var proclist = new List<Process> (pids.Length);
867 for (int i = 0; i < pids.Length; i++) {
869 proclist.Add (GetProcessById (pids [i]));
870 } catch (SystemException) {
871 /* The process might exit
873 * GetProcesses_internal and
879 return proclist.ToArray ();
882 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
883 public static Process[] GetProcesses(string machineName) {
884 if (machineName == null)
885 throw new ArgumentNullException ("machineName");
887 if (!IsLocalMachine (machineName))
888 throw new NotImplementedException ();
890 return GetProcesses ();
893 public static Process[] GetProcessesByName(string processName)
895 int [] pids = GetProcesses_internal ();
897 return new Process [0];
899 var proclist = new List<Process> (pids.Length);
900 for (int i = 0; i < pids.Length; i++) {
902 Process p = GetProcessById (pids [i]);
903 if (String.Compare (processName, p.ProcessName, true) == 0)
905 } catch (SystemException) {
906 /* The process might exit
908 * GetProcesses_internal and
914 return proclist.ToArray ();
918 public static Process[] GetProcessesByName(string processName, string machineName) {
919 throw new NotImplementedException();
928 public static void LeaveDebugMode() {
931 public void Refresh ()
933 // FIXME: should refresh any cached data we might have about
934 // the process (currently we have none).
937 [MethodImplAttribute(MethodImplOptions.InternalCall)]
938 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
939 ref ProcInfo proc_info);
941 [MethodImplAttribute(MethodImplOptions.InternalCall)]
942 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
946 ref ProcInfo proc_info);
948 private static bool Start_shell (ProcessStartInfo startInfo, Process process)
950 ProcInfo proc_info=new ProcInfo();
953 if (startInfo.RedirectStandardInput ||
954 startInfo.RedirectStandardOutput ||
955 startInfo.RedirectStandardError) {
956 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
959 if (startInfo.HaveEnvVars)
960 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
962 FillUserInfo (startInfo, ref proc_info);
964 ret = ShellExecuteEx_internal (startInfo,
967 if (proc_info.Password != IntPtr.Zero)
968 Marshal.ZeroFreeBSTR (proc_info.Password);
969 proc_info.Password = IntPtr.Zero;
972 throw new Win32Exception (-proc_info.pid);
975 process.process_handle = proc_info.process_handle;
976 process.pid = proc_info.pid;
977 process.StartExitCallbackIfNeeded ();
982 // Creates a pipe with read and write descriptors
984 static void CreatePipe (out IntPtr read, out IntPtr write, bool writeDirection)
989 // Creates read/write pipe from parent -> child perspective
990 // a child process uses same descriptors after fork. That's
991 // 4 descriptors in total where only 2. One in child, one in parent
992 // should be active and the other 2 closed. Which ones depends on
993 // comunication direction
995 // parent --------> child (parent can write, child can read)
997 // read: closed read: used
998 // write: used write: closed
1001 // parent <-------- child (parent can read, child can write)
1003 // read: used read: closed
1004 // write: closed write: used
1006 // It can still be tricky for predefined descriptiors http://unixwiz.net/techtips/remap-pipe-fds.html
1008 if (!MonoIO.CreatePipe (out read, out write, out error))
1009 throw MonoIO.GetException (error);
1012 const int DUPLICATE_SAME_ACCESS = 0x00000002;
1013 var tmp = writeDirection ? write : read;
1015 if (!MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, tmp, Process.GetCurrentProcess ().Handle, out tmp, 0, 0, DUPLICATE_SAME_ACCESS, out error))
1016 throw MonoIO.GetException (error);
1018 if (writeDirection) {
1019 if (!MonoIO.Close (write, out error))
1020 throw MonoIO.GetException (error);
1023 if (!MonoIO.Close (read, out error))
1024 throw MonoIO.GetException (error);
1030 static bool Start_noshell (ProcessStartInfo startInfo, Process process)
1032 var proc_info = new ProcInfo ();
1034 if (startInfo.HaveEnvVars) {
1035 string [] strs = new string [startInfo.EnvironmentVariables.Count];
1036 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
1037 proc_info.envKeys = strs;
1039 strs = new string [startInfo.EnvironmentVariables.Count];
1040 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
1041 proc_info.envValues = strs;
1045 IntPtr stdin_read = IntPtr.Zero, stdin_write = IntPtr.Zero;
1046 IntPtr stdout_read = IntPtr.Zero, stdout_write = IntPtr.Zero;
1047 IntPtr stderr_read = IntPtr.Zero, stderr_write = IntPtr.Zero;
1050 if (startInfo.RedirectStandardInput) {
1051 CreatePipe (out stdin_read, out stdin_write, true);
1053 stdin_read = MonoIO.ConsoleInput;
1054 stdin_write = IntPtr.Zero;
1057 if (startInfo.RedirectStandardOutput) {
1058 CreatePipe (out stdout_read, out stdout_write, false);
1059 process.stdout_rd = stdout_read;
1061 process.stdout_rd = IntPtr.Zero;
1062 stdout_write = MonoIO.ConsoleOutput;
1065 if (startInfo.RedirectStandardError) {
1066 CreatePipe (out stderr_read, out stderr_write, false);
1067 process.stderr_rd = stderr_read;
1069 process.stderr_rd = IntPtr.Zero;
1070 stderr_write = MonoIO.ConsoleError;
1073 FillUserInfo (startInfo, ref proc_info);
1076 // FIXME: For redirected pipes we need to send descriptors of
1077 // stdin_write, stdout_read, stderr_read to child process and
1078 // close them there (fork makes exact copy of parent's descriptors)
1080 if (!CreateProcess_internal (startInfo, stdin_read, stdout_write, stderr_write, ref proc_info)) {
1081 throw new Win32Exception (-proc_info.pid,
1082 "ApplicationName='" + startInfo.FileName +
1083 "', CommandLine='" + startInfo.Arguments +
1084 "', CurrentDirectory='" + startInfo.WorkingDirectory +
1085 "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
1088 if (startInfo.RedirectStandardInput) {
1089 if (stdin_read != IntPtr.Zero)
1090 MonoIO.Close (stdin_read, out error);
1091 if (stdin_write != IntPtr.Zero)
1092 MonoIO.Close (stdin_write, out error);
1095 if (startInfo.RedirectStandardOutput) {
1096 if (stdout_read != IntPtr.Zero)
1097 MonoIO.Close (stdout_read, out error);
1098 if (stdout_write != IntPtr.Zero)
1099 MonoIO.Close (stdout_write, out error);
1102 if (startInfo.RedirectStandardError) {
1103 if (stderr_read != IntPtr.Zero)
1104 MonoIO.Close (stderr_read, out error);
1105 if (stderr_write != IntPtr.Zero)
1106 MonoIO.Close (stderr_write, out error);
1111 if (proc_info.Password != IntPtr.Zero) {
1112 Marshal.ZeroFreeBSTR (proc_info.Password);
1113 proc_info.Password = IntPtr.Zero;
1117 process.process_handle = proc_info.process_handle;
1118 process.pid = proc_info.pid;
1120 if (startInfo.RedirectStandardInput) {
1122 // FIXME: The descriptor needs to be closed but due to wapi io-layer
1123 // not coping with duplicated descriptors any StandardInput write fails
1125 // MonoIO.Close (stdin_read, out error);
1128 var stdinEncoding = Encoding.Default;
1130 var stdinEncoding = Console.InputEncoding;
1132 process.input_stream = new StreamWriter (new FileStream (new SafeFileHandle (stdin_write, false), FileAccess.Write, 8192, false), stdinEncoding) {
1137 if (startInfo.RedirectStandardOutput) {
1138 MonoIO.Close (stdout_write, out error);
1140 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1142 process.output_stream = new StreamReader (new FileStream (new SafeFileHandle (stdout_read, false), FileAccess.Read, 8192, false), stdoutEncoding, true, 8192);
1145 if (startInfo.RedirectStandardError) {
1146 MonoIO.Close (stderr_write, out error);
1148 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1150 process.error_stream = new StreamReader (new FileStream (new SafeFileHandle (stderr_read, false), FileAccess.Read, 8192, false), stderrEncoding, true, 8192);
1153 process.StartExitCallbackIfNeeded ();
1158 // Note that ProcInfo.Password must be freed.
1159 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1161 if (startInfo.UserName.Length != 0) {
1162 proc_info.UserName = startInfo.UserName;
1163 proc_info.Domain = startInfo.Domain;
1164 if (startInfo.Password != null)
1165 proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1167 proc_info.Password = IntPtr.Zero;
1168 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1172 private static bool Start_common (ProcessStartInfo startInfo,
1175 if (startInfo.FileName.Length == 0)
1176 throw new InvalidOperationException("File name has not been set");
1178 if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1179 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1180 if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1181 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1183 if (startInfo.UseShellExecute) {
1184 if (startInfo.UserName.Length != 0)
1185 throw new InvalidOperationException ("UseShellExecute must be false if an explicit UserName is specified when starting a process");
1186 return (Start_shell (startInfo, process));
1188 return (Start_noshell (startInfo, process));
1192 public bool Start ()
1194 if (process_handle != IntPtr.Zero) {
1195 Process_free_internal (process_handle);
1196 process_handle = IntPtr.Zero;
1198 return Start_common(start_info, this);
1201 public static Process Start (ProcessStartInfo startInfo)
1203 if (startInfo == null)
1204 throw new ArgumentNullException ("startInfo");
1206 Process process = new Process();
1207 process.StartInfo = startInfo;
1208 if (Start_common(startInfo, process) && process.process_handle != IntPtr.Zero)
1213 public static Process Start (string fileName)
1215 return Start (new ProcessStartInfo (fileName));
1218 public static Process Start(string fileName, string arguments)
1220 return Start (new ProcessStartInfo (fileName, arguments));
1223 public static Process Start(string fileName, string username, SecureString password, string domain) {
1224 return Start(fileName, null, username, password, domain);
1227 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1228 ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1229 psi.UserName = username;
1230 psi.Password = password;
1231 psi.Domain = domain;
1232 psi.UseShellExecute = false;
1236 public override string ToString()
1238 return(base.ToString() + " (" + this.ProcessName + ")");
1241 /* Waits up to ms milliseconds for process 'handle' to
1242 * exit. ms can be <0 to mean wait forever.
1244 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1245 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1247 public void WaitForExit ()
1252 public bool WaitForExit(int milliseconds) {
1253 int ms = milliseconds;
1254 if (ms == int.MaxValue)
1257 if (process_handle == IntPtr.Zero)
1258 throw new InvalidOperationException ("No process is associated with this object.");
1261 DateTime start = DateTime.UtcNow;
1262 if (async_output != null && !async_output.IsCompleted) {
1263 if (false == async_output.AsyncWaitHandle.WaitOne (ms, false))
1264 return false; // Timed out
1267 DateTime now = DateTime.UtcNow;
1268 ms -= (int) (now - start).TotalMilliseconds;
1275 if (async_error != null && !async_error.IsCompleted) {
1276 if (false == async_error.AsyncWaitHandle.WaitOne (ms, false))
1277 return false; // Timed out
1280 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1286 bool exited = WaitForExit_internal (process_handle, ms);
1294 /* Waits up to ms milliseconds for process 'handle' to
1295 * wait for input. ms can be <0 to mean wait forever.
1297 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1298 private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
1300 // The internal call is only implemented properly on Windows.
1302 public bool WaitForInputIdle() {
1303 return WaitForInputIdle (-1);
1306 // The internal call is only implemented properly on Windows.
1308 public bool WaitForInputIdle(int milliseconds) {
1309 return WaitForInputIdle_internal (process_handle, milliseconds);
1312 private static bool IsLocalMachine (string machineName)
1314 if (machineName == "." || machineName.Length == 0)
1317 return (string.Compare (machineName, Environment.MachineName, true) == 0);
1321 [MonitoringDescription ("Raised when it receives output data")]
1322 public event DataReceivedEventHandler OutputDataReceived;
1324 [MonitoringDescription ("Raised when it receives error data")]
1325 public event DataReceivedEventHandler ErrorDataReceived;
1327 void OnOutputDataReceived (string str)
1329 if (OutputDataReceived != null)
1330 OutputDataReceived (this, new DataReceivedEventArgs (str));
1333 void OnErrorDataReceived (string str)
1335 if (ErrorDataReceived != null)
1336 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1344 AsyncOutput = 1 << 2,
1348 [StructLayout (LayoutKind.Sequential)]
1349 sealed class ProcessAsyncReader : IOAsyncResult
1356 StringBuilder sb = new StringBuilder ();
1357 byte[] buffer = new byte [4096];
1359 public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1362 this.process = process;
1363 this.handle = handle;
1364 this.stream = new FileStream (handle, FileAccess.Read, false);
1365 this.err_out = err_out;
1368 public void BeginRead ()
1370 IOSelector.Add (this.handle, new IOSelectorJob (IOOperation.Read, _ => AddInput (), null));
1373 public void AddInput ()
1376 int nread = stream.Read (buffer, 0, buffer.Length);
1382 process.OnOutputDataReceived (null);
1384 process.OnErrorDataReceived (null);
1390 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1392 // Just in case the encoding fails...
1393 for (int i = 0; i < nread; i++) {
1394 sb.Append ((char) buffer [i]);
1400 IOSelector.Add (this.handle, new IOSelectorJob (IOOperation.Read, _ => AddInput (), null));
1404 void Flush (bool last)
1406 if (sb.Length == 0 || (err_out && process.output_canceled) || (!err_out && process.error_canceled))
1409 string[] strs = sb.ToString ().Split ('\n');
1413 if (strs.Length == 0)
1416 for (int i = 0; i < strs.Length - 1; i++) {
1418 process.OnOutputDataReceived (strs [i]);
1420 process.OnErrorDataReceived (strs [i]);
1423 string end = strs [strs.Length - 1];
1424 if (last || (strs.Length == 1 && end == "")) {
1426 process.OnOutputDataReceived (end);
1428 process.OnErrorDataReceived (end);
1434 public void Close ()
1436 IOSelector.Remove (handle);
1440 internal override void CompleteDisposed ()
1442 throw new NotSupportedException ();
1446 AsyncModes async_mode;
1447 bool output_canceled;
1448 bool error_canceled;
1449 ProcessAsyncReader async_output;
1450 ProcessAsyncReader async_error;
1452 [ComVisibleAttribute(false)]
1453 public void BeginOutputReadLine ()
1455 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1456 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1458 if ((async_mode & AsyncModes.SyncOutput) != 0)
1459 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1461 async_mode |= AsyncModes.AsyncOutput;
1462 output_canceled = false;
1463 if (async_output == null) {
1464 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1465 async_output.BeginRead ();
1469 [ComVisibleAttribute(false)]
1470 public void CancelOutputRead ()
1472 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1473 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1475 if ((async_mode & AsyncModes.SyncOutput) != 0)
1476 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1478 if (async_output == null)
1479 throw new InvalidOperationException ("No async operation in progress.");
1481 output_canceled = true;
1484 [ComVisibleAttribute(false)]
1485 public void BeginErrorReadLine ()
1487 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1488 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1490 if ((async_mode & AsyncModes.SyncError) != 0)
1491 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1493 async_mode |= AsyncModes.AsyncError;
1494 error_canceled = false;
1495 if (async_error == null) {
1496 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1497 async_error.BeginRead ();
1501 [ComVisibleAttribute(false)]
1502 public void CancelErrorRead ()
1504 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1505 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1507 if ((async_mode & AsyncModes.SyncOutput) != 0)
1508 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1510 if (async_error == null)
1511 throw new InvalidOperationException ("No async operation in progress.");
1513 error_canceled = true;
1516 [Category ("Behavior")]
1517 [MonitoringDescription ("Raised when this process exits.")]
1518 public event EventHandler Exited {
1520 if (process_handle != IntPtr.Zero && HasExited) {
1521 value.BeginInvoke (null, null, null, null);
1523 exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1524 if (exited_event != null)
1525 StartExitCallbackIfNeeded ();
1529 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1533 // Closes the system process handle
1534 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1535 private extern void Process_free_internal(IntPtr handle);
1537 private bool disposed = false;
1539 protected override void Dispose(bool disposing) {
1540 // Check to see if Dispose has already been called.
1541 if(this.disposed == false) {
1543 // If this is a call to Dispose,
1544 // dispose all managed resources.
1548 /* These have open FileStreams on the pipes we are about to close */
1549 if (async_output != null)
1550 async_output.Close ();
1551 if (async_error != null)
1552 async_error.Close ();
1554 if (input_stream != null) {
1555 if (!input_stream_exposed)
1556 input_stream.Close ();
1557 input_stream = null;
1559 if (output_stream != null) {
1560 if (!output_stream_exposed)
1561 output_stream.Close ();
1562 output_stream = null;
1564 if (error_stream != null) {
1565 if (!error_stream_exposed)
1566 error_stream.Close ();
1567 error_stream = null;
1572 // Release unmanaged resources
1575 if(process_handle!=IntPtr.Zero) {
1576 Process_free_internal(process_handle);
1577 process_handle=IntPtr.Zero;
1581 base.Dispose (disposing);
1589 static void CBOnExit (object state, bool unused)
1591 Process p = (Process) state;
1593 if (!p.IsExitCallbackPending ())
1597 p.UnregisterExitCallback ();
1598 p.StartExitCallbackIfNeeded ();
1605 int on_exited_called = 0;
1607 protected void OnExited()
1609 if (exited_event == null)
1612 if (on_exited_called != 0 || Interlocked.CompareExchange (ref on_exited_called, 1, 0) != 0)
1615 UnregisterExitCallback ();
1617 if (synchronizingObject == null) {
1618 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1620 d (this, EventArgs.Empty);
1626 object [] args = new object [] {this, EventArgs.Empty};
1627 synchronizingObject.BeginInvoke (exited_event, args);
1630 static bool IsWindows
1634 PlatformID platform = Environment.OSVersion.Platform;
1635 if (platform == PlatformID.Win32S ||
1636 platform == PlatformID.Win32Windows ||
1637 platform == PlatformID.Win32NT ||
1638 platform == PlatformID.WinCE) {
1645 class ProcessWaitHandle : WaitHandle
1647 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1648 private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1650 public ProcessWaitHandle (IntPtr handle)
1652 // Need to keep a reference to this handle,
1653 // in case the Process object is collected
1654 Handle = ProcessHandle_duplicate (handle);
1656 // When the wait handle is disposed, the duplicated handle will be
1657 // closed, so no need to override dispose (bug #464628).