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)
987 // Creates read/write pipe from parent -> child perspective
988 // a child process uses same descriptors after fork. That's
989 // 4 descriptors in total where only 2. One in child, one in parent
990 // should be active and the other 2 closed. Which ones depends on
991 // comunication direction
993 // parent --------> child (parent can write, child can read)
995 // read: closed read: used
996 // write: used write: closed
999 // parent <-------- child (parent can read, child can write)
1001 // read: used read: closed
1002 // write: closed write: used
1004 // It can still be tricky for predefined descriptiors http://unixwiz.net/techtips/remap-pipe-fds.html
1006 var ret = MonoIO.CreatePipe (out read, out write);
1008 throw new IOException ("Error creating process pipe");
1011 const int DUPLICATE_SAME_ACCESS = 0x00000002;
1012 var tmp = writeDirection ? write : read;
1014 ret = MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, tmp,
1015 Process.GetCurrentProcess ().Handle, out tmp, 0, 0, DUPLICATE_SAME_ACCESS);
1020 if (writeDirection) {
1021 MonoIO.Close (write, out error);
1024 MonoIO.Close (read, out 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.WaitHandle.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.WaitHandle.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 : IThreadPoolWorkItem
1352 The following fields match those of SocketAsyncResult.
1353 This is so that changes needed in the runtime to handle
1354 asynchronous reads are trivial
1355 Keep this in sync with SocketAsyncResult in
1356 ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
1357 in metadata/socket-io.h.
1359 /* DON'T shuffle fields around. DON'T remove fields */
1361 public IntPtr handle;
1362 public object state;
1363 public AsyncCallback callback;
1364 public ManualResetEvent wait_handle;
1366 public Exception delayedException;
1368 public object EndPoint;
1369 byte [] buffer = new byte [4196];
1372 public int SockFlags;
1374 public object AcceptSocket;
1375 public object[] Addresses;
1377 public object Buffers; // Reserve this slot in older profiles
1378 public bool ReuseSocket; // Disconnect
1379 public object acc_socket;
1381 public bool completed_sync;
1383 bool err_out; // true -> stdout, false -> stderr
1385 public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1386 public AsyncResult async_result;
1387 public int EndCalled;
1389 // These fields are not in SocketAsyncResult
1392 StringBuilder sb = new StringBuilder ();
1393 public AsyncReadHandler ReadHandler;
1395 public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1397 this.process = process;
1398 this.handle = handle;
1399 stream = new FileStream (handle, FileAccess.Read, false);
1400 this.ReadHandler = new AsyncReadHandler (AddInput);
1401 this.err_out = err_out;
1404 public void AddInput ()
1407 int nread = stream.Read (buffer, 0, buffer.Length);
1410 if (wait_handle != null)
1417 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1419 // Just in case the encoding fails...
1420 for (int i = 0; i < nread; i++) {
1421 sb.Append ((char) buffer [i]);
1426 ReadHandler.BeginInvoke (null, this);
1434 process.OnOutputDataReceived (null);
1436 process.OnErrorDataReceived (null);
1440 void Flush (bool last)
1442 if (sb.Length == 0 ||
1443 (err_out && process.output_canceled) ||
1444 (!err_out && process.error_canceled))
1447 string total = sb.ToString ();
1449 string [] strs = total.Split ('\n');
1450 int len = strs.Length;
1454 for (int i = 0; i < len - 1; i++) {
1456 process.OnOutputDataReceived (strs [i]);
1458 process.OnErrorDataReceived (strs [i]);
1461 string end = strs [len - 1];
1462 if (last || (len == 1 && end == "")) {
1464 process.OnOutputDataReceived (end);
1466 process.OnErrorDataReceived (end);
1473 public bool IsCompleted {
1474 get { return completed; }
1477 public WaitHandle WaitHandle {
1480 if (wait_handle == null)
1481 wait_handle = new ManualResetEvent (completed);
1487 public void Close () {
1488 RemoveFromIOThreadPool (handle);
1492 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1493 extern static void RemoveFromIOThreadPool (IntPtr handle);
1495 void IThreadPoolWorkItem.ExecuteWorkItem()
1497 async_result.Invoke ();
1500 void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae)
1505 AsyncModes async_mode;
1506 bool output_canceled;
1507 bool error_canceled;
1508 ProcessAsyncReader async_output;
1509 ProcessAsyncReader async_error;
1510 delegate void AsyncReadHandler ();
1512 [ComVisibleAttribute(false)]
1513 public void BeginOutputReadLine ()
1515 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1516 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1518 if ((async_mode & AsyncModes.SyncOutput) != 0)
1519 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1521 async_mode |= AsyncModes.AsyncOutput;
1522 output_canceled = false;
1523 if (async_output == null) {
1524 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1525 async_output.ReadHandler.BeginInvoke (null, async_output);
1529 [ComVisibleAttribute(false)]
1530 public void CancelOutputRead ()
1532 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1533 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1535 if ((async_mode & AsyncModes.SyncOutput) != 0)
1536 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1538 if (async_output == null)
1539 throw new InvalidOperationException ("No async operation in progress.");
1541 output_canceled = true;
1544 [ComVisibleAttribute(false)]
1545 public void BeginErrorReadLine ()
1547 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1548 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1550 if ((async_mode & AsyncModes.SyncError) != 0)
1551 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1553 async_mode |= AsyncModes.AsyncError;
1554 error_canceled = false;
1555 if (async_error == null) {
1556 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1557 async_error.ReadHandler.BeginInvoke (null, async_error);
1561 [ComVisibleAttribute(false)]
1562 public void CancelErrorRead ()
1564 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1565 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1567 if ((async_mode & AsyncModes.SyncOutput) != 0)
1568 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1570 if (async_error == null)
1571 throw new InvalidOperationException ("No async operation in progress.");
1573 error_canceled = true;
1576 [Category ("Behavior")]
1577 [MonitoringDescription ("Raised when this process exits.")]
1578 public event EventHandler Exited {
1580 if (process_handle != IntPtr.Zero && HasExited) {
1581 value.BeginInvoke (null, null, null, null);
1583 exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1584 if (exited_event != null)
1585 StartExitCallbackIfNeeded ();
1589 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1593 // Closes the system process handle
1594 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1595 private extern void Process_free_internal(IntPtr handle);
1597 private bool disposed = false;
1599 protected override void Dispose(bool disposing) {
1600 // Check to see if Dispose has already been called.
1601 if(this.disposed == false) {
1603 // If this is a call to Dispose,
1604 // dispose all managed resources.
1608 /* These have open FileStreams on the pipes we are about to close */
1609 if (async_output != null)
1610 async_output.Close ();
1611 if (async_error != null)
1612 async_error.Close ();
1614 if (input_stream != null) {
1615 if (!input_stream_exposed)
1616 input_stream.Close ();
1617 input_stream = null;
1619 if (output_stream != null) {
1620 if (!output_stream_exposed)
1621 output_stream.Close ();
1622 output_stream = null;
1624 if (error_stream != null) {
1625 if (!error_stream_exposed)
1626 error_stream.Close ();
1627 error_stream = null;
1632 // Release unmanaged resources
1635 if(process_handle!=IntPtr.Zero) {
1636 Process_free_internal(process_handle);
1637 process_handle=IntPtr.Zero;
1641 base.Dispose (disposing);
1649 static void CBOnExit (object state, bool unused)
1651 Process p = (Process) state;
1653 if (!p.IsExitCallbackPending ())
1657 p.UnregisterExitCallback ();
1658 p.StartExitCallbackIfNeeded ();
1665 int on_exited_called = 0;
1667 protected void OnExited()
1669 if (exited_event == null)
1672 if (on_exited_called != 0 || Interlocked.CompareExchange (ref on_exited_called, 1, 0) != 0)
1675 UnregisterExitCallback ();
1677 if (synchronizingObject == null) {
1678 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1680 d (this, EventArgs.Empty);
1686 object [] args = new object [] {this, EventArgs.Empty};
1687 synchronizingObject.BeginInvoke (exited_event, args);
1690 static bool IsWindows
1694 PlatformID platform = Environment.OSVersion.Platform;
1695 if (platform == PlatformID.Win32S ||
1696 platform == PlatformID.Win32Windows ||
1697 platform == PlatformID.Win32NT ||
1698 platform == PlatformID.WinCE) {
1705 class ProcessWaitHandle : WaitHandle
1707 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1708 private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1710 public ProcessWaitHandle (IntPtr handle)
1712 // Need to keep a reference to this handle,
1713 // in case the Process object is collected
1714 Handle = ProcessHandle_duplicate (handle);
1716 // When the wait handle is disposed, the duplicated handle will be
1717 // closed, so no need to override dispose (bug #464628).