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 int enable_raising_events;
80 Thread background_wait_for_exit_thread;
81 ISynchronizeInvoke synchronizingObject;
82 EventHandler exited_event;
84 /* Private constructor called from other methods */
85 private Process(IntPtr handle, int id) {
86 process_handle = handle;
95 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
96 [MonitoringDescription ("Base process priority.")]
97 public int BasePriority {
101 [DefaultValue (false), Browsable (false)]
102 [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
103 public bool EnableRaisingEvents {
105 return enable_raising_events == 1;
108 if (value && Interlocked.Exchange (ref enable_raising_events, 1) == 0)
109 StartBackgroundWaitForExit ();
113 [MethodImplAttribute(MethodImplOptions.InternalCall)]
114 private extern static int ExitCode_internal(IntPtr handle);
116 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
117 [MonitoringDescription ("The exit code of the process.")]
118 public int ExitCode {
120 if (process_handle == IntPtr.Zero)
121 throw new InvalidOperationException ("Process has not been started.");
123 int code = ExitCode_internal (process_handle);
125 throw new InvalidOperationException ("The process must exit before getting the requested information.");
131 /* Returns the process start time in Windows file
132 * times (ticks from DateTime(1/1/1601 00:00 GMT))
134 [MethodImplAttribute(MethodImplOptions.InternalCall)]
135 private extern static long ExitTime_internal(IntPtr handle);
137 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
138 [MonitoringDescription ("The exit time of the process.")]
139 public DateTime ExitTime {
141 if (process_handle == IntPtr.Zero)
142 throw new InvalidOperationException ("Process has not been started.");
145 throw new InvalidOperationException ("The process must exit before " +
146 "getting the requested information.");
148 return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
152 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
153 [MonitoringDescription ("Handle for this process.")]
154 public IntPtr Handle {
156 if (process_handle == IntPtr.Zero)
157 throw new InvalidOperationException ("No process is associated with this object.");
158 return(process_handle);
163 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
164 [MonitoringDescription ("Handles for this process.")]
165 public int HandleCount {
171 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
172 [MonitoringDescription ("Determines if the process is still running.")]
173 public bool HasExited {
175 if (process_handle == IntPtr.Zero)
176 throw new InvalidOperationException ("Process has not been started.");
178 int exitcode = ExitCode_internal (process_handle);
189 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
190 [MonitoringDescription ("Process identifier.")]
194 throw new InvalidOperationException ("Process ID has not been set.");
201 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
202 [MonitoringDescription ("The name of the computer running the process.")]
203 public string MachineName {
209 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
210 [MonitoringDescription ("The main module of the process.")]
211 public ProcessModule MainModule {
213 return(this.Modules[0]);
218 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
219 [MonitoringDescription ("The handle of the main window of the process.")]
220 public IntPtr MainWindowHandle {
227 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
228 [MonitoringDescription ("The title of the main window of the process.")]
229 public string MainWindowTitle {
235 [MethodImplAttribute(MethodImplOptions.InternalCall)]
236 private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
237 [MethodImplAttribute(MethodImplOptions.InternalCall)]
238 private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);
240 /* LAMESPEC: why is this an IntPtr not a plain int? */
241 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
242 [MonitoringDescription ("The maximum working set for this process.")]
243 public IntPtr MaxWorkingSet {
246 throw new InvalidOperationException(
247 "The process " + ProcessName +
248 " (ID " + Id + ") has exited");
252 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
254 throw new Win32Exception();
261 throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
264 bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
266 throw new Win32Exception();
271 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
272 [MonitoringDescription ("The minimum working set for this process.")]
273 public IntPtr MinWorkingSet {
276 throw new InvalidOperationException(
277 "The process " + ProcessName +
278 " (ID " + Id + ") has exited");
282 bool ok= GetWorkingSet_internal (process_handle, out min, out max);
284 throw new Win32Exception();
285 return ((IntPtr) min);
289 throw new InvalidOperationException(
290 "The process " + ProcessName +
291 " (ID " + Id + ") has exited");
293 bool ok = SetWorkingSet_internal (process_handle, value.ToInt32(), 0, true);
295 throw new Win32Exception();
299 /* Returns the list of process modules. The main module is
302 [MethodImplAttribute(MethodImplOptions.InternalCall)]
303 private extern ProcessModule[] GetModules_internal(IntPtr handle);
305 private ProcessModuleCollection module_collection;
307 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
308 [MonitoringDescription ("The modules that are loaded as part of this process.")]
309 public ProcessModuleCollection Modules {
311 if (module_collection == null)
312 module_collection = new ProcessModuleCollection(
313 GetModules_internal (process_handle));
314 return(module_collection);
318 /* data type is from the MonoProcessData enum in mono-proclib.h in the runtime */
319 [MethodImplAttribute(MethodImplOptions.InternalCall)]
320 private extern static long GetProcessData (int pid, int data_type, out int error);
323 [Obsolete ("Use NonpagedSystemMemorySize64")]
324 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
325 [MonitoringDescription ("The number of bytes that are not pageable.")]
326 public int NonpagedSystemMemorySize {
332 [Obsolete ("Use PagedMemorySize64")]
333 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
334 [MonitoringDescription ("The number of bytes that are paged.")]
335 public int PagedMemorySize {
337 return(int)PagedMemorySize64;
341 [Obsolete ("Use PagedSystemMemorySize64")]
342 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
343 [MonitoringDescription ("The amount of paged system memory in bytes.")]
344 public int PagedSystemMemorySize {
346 return(int)PagedMemorySize64;
351 [Obsolete ("Use PeakPagedMemorySize64")]
352 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
353 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
354 public int PeakPagedMemorySize {
360 [Obsolete ("Use PeakVirtualMemorySize64")]
361 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
362 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
363 public int PeakVirtualMemorySize {
366 return (int)GetProcessData (pid, 8, out error);
370 [Obsolete ("Use PeakWorkingSet64")]
371 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
372 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
373 public int PeakWorkingSet {
376 return (int)GetProcessData (pid, 5, out error);
381 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
382 [MonitoringDescription ("The number of bytes that are not pageable.")]
384 public long NonpagedSystemMemorySize64 {
390 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
391 [MonitoringDescription ("The number of bytes that are paged.")]
393 public long PagedMemorySize64 {
396 return GetProcessData (pid, 12, out error);
400 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
401 [MonitoringDescription ("The amount of paged system memory in bytes.")]
403 public long PagedSystemMemorySize64 {
405 return PagedMemorySize64;
410 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
411 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
413 public long PeakPagedMemorySize64 {
419 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
420 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
422 public long PeakVirtualMemorySize64 {
425 return GetProcessData (pid, 8, out error);
429 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
430 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
432 public long PeakWorkingSet64 {
435 return GetProcessData (pid, 5, out error);
440 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
441 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
442 public bool PriorityBoostEnabled {
450 [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
451 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
452 [MonitoringDescription ("The relative process priority.")]
453 public ProcessPriorityClass PriorityClass {
455 if (process_handle == IntPtr.Zero)
456 throw new InvalidOperationException ("Process has not been started.");
459 int prio = GetPriorityClass (process_handle, out error);
461 throw new Win32Exception (error);
462 return (ProcessPriorityClass) prio;
465 if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
466 throw new InvalidEnumArgumentException (
467 "value", (int) value,
468 typeof (ProcessPriorityClass));
470 if (process_handle == IntPtr.Zero)
471 throw new InvalidOperationException ("Process has not been started.");
474 if (!SetPriorityClass (process_handle, (int) value, out error)) {
476 throw new Win32Exception (error);
481 void CheckExited () {
483 throw new InvalidOperationException (String.Format ("Cannot process request because the process ({0}) has exited.", Id));
486 [MethodImplAttribute(MethodImplOptions.InternalCall)]
487 static extern int GetPriorityClass (IntPtr handle, out int error);
489 [MethodImplAttribute(MethodImplOptions.InternalCall)]
490 static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);
492 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
493 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
494 [Obsolete ("Use PrivateMemorySize64")]
495 public int PrivateMemorySize {
498 return (int)GetProcessData (pid, 6, out error);
502 [MonoNotSupported ("")]
503 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
504 [MonitoringDescription ("The session ID for this process.")]
505 public int SessionId {
506 get { throw new NotImplementedException (); }
509 /* the meaning of type is as follows: 0: user, 1: system, 2: total */
510 [MethodImplAttribute(MethodImplOptions.InternalCall)]
511 private extern static long Times (IntPtr handle, int type);
513 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
514 [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
515 public TimeSpan PrivilegedProcessorTime {
517 return new TimeSpan (Times (process_handle, 1));
521 [MethodImplAttribute(MethodImplOptions.InternalCall)]
522 private extern static string ProcessName_internal(IntPtr handle);
524 private string process_name=null;
526 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
527 [MonitoringDescription ("The name of this process.")]
528 public string ProcessName {
530 if(process_name==null) {
532 if (process_handle == IntPtr.Zero)
533 throw new InvalidOperationException ("No process is associated with this object.");
535 process_name=ProcessName_internal(process_handle);
536 /* If process_name is _still_
537 * null, assume the process
540 if (process_name == null)
541 throw new InvalidOperationException ("Process has exited, so the requested information is not available.");
543 /* Strip the suffix (if it
544 * exists) simplistically
545 * instead of removing any
546 * trailing \.???, so we dont
547 * get stupid results on sane
550 if(process_name.EndsWith(".exe") ||
551 process_name.EndsWith(".bat") ||
552 process_name.EndsWith(".com")) {
553 process_name=process_name.Substring(0, process_name.Length-4);
556 return(process_name);
561 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
562 [MonitoringDescription ("Allowed processor that can be used by this process.")]
563 public IntPtr ProcessorAffinity {
572 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
573 [MonitoringDescription ("Is this process responsive.")]
574 public bool Responding {
580 #if MONO_FEATURE_PROCESS_START
581 private StreamReader error_stream=null;
582 bool error_stream_exposed;
584 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
585 [MonitoringDescription ("The standard error stream of this process.")]
586 public StreamReader StandardError {
588 if (error_stream == null)
589 throw new InvalidOperationException("Standard error has not been redirected");
591 if ((async_mode & AsyncModes.AsyncError) != 0)
592 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
594 async_mode |= AsyncModes.SyncError;
596 error_stream_exposed = true;
597 return(error_stream);
601 private StreamWriter input_stream=null;
602 bool input_stream_exposed;
604 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
605 [MonitoringDescription ("The standard input stream of this process.")]
606 public StreamWriter StandardInput {
608 if (input_stream == null)
609 throw new InvalidOperationException("Standard input has not been redirected");
611 input_stream_exposed = true;
612 return(input_stream);
616 private StreamReader output_stream=null;
617 bool output_stream_exposed;
619 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
620 [MonitoringDescription ("The standard output stream of this process.")]
621 public StreamReader StandardOutput {
623 if (output_stream == null)
624 throw new InvalidOperationException("Standard output has not been redirected");
626 if ((async_mode & AsyncModes.AsyncOutput) != 0)
627 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
629 async_mode |= AsyncModes.SyncOutput;
631 output_stream_exposed = true;
632 return(output_stream);
636 private ProcessStartInfo start_info=null;
638 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
639 [MonitoringDescription ("Information for the start of this process.")]
640 public ProcessStartInfo StartInfo {
642 if (start_info == null)
643 start_info = new ProcessStartInfo();
648 throw new ArgumentNullException("value");
653 [Obsolete ("Process.StandardError is not supported on the current platform.", true)]
654 public StreamReader StandardError {
655 get { throw new PlatformNotSupportedException ("Process.StandardError is not supported on the current platform."); }
658 [Obsolete ("Process.StandardInput is not supported on the current platform.", true)]
659 public StreamWriter StandardInput {
660 get { throw new PlatformNotSupportedException ("Process.StandardInput is not supported on the current platform."); }
663 [Obsolete ("Process.StandardOutput is not supported on the current platform.", true)]
664 public StreamReader StandardOutput {
665 get { throw new PlatformNotSupportedException ("Process.StandardOutput is not supported on the current platform."); }
668 [Obsolete ("Process.StartInfo is not supported on the current platform.", true)]
669 public ProcessStartInfo StartInfo {
670 get { throw new PlatformNotSupportedException ("Process.StartInfo is not supported on the current platform."); }
671 set { throw new PlatformNotSupportedException ("Process.StartInfo is not supported on the current platform."); }
673 #endif // MONO_FEATURE_PROCESS_START
675 /* Returns the process start time in Windows file
676 * times (ticks from DateTime(1/1/1601 00:00 GMT))
678 [MethodImplAttribute(MethodImplOptions.InternalCall)]
679 private extern static long StartTime_internal(IntPtr handle);
681 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
682 [MonitoringDescription ("The time this process started.")]
683 public DateTime StartTime {
685 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
689 [DefaultValue (null), Browsable (false)]
690 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
691 public ISynchronizeInvoke SynchronizingObject {
692 get { return synchronizingObject; }
693 set { synchronizingObject = value; }
697 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
698 [MonitoringDescription ("The number of threads of this process.")]
699 public ProcessThreadCollection Threads {
701 // This'll return a correctly-sized array of empty ProcessThreads for now.
703 return new ProcessThreadCollection(new ProcessThread[GetProcessData (pid, 0, out error)]);
707 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
708 [MonitoringDescription ("The total CPU time spent for this process.")]
709 public TimeSpan TotalProcessorTime {
711 return new TimeSpan (Times (process_handle, 2));
715 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
716 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
717 public TimeSpan UserProcessorTime {
719 return new TimeSpan (Times (process_handle, 0));
723 [Obsolete ("Use VirtualMemorySize64")]
724 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
725 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
726 public int VirtualMemorySize {
729 return (int)GetProcessData (pid, 7, out error);
733 [Obsolete ("Use WorkingSet64")]
734 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
735 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
736 public int WorkingSet {
739 return (int)GetProcessData (pid, 4, out error);
743 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
744 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
746 public long PrivateMemorySize64 {
749 return GetProcessData (pid, 6, out error);
753 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
754 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
756 public long VirtualMemorySize64 {
759 return GetProcessData (pid, 7, out error);
763 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
764 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
766 public long WorkingSet64 {
769 return GetProcessData (pid, 4, out error);
778 [MethodImplAttribute(MethodImplOptions.InternalCall)]
779 extern static bool Kill_internal (IntPtr handle, int signo);
781 /* int kill -> 1 KILL, 2 CloseMainWindow */
782 bool Close (int signo)
784 if (process_handle == IntPtr.Zero)
785 throw new SystemException ("No process to kill.");
787 int exitcode = ExitCode_internal (process_handle);
789 throw new InvalidOperationException ("The process already finished.");
791 return Kill_internal (process_handle, signo);
794 public bool CloseMainWindow ()
800 public static void EnterDebugMode() {
803 [MethodImplAttribute(MethodImplOptions.InternalCall)]
804 private extern static IntPtr GetProcess_internal(int pid);
806 [MethodImplAttribute(MethodImplOptions.InternalCall)]
807 private extern static int GetPid_internal();
809 public static Process GetCurrentProcess()
811 int pid = GetPid_internal();
812 IntPtr proc = GetProcess_internal(pid);
814 if (proc == IntPtr.Zero)
815 throw new SystemException("Can't find current process");
817 return (new Process (proc, pid));
820 public static Process GetProcessById(int processId)
822 IntPtr proc = GetProcess_internal(processId);
824 if (proc == IntPtr.Zero)
825 throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
827 return (new Process (proc, processId));
830 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
831 public static Process GetProcessById(int processId, string machineName) {
832 if (machineName == null)
833 throw new ArgumentNullException ("machineName");
835 if (!IsLocalMachine (machineName))
836 throw new NotImplementedException ();
838 return GetProcessById (processId);
841 [MethodImplAttribute(MethodImplOptions.InternalCall)]
842 private extern static int[] GetProcesses_internal();
844 public static Process[] GetProcesses ()
846 int [] pids = GetProcesses_internal ();
848 return new Process [0];
850 var proclist = new List<Process> (pids.Length);
851 for (int i = 0; i < pids.Length; i++) {
853 proclist.Add (GetProcessById (pids [i]));
854 } catch (SystemException) {
855 /* The process might exit
857 * GetProcesses_internal and
863 return proclist.ToArray ();
866 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
867 public static Process[] GetProcesses(string machineName) {
868 if (machineName == null)
869 throw new ArgumentNullException ("machineName");
871 if (!IsLocalMachine (machineName))
872 throw new NotImplementedException ();
874 return GetProcesses ();
877 public static Process[] GetProcessesByName(string processName)
879 int [] pids = GetProcesses_internal ();
881 return new Process [0];
883 var proclist = new List<Process> (pids.Length);
884 for (int i = 0; i < pids.Length; i++) {
886 Process p = GetProcessById (pids [i]);
887 if (String.Compare (processName, p.ProcessName, true) == 0)
889 } catch (SystemException) {
890 /* The process might exit
892 * GetProcesses_internal and
898 return proclist.ToArray ();
902 public static Process[] GetProcessesByName(string processName, string machineName) {
903 throw new NotImplementedException();
912 public static void LeaveDebugMode() {
915 public void Refresh ()
917 // FIXME: should refresh any cached data we might have about
918 // the process (currently we have none).
921 #if MONO_FEATURE_PROCESS_START
922 [MethodImplAttribute(MethodImplOptions.InternalCall)]
923 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
924 ref ProcInfo proc_info);
926 [MethodImplAttribute(MethodImplOptions.InternalCall)]
927 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
931 ref ProcInfo proc_info);
933 private static bool Start_shell (ProcessStartInfo startInfo, Process process)
935 ProcInfo proc_info=new ProcInfo();
938 if (startInfo.RedirectStandardInput ||
939 startInfo.RedirectStandardOutput ||
940 startInfo.RedirectStandardError) {
941 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
944 if (startInfo.HaveEnvVars)
945 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
947 FillUserInfo (startInfo, ref proc_info);
949 ret = ShellExecuteEx_internal (startInfo,
952 if (proc_info.Password != IntPtr.Zero)
953 Marshal.ZeroFreeBSTR (proc_info.Password);
954 proc_info.Password = IntPtr.Zero;
957 throw new Win32Exception (-proc_info.pid);
960 process.process_handle = proc_info.process_handle;
961 process.pid = proc_info.pid;
962 process.StartBackgroundWaitForExit ();
967 // Creates a pipe with read and write descriptors
969 static void CreatePipe (out IntPtr read, out IntPtr write, bool writeDirection)
974 // Creates read/write pipe from parent -> child perspective
975 // a child process uses same descriptors after fork. That's
976 // 4 descriptors in total where only 2. One in child, one in parent
977 // should be active and the other 2 closed. Which ones depends on
978 // comunication direction
980 // parent --------> child (parent can write, child can read)
982 // read: closed read: used
983 // write: used write: closed
986 // parent <-------- child (parent can read, child can write)
988 // read: used read: closed
989 // write: closed write: used
991 // It can still be tricky for predefined descriptiors http://unixwiz.net/techtips/remap-pipe-fds.html
993 if (!MonoIO.CreatePipe (out read, out write, out error))
994 throw MonoIO.GetException (error);
997 const int DUPLICATE_SAME_ACCESS = 0x00000002;
998 var tmp = writeDirection ? write : read;
1000 if (!MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, tmp, Process.GetCurrentProcess ().Handle, out tmp, 0, 0, DUPLICATE_SAME_ACCESS, out error))
1001 throw MonoIO.GetException (error);
1003 if (writeDirection) {
1004 if (!MonoIO.Close (write, out error))
1005 throw MonoIO.GetException (error);
1008 if (!MonoIO.Close (read, out error))
1009 throw MonoIO.GetException (error);
1015 static bool Start_noshell (ProcessStartInfo startInfo, Process process)
1017 var proc_info = new ProcInfo ();
1019 if (startInfo.HaveEnvVars) {
1020 string [] strs = new string [startInfo.EnvironmentVariables.Count];
1021 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
1022 proc_info.envKeys = strs;
1024 strs = new string [startInfo.EnvironmentVariables.Count];
1025 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
1026 proc_info.envValues = strs;
1030 IntPtr stdin_read = IntPtr.Zero, stdin_write = IntPtr.Zero;
1031 IntPtr stdout_read = IntPtr.Zero, stdout_write = IntPtr.Zero;
1032 IntPtr stderr_read = IntPtr.Zero, stderr_write = IntPtr.Zero;
1035 if (startInfo.RedirectStandardInput) {
1036 CreatePipe (out stdin_read, out stdin_write, true);
1038 stdin_read = MonoIO.ConsoleInput;
1039 stdin_write = IntPtr.Zero;
1042 if (startInfo.RedirectStandardOutput) {
1043 CreatePipe (out stdout_read, out stdout_write, false);
1045 stdout_read = IntPtr.Zero;
1046 stdout_write = MonoIO.ConsoleOutput;
1049 if (startInfo.RedirectStandardError) {
1050 CreatePipe (out stderr_read, out stderr_write, false);
1052 stderr_read = IntPtr.Zero;
1053 stderr_write = MonoIO.ConsoleError;
1056 FillUserInfo (startInfo, ref proc_info);
1059 // FIXME: For redirected pipes we need to send descriptors of
1060 // stdin_write, stdout_read, stderr_read to child process and
1061 // close them there (fork makes exact copy of parent's descriptors)
1063 if (!CreateProcess_internal (startInfo, stdin_read, stdout_write, stderr_write, ref proc_info)) {
1064 throw new Win32Exception (-proc_info.pid,
1065 "ApplicationName='" + startInfo.FileName +
1066 "', CommandLine='" + startInfo.Arguments +
1067 "', CurrentDirectory='" + startInfo.WorkingDirectory +
1068 "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
1071 if (startInfo.RedirectStandardInput) {
1072 if (stdin_read != IntPtr.Zero)
1073 MonoIO.Close (stdin_read, out error);
1074 if (stdin_write != IntPtr.Zero)
1075 MonoIO.Close (stdin_write, out error);
1078 if (startInfo.RedirectStandardOutput) {
1079 if (stdout_read != IntPtr.Zero)
1080 MonoIO.Close (stdout_read, out error);
1081 if (stdout_write != IntPtr.Zero)
1082 MonoIO.Close (stdout_write, out error);
1085 if (startInfo.RedirectStandardError) {
1086 if (stderr_read != IntPtr.Zero)
1087 MonoIO.Close (stderr_read, out error);
1088 if (stderr_write != IntPtr.Zero)
1089 MonoIO.Close (stderr_write, out error);
1094 if (proc_info.Password != IntPtr.Zero) {
1095 Marshal.ZeroFreeBSTR (proc_info.Password);
1096 proc_info.Password = IntPtr.Zero;
1100 process.process_handle = proc_info.process_handle;
1101 process.pid = proc_info.pid;
1103 if (startInfo.RedirectStandardInput) {
1105 // FIXME: The descriptor needs to be closed but due to wapi io-layer
1106 // not coping with duplicated descriptors any StandardInput write fails
1108 // MonoIO.Close (stdin_read, out error);
1111 var stdinEncoding = Encoding.Default;
1113 var stdinEncoding = Console.InputEncoding;
1115 process.input_stream = new StreamWriter (new FileStream (stdin_write, FileAccess.Write, true, 8192), stdinEncoding) {
1120 if (startInfo.RedirectStandardOutput) {
1121 MonoIO.Close (stdout_write, out error);
1123 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1125 process.output_stream = new StreamReader (new FileStream (stdout_read, FileAccess.Read, true, 8192), stdoutEncoding, true);
1128 if (startInfo.RedirectStandardError) {
1129 MonoIO.Close (stderr_write, out error);
1131 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1133 process.error_stream = new StreamReader (new FileStream (stderr_read, FileAccess.Read, true, 8192), stderrEncoding, true);
1136 process.StartBackgroundWaitForExit ();
1141 // Note that ProcInfo.Password must be freed.
1142 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1144 if (startInfo.UserName.Length != 0) {
1145 proc_info.UserName = startInfo.UserName;
1146 proc_info.Domain = startInfo.Domain;
1147 if (startInfo.Password != null)
1148 proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1150 proc_info.Password = IntPtr.Zero;
1151 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1155 private static bool Start_common (ProcessStartInfo startInfo,
1158 if (startInfo.FileName.Length == 0)
1159 throw new InvalidOperationException("File name has not been set");
1161 if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1162 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1163 if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1164 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1166 if (startInfo.UseShellExecute) {
1167 if (startInfo.UserName.Length != 0)
1168 throw new InvalidOperationException ("UseShellExecute must be false if an explicit UserName is specified when starting a process");
1169 return (Start_shell (startInfo, process));
1171 return (Start_noshell (startInfo, process));
1175 public bool Start ()
1177 if (process_handle != IntPtr.Zero) {
1178 Process_free_internal (process_handle);
1179 process_handle = IntPtr.Zero;
1181 return Start_common(start_info, this);
1184 public static Process Start (ProcessStartInfo startInfo)
1186 if (startInfo == null)
1187 throw new ArgumentNullException ("startInfo");
1189 Process process = new Process();
1190 process.StartInfo = startInfo;
1191 if (Start_common(startInfo, process) && process.process_handle != IntPtr.Zero)
1196 public static Process Start (string fileName)
1198 return Start (new ProcessStartInfo (fileName));
1201 public static Process Start(string fileName, string arguments)
1203 return Start (new ProcessStartInfo (fileName, arguments));
1206 public static Process Start(string fileName, string username, SecureString password, string domain) {
1207 return Start(fileName, null, username, password, domain);
1210 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1211 ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1212 psi.UserName = username;
1213 psi.Password = password;
1214 psi.Domain = domain;
1215 psi.UseShellExecute = false;
1219 [Obsolete ("Process.Start is not supported on the current platform.", true)]
1220 public bool Start ()
1222 throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
1225 [Obsolete ("Process.Start is not supported on the current platform.", true)]
1226 public static Process Start (ProcessStartInfo startInfo)
1228 throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
1231 [Obsolete ("Process.Start is not supported on the current platform.", true)]
1232 public static Process Start (string fileName)
1234 throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
1237 [Obsolete ("Process.Start is not supported on the current platform.", true)]
1238 public static Process Start(string fileName, string arguments)
1240 throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
1243 [Obsolete ("Process.Start is not supported on the current platform.", true)]
1244 public static Process Start(string fileName, string username, SecureString password, string domain)
1246 throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
1249 [Obsolete ("Process.Start is not supported on the current platform.", true)]
1250 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain)
1252 throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
1254 #endif // MONO_FEATURE_PROCESS_START
1256 public override string ToString()
1258 return(base.ToString() + " (" + this.ProcessName + ")");
1261 /* Waits up to ms milliseconds for process 'handle' to
1262 * exit. ms can be <0 to mean wait forever.
1264 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1265 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1267 public void WaitForExit ()
1272 public bool WaitForExit(int milliseconds) {
1273 int ms = milliseconds;
1274 if (ms == int.MaxValue)
1277 if (process_handle == IntPtr.Zero)
1278 throw new InvalidOperationException ("No process is associated with this object.");
1280 if (!WaitForExit_internal (process_handle, ms))
1283 #if MONO_FEATURE_PROCESS_START
1284 if (async_output != null && !async_output.IsCompleted)
1285 async_output.AsyncWaitHandle.WaitOne ();
1287 if (async_error != null && !async_error.IsCompleted)
1288 async_error.AsyncWaitHandle.WaitOne ();
1289 #endif // MONO_FEATURE_PROCESS_START
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 DataReceivedEventHandler cb = OutputDataReceived;
1333 cb (this, new DataReceivedEventArgs (str));
1336 void OnErrorDataReceived (string str)
1338 DataReceivedEventHandler cb = ErrorDataReceived;
1340 cb (this, new DataReceivedEventArgs (str));
1343 #if MONO_FEATURE_PROCESS_START
1349 AsyncOutput = 1 << 2,
1353 [StructLayout (LayoutKind.Sequential)]
1354 sealed class ProcessAsyncReader : IOAsyncResult
1361 StringBuilder sb = new StringBuilder ();
1362 byte[] buffer = new byte [4096];
1364 const int ERROR_INVALID_HANDLE = 6;
1366 public ProcessAsyncReader (Process process, FileStream stream, bool err_out)
1369 this.process = process;
1370 this.handle = stream.SafeFileHandle.DangerousGetHandle ();
1371 this.stream = stream;
1372 this.err_out = err_out;
1375 public void BeginReadLine ()
1377 IOSelector.Add (this.handle, new IOSelectorJob (IOOperation.Read, _ => Read (), null));
1385 nread = stream.Read (buffer, 0, buffer.Length);
1386 } catch (ObjectDisposedException) {
1387 } catch (IOException ex) {
1388 if (ex.HResult != (unchecked((int) 0x80070000) | (int) ERROR_INVALID_HANDLE))
1390 } catch (NotSupportedException) {
1399 process.OnOutputDataReceived (null);
1401 process.OnErrorDataReceived (null);
1409 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1411 // Just in case the encoding fails...
1412 for (int i = 0; i < nread; i++) {
1413 sb.Append ((char) buffer [i]);
1419 IOSelector.Add (this.handle, new IOSelectorJob (IOOperation.Read, _ => Read (), null));
1422 void Flush (bool last)
1424 if (sb.Length == 0 || (err_out && process.output_canceled) || (!err_out && process.error_canceled))
1427 string[] strs = sb.ToString ().Split ('\n');
1431 if (strs.Length == 0)
1434 for (int i = 0; i < strs.Length - 1; i++) {
1436 process.OnOutputDataReceived (strs [i]);
1438 process.OnErrorDataReceived (strs [i]);
1441 string end = strs [strs.Length - 1];
1442 if (last || (strs.Length == 1 && end == "")) {
1444 process.OnOutputDataReceived (end);
1446 process.OnErrorDataReceived (end);
1452 public void Close ()
1454 IOSelector.Remove (handle);
1457 internal override void CompleteDisposed ()
1459 throw new NotSupportedException ();
1463 AsyncModes async_mode;
1464 bool output_canceled;
1465 bool error_canceled;
1466 ProcessAsyncReader async_output;
1467 ProcessAsyncReader async_error;
1469 [ComVisibleAttribute(false)]
1470 public void BeginOutputReadLine ()
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 ("Cannot mix asynchronous and synchonous reads.");
1478 async_mode |= AsyncModes.AsyncOutput;
1479 output_canceled = false;
1480 if (async_output == null) {
1481 async_output = new ProcessAsyncReader (this, (FileStream) output_stream.BaseStream, true);
1482 async_output.BeginReadLine ();
1486 [ComVisibleAttribute(false)]
1487 public void CancelOutputRead ()
1489 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1490 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1492 if ((async_mode & AsyncModes.SyncOutput) != 0)
1493 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1495 if (async_output == null)
1496 throw new InvalidOperationException ("No async operation in progress.");
1498 output_canceled = true;
1501 [ComVisibleAttribute(false)]
1502 public void BeginErrorReadLine ()
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.SyncError) != 0)
1508 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1510 async_mode |= AsyncModes.AsyncError;
1511 error_canceled = false;
1512 if (async_error == null) {
1513 async_error = new ProcessAsyncReader (this, (FileStream) error_stream.BaseStream, false);
1514 async_error.BeginReadLine ();
1518 [ComVisibleAttribute(false)]
1519 public void CancelErrorRead ()
1521 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1522 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1524 if ((async_mode & AsyncModes.SyncOutput) != 0)
1525 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1527 if (async_error == null)
1528 throw new InvalidOperationException ("No async operation in progress.");
1530 error_canceled = true;
1533 [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
1534 public void BeginOutputReadLine ()
1536 throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
1539 [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
1540 public void CancelOutputRead ()
1542 throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
1545 [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
1546 public void BeginErrorReadLine ()
1548 throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
1551 [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
1552 public void CancelErrorRead ()
1554 throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
1556 #endif // MONO_FEATURE_PROCESS_START
1558 [Category ("Behavior")]
1559 [MonitoringDescription ("Raised when this process exits.")]
1560 public event EventHandler Exited {
1562 if (process_handle != IntPtr.Zero && HasExited) {
1563 value.BeginInvoke (null, null, null, null);
1565 exited_event += value;
1566 if (exited_event != null)
1567 StartBackgroundWaitForExit ();
1571 exited_event -= value;
1575 // Closes the system process handle
1576 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1577 private extern void Process_free_internal(IntPtr handle);
1581 protected override void Dispose(bool disposing) {
1582 // Check to see if Dispose has already been called.
1583 if (disposed != 0 || Interlocked.CompareExchange (ref disposed, 1, 0) != 0)
1586 // If this is a call to Dispose,
1587 // dispose all managed resources.
1589 #if MONO_FEATURE_PROCESS_START
1590 /* These have open FileStreams on the pipes we are about to close */
1591 if (async_output != null)
1592 async_output.Close ();
1593 if (async_error != null)
1594 async_error.Close ();
1596 if (input_stream != null) {
1597 if (!input_stream_exposed)
1598 input_stream.Close ();
1599 input_stream = null;
1601 if (output_stream != null) {
1602 if (!output_stream_exposed)
1603 output_stream.Close ();
1604 output_stream = null;
1606 if (error_stream != null) {
1607 if (!error_stream_exposed)
1608 error_stream.Close ();
1609 error_stream = null;
1611 #endif // MONO_FEATURE_PROCESS_START
1614 // Release unmanaged resources
1616 if (process_handle!=IntPtr.Zero) {
1617 Process_free_internal (process_handle);
1618 process_handle = IntPtr.Zero;
1621 base.Dispose (disposing);
1629 int on_exited_called = 0;
1631 protected void OnExited()
1633 if (on_exited_called != 0 || Interlocked.CompareExchange (ref on_exited_called, 1, 0) != 0)
1636 var cb = exited_event;
1640 if (synchronizingObject != null) {
1641 synchronizingObject.BeginInvoke (cb, new object [] { this, EventArgs.Empty });
1643 foreach (EventHandler d in cb.GetInvocationList ()) {
1645 d (this, EventArgs.Empty);
1652 static bool IsWindows
1656 PlatformID platform = Environment.OSVersion.Platform;
1657 if (platform == PlatformID.Win32S ||
1658 platform == PlatformID.Win32Windows ||
1659 platform == PlatformID.Win32NT ||
1660 platform == PlatformID.WinCE) {
1667 void StartBackgroundWaitForExit ()
1669 if (enable_raising_events == 0)
1671 if (exited_event == null)
1673 if (process_handle == IntPtr.Zero)
1675 if (background_wait_for_exit_thread != null)
1678 Thread t = new Thread (_ => WaitForExit ()) { IsBackground = true };
1680 if (Interlocked.CompareExchange (ref background_wait_for_exit_thread, t, null) == null)
1684 class ProcessWaitHandle : WaitHandle
1686 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1687 private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1689 public ProcessWaitHandle (IntPtr handle)
1691 // Need to keep a reference to this handle,
1692 // in case the Process object is collected
1693 Handle = ProcessHandle_duplicate (handle);
1695 // When the wait handle is disposed, the duplicated handle will be
1696 // closed, so no need to override dispose (bug #464628).