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;
86 /* Private constructor called from other methods */
87 private Process(IntPtr handle, int id) {
88 process_handle = handle;
97 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
98 [MonitoringDescription ("Base process priority.")]
99 public int BasePriority {
103 [DefaultValue (false), Browsable (false)]
104 [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
105 public bool EnableRaisingEvents {
107 return enable_raising_events == 1;
110 if (value && Interlocked.Exchange (ref enable_raising_events, 1) == 0)
111 StartBackgroundWaitForExit ();
115 [MethodImplAttribute(MethodImplOptions.InternalCall)]
116 private extern static int ExitCode_internal(IntPtr handle);
118 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
119 [MonitoringDescription ("The exit code of the process.")]
120 public int ExitCode {
122 if (process_handle == IntPtr.Zero)
123 throw new InvalidOperationException ("Process has not been started.");
125 int code = ExitCode_internal (process_handle);
127 throw new InvalidOperationException ("The process must exit before getting the requested information.");
133 /* Returns the process start time in Windows file
134 * times (ticks from DateTime(1/1/1601 00:00 GMT))
136 [MethodImplAttribute(MethodImplOptions.InternalCall)]
137 private extern static long ExitTime_internal(IntPtr handle);
139 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
140 [MonitoringDescription ("The exit time of the process.")]
141 public DateTime ExitTime {
143 if (process_handle == IntPtr.Zero)
144 throw new InvalidOperationException ("Process has not been started.");
147 throw new InvalidOperationException ("The process must exit before " +
148 "getting the requested information.");
150 return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
154 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
155 [MonitoringDescription ("Handle for this process.")]
156 public IntPtr Handle {
158 if (process_handle == IntPtr.Zero)
159 throw new InvalidOperationException ("No process is associated with this object.");
160 return(process_handle);
165 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
166 [MonitoringDescription ("Handles for this process.")]
167 public int HandleCount {
173 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
174 [MonitoringDescription ("Determines if the process is still running.")]
175 public bool HasExited {
177 if (process_handle == IntPtr.Zero)
178 throw new InvalidOperationException ("Process has not been started.");
180 int exitcode = ExitCode_internal (process_handle);
191 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
192 [MonitoringDescription ("Process identifier.")]
196 throw new InvalidOperationException ("Process ID has not been set.");
203 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
204 [MonitoringDescription ("The name of the computer running the process.")]
205 public string MachineName {
211 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
212 [MonitoringDescription ("The main module of the process.")]
213 public ProcessModule MainModule {
215 return(this.Modules[0]);
220 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
221 [MonitoringDescription ("The handle of the main window of the process.")]
222 public IntPtr MainWindowHandle {
229 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
230 [MonitoringDescription ("The title of the main window of the process.")]
231 public string MainWindowTitle {
237 [MethodImplAttribute(MethodImplOptions.InternalCall)]
238 private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
239 [MethodImplAttribute(MethodImplOptions.InternalCall)]
240 private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);
242 /* LAMESPEC: why is this an IntPtr not a plain int? */
243 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
244 [MonitoringDescription ("The maximum working set for this process.")]
245 public IntPtr MaxWorkingSet {
248 throw new InvalidOperationException(
249 "The process " + ProcessName +
250 " (ID " + Id + ") has exited");
254 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
256 throw new Win32Exception();
263 throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
266 bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
268 throw new Win32Exception();
273 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
274 [MonitoringDescription ("The minimum working set for this process.")]
275 public IntPtr MinWorkingSet {
278 throw new InvalidOperationException(
279 "The process " + ProcessName +
280 " (ID " + Id + ") has exited");
284 bool ok= GetWorkingSet_internal (process_handle, out min, out max);
286 throw new Win32Exception();
287 return ((IntPtr) min);
291 throw new InvalidOperationException(
292 "The process " + ProcessName +
293 " (ID " + Id + ") has exited");
295 bool ok = SetWorkingSet_internal (process_handle, value.ToInt32(), 0, true);
297 throw new Win32Exception();
301 /* Returns the list of process modules. The main module is
304 [MethodImplAttribute(MethodImplOptions.InternalCall)]
305 private extern ProcessModule[] GetModules_internal(IntPtr handle);
307 private ProcessModuleCollection module_collection;
309 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
310 [MonitoringDescription ("The modules that are loaded as part of this process.")]
311 public ProcessModuleCollection Modules {
313 if (module_collection == null)
314 module_collection = new ProcessModuleCollection(
315 GetModules_internal (process_handle));
316 return(module_collection);
320 /* data type is from the MonoProcessData enum in mono-proclib.h in the runtime */
321 [MethodImplAttribute(MethodImplOptions.InternalCall)]
322 private extern static long GetProcessData (int pid, int data_type, out int error);
325 [Obsolete ("Use NonpagedSystemMemorySize64")]
326 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
327 [MonitoringDescription ("The number of bytes that are not pageable.")]
328 public int NonpagedSystemMemorySize {
334 [Obsolete ("Use PagedMemorySize64")]
335 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
336 [MonitoringDescription ("The number of bytes that are paged.")]
337 public int PagedMemorySize {
339 return(int)PagedMemorySize64;
343 [Obsolete ("Use PagedSystemMemorySize64")]
344 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
345 [MonitoringDescription ("The amount of paged system memory in bytes.")]
346 public int PagedSystemMemorySize {
348 return(int)PagedMemorySize64;
353 [Obsolete ("Use PeakPagedMemorySize64")]
354 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
355 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
356 public int PeakPagedMemorySize {
362 [Obsolete ("Use PeakVirtualMemorySize64")]
363 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
364 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
365 public int PeakVirtualMemorySize {
368 return (int)GetProcessData (pid, 8, out error);
372 [Obsolete ("Use PeakWorkingSet64")]
373 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
374 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
375 public int PeakWorkingSet {
378 return (int)GetProcessData (pid, 5, out error);
383 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
384 [MonitoringDescription ("The number of bytes that are not pageable.")]
386 public long NonpagedSystemMemorySize64 {
392 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
393 [MonitoringDescription ("The number of bytes that are paged.")]
395 public long PagedMemorySize64 {
398 return GetProcessData (pid, 12, out error);
402 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
403 [MonitoringDescription ("The amount of paged system memory in bytes.")]
405 public long PagedSystemMemorySize64 {
407 return PagedMemorySize64;
412 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
413 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
415 public long PeakPagedMemorySize64 {
421 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
422 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
424 public long PeakVirtualMemorySize64 {
427 return GetProcessData (pid, 8, out error);
431 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
432 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
434 public long PeakWorkingSet64 {
437 return GetProcessData (pid, 5, out error);
442 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
443 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
444 public bool PriorityBoostEnabled {
452 [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
453 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
454 [MonitoringDescription ("The relative process priority.")]
455 public ProcessPriorityClass PriorityClass {
457 if (process_handle == IntPtr.Zero)
458 throw new InvalidOperationException ("Process has not been started.");
461 int prio = GetPriorityClass (process_handle, out error);
463 throw new Win32Exception (error);
464 return (ProcessPriorityClass) prio;
467 if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
468 throw new InvalidEnumArgumentException (
469 "value", (int) value,
470 typeof (ProcessPriorityClass));
472 if (process_handle == IntPtr.Zero)
473 throw new InvalidOperationException ("Process has not been started.");
476 if (!SetPriorityClass (process_handle, (int) value, out error)) {
478 throw new Win32Exception (error);
483 void CheckExited () {
485 throw new InvalidOperationException (String.Format ("Cannot process request because the process ({0}) has exited.", Id));
488 [MethodImplAttribute(MethodImplOptions.InternalCall)]
489 static extern int GetPriorityClass (IntPtr handle, out int error);
491 [MethodImplAttribute(MethodImplOptions.InternalCall)]
492 static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);
494 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
495 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
496 [Obsolete ("Use PrivateMemorySize64")]
497 public int PrivateMemorySize {
500 return (int)GetProcessData (pid, 6, out error);
504 [MonoNotSupported ("")]
505 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
506 [MonitoringDescription ("The session ID for this process.")]
507 public int SessionId {
508 get { throw new NotImplementedException (); }
511 /* the meaning of type is as follows: 0: user, 1: system, 2: total */
512 [MethodImplAttribute(MethodImplOptions.InternalCall)]
513 private extern static long Times (IntPtr handle, int type);
515 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
516 [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
517 public TimeSpan PrivilegedProcessorTime {
519 return new TimeSpan (Times (process_handle, 1));
523 [MethodImplAttribute(MethodImplOptions.InternalCall)]
524 private extern static string ProcessName_internal(IntPtr handle);
526 private string process_name=null;
528 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
529 [MonitoringDescription ("The name of this process.")]
530 public string ProcessName {
532 if(process_name==null) {
534 if (process_handle == IntPtr.Zero)
535 throw new InvalidOperationException ("No process is associated with this object.");
537 process_name=ProcessName_internal(process_handle);
538 /* If process_name is _still_
539 * null, assume the process
542 if (process_name == null)
543 throw new InvalidOperationException ("Process has exited, so the requested information is not available.");
545 /* Strip the suffix (if it
546 * exists) simplistically
547 * instead of removing any
548 * trailing \.???, so we dont
549 * get stupid results on sane
552 if(process_name.EndsWith(".exe") ||
553 process_name.EndsWith(".bat") ||
554 process_name.EndsWith(".com")) {
555 process_name=process_name.Substring(0, process_name.Length-4);
558 return(process_name);
563 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
564 [MonitoringDescription ("Allowed processor that can be used by this process.")]
565 public IntPtr ProcessorAffinity {
574 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
575 [MonitoringDescription ("Is this process responsive.")]
576 public bool Responding {
582 private StreamReader error_stream=null;
583 bool error_stream_exposed;
585 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
586 [MonitoringDescription ("The standard error stream of this process.")]
587 public StreamReader StandardError {
589 if (error_stream == null)
590 throw new InvalidOperationException("Standard error has not been redirected");
592 if ((async_mode & AsyncModes.AsyncError) != 0)
593 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
595 async_mode |= AsyncModes.SyncError;
597 error_stream_exposed = true;
598 return(error_stream);
602 private StreamWriter input_stream=null;
603 bool input_stream_exposed;
605 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
606 [MonitoringDescription ("The standard input stream of this process.")]
607 public StreamWriter StandardInput {
609 if (input_stream == null)
610 throw new InvalidOperationException("Standard input has not been redirected");
612 input_stream_exposed = true;
613 return(input_stream);
617 private StreamReader output_stream=null;
618 bool output_stream_exposed;
620 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
621 [MonitoringDescription ("The standard output stream of this process.")]
622 public StreamReader StandardOutput {
624 if (output_stream == null)
625 throw new InvalidOperationException("Standard output has not been redirected");
627 if ((async_mode & AsyncModes.AsyncOutput) != 0)
628 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
630 async_mode |= AsyncModes.SyncOutput;
632 output_stream_exposed = true;
633 return(output_stream);
637 private ProcessStartInfo start_info=null;
639 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
640 [MonitoringDescription ("Information for the start of this process.")]
641 public ProcessStartInfo StartInfo {
643 if (start_info == null)
644 start_info = new ProcessStartInfo();
649 throw new ArgumentNullException("value");
654 /* Returns the process start time in Windows file
655 * times (ticks from DateTime(1/1/1601 00:00 GMT))
657 [MethodImplAttribute(MethodImplOptions.InternalCall)]
658 private extern static long StartTime_internal(IntPtr handle);
660 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
661 [MonitoringDescription ("The time this process started.")]
662 public DateTime StartTime {
664 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
668 [DefaultValue (null), Browsable (false)]
669 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
670 public ISynchronizeInvoke SynchronizingObject {
671 get { return synchronizingObject; }
672 set { synchronizingObject = value; }
676 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
677 [MonitoringDescription ("The number of threads of this process.")]
678 public ProcessThreadCollection Threads {
680 // This'll return a correctly-sized array of empty ProcessThreads for now.
682 return new ProcessThreadCollection(new ProcessThread[GetProcessData (pid, 0, out error)]);
686 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
687 [MonitoringDescription ("The total CPU time spent for this process.")]
688 public TimeSpan TotalProcessorTime {
690 return new TimeSpan (Times (process_handle, 2));
694 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
695 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
696 public TimeSpan UserProcessorTime {
698 return new TimeSpan (Times (process_handle, 0));
702 [Obsolete ("Use VirtualMemorySize64")]
703 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
704 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
705 public int VirtualMemorySize {
708 return (int)GetProcessData (pid, 7, out error);
712 [Obsolete ("Use WorkingSet64")]
713 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
714 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
715 public int WorkingSet {
718 return (int)GetProcessData (pid, 4, out error);
722 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
723 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
725 public long PrivateMemorySize64 {
728 return GetProcessData (pid, 6, out error);
732 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
733 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
735 public long VirtualMemorySize64 {
738 return GetProcessData (pid, 7, out error);
742 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
743 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
745 public long WorkingSet64 {
748 return GetProcessData (pid, 4, out error);
757 [MethodImplAttribute(MethodImplOptions.InternalCall)]
758 extern static bool Kill_internal (IntPtr handle, int signo);
760 /* int kill -> 1 KILL, 2 CloseMainWindow */
761 bool Close (int signo)
763 if (process_handle == IntPtr.Zero)
764 throw new SystemException ("No process to kill.");
766 int exitcode = ExitCode_internal (process_handle);
768 throw new InvalidOperationException ("The process already finished.");
770 return Kill_internal (process_handle, signo);
773 public bool CloseMainWindow ()
779 public static void EnterDebugMode() {
782 [MethodImplAttribute(MethodImplOptions.InternalCall)]
783 private extern static IntPtr GetProcess_internal(int pid);
785 [MethodImplAttribute(MethodImplOptions.InternalCall)]
786 private extern static int GetPid_internal();
788 public static Process GetCurrentProcess()
790 int pid = GetPid_internal();
791 IntPtr proc = GetProcess_internal(pid);
793 if (proc == IntPtr.Zero)
794 throw new SystemException("Can't find current process");
796 return (new Process (proc, pid));
799 public static Process GetProcessById(int processId)
801 IntPtr proc = GetProcess_internal(processId);
803 if (proc == IntPtr.Zero)
804 throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
806 return (new Process (proc, processId));
809 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
810 public static Process GetProcessById(int processId, string machineName) {
811 if (machineName == null)
812 throw new ArgumentNullException ("machineName");
814 if (!IsLocalMachine (machineName))
815 throw new NotImplementedException ();
817 return GetProcessById (processId);
820 [MethodImplAttribute(MethodImplOptions.InternalCall)]
821 private extern static int[] GetProcesses_internal();
823 public static Process[] GetProcesses ()
825 int [] pids = GetProcesses_internal ();
827 return new Process [0];
829 var proclist = new List<Process> (pids.Length);
830 for (int i = 0; i < pids.Length; i++) {
832 proclist.Add (GetProcessById (pids [i]));
833 } catch (SystemException) {
834 /* The process might exit
836 * GetProcesses_internal and
842 return proclist.ToArray ();
845 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
846 public static Process[] GetProcesses(string machineName) {
847 if (machineName == null)
848 throw new ArgumentNullException ("machineName");
850 if (!IsLocalMachine (machineName))
851 throw new NotImplementedException ();
853 return GetProcesses ();
856 public static Process[] GetProcessesByName(string processName)
858 int [] pids = GetProcesses_internal ();
860 return new Process [0];
862 var proclist = new List<Process> (pids.Length);
863 for (int i = 0; i < pids.Length; i++) {
865 Process p = GetProcessById (pids [i]);
866 if (String.Compare (processName, p.ProcessName, true) == 0)
868 } catch (SystemException) {
869 /* The process might exit
871 * GetProcesses_internal and
877 return proclist.ToArray ();
881 public static Process[] GetProcessesByName(string processName, string machineName) {
882 throw new NotImplementedException();
891 public static void LeaveDebugMode() {
894 public void Refresh ()
896 // FIXME: should refresh any cached data we might have about
897 // the process (currently we have none).
900 [MethodImplAttribute(MethodImplOptions.InternalCall)]
901 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
902 ref ProcInfo proc_info);
904 [MethodImplAttribute(MethodImplOptions.InternalCall)]
905 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
909 ref ProcInfo proc_info);
911 private static bool Start_shell (ProcessStartInfo startInfo, Process process)
913 ProcInfo proc_info=new ProcInfo();
916 if (startInfo.RedirectStandardInput ||
917 startInfo.RedirectStandardOutput ||
918 startInfo.RedirectStandardError) {
919 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
922 if (startInfo.HaveEnvVars)
923 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
925 FillUserInfo (startInfo, ref proc_info);
927 ret = ShellExecuteEx_internal (startInfo,
930 if (proc_info.Password != IntPtr.Zero)
931 Marshal.ZeroFreeBSTR (proc_info.Password);
932 proc_info.Password = IntPtr.Zero;
935 throw new Win32Exception (-proc_info.pid);
938 process.process_handle = proc_info.process_handle;
939 process.pid = proc_info.pid;
940 process.StartBackgroundWaitForExit ();
945 // Creates a pipe with read and write descriptors
947 static void CreatePipe (out IntPtr read, out IntPtr write, bool writeDirection)
952 // Creates read/write pipe from parent -> child perspective
953 // a child process uses same descriptors after fork. That's
954 // 4 descriptors in total where only 2. One in child, one in parent
955 // should be active and the other 2 closed. Which ones depends on
956 // comunication direction
958 // parent --------> child (parent can write, child can read)
960 // read: closed read: used
961 // write: used write: closed
964 // parent <-------- child (parent can read, child can write)
966 // read: used read: closed
967 // write: closed write: used
969 // It can still be tricky for predefined descriptiors http://unixwiz.net/techtips/remap-pipe-fds.html
971 if (!MonoIO.CreatePipe (out read, out write, out error))
972 throw MonoIO.GetException (error);
975 const int DUPLICATE_SAME_ACCESS = 0x00000002;
976 var tmp = writeDirection ? write : read;
978 if (!MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, tmp, Process.GetCurrentProcess ().Handle, out tmp, 0, 0, DUPLICATE_SAME_ACCESS, out error))
979 throw MonoIO.GetException (error);
981 if (writeDirection) {
982 if (!MonoIO.Close (write, out error))
983 throw MonoIO.GetException (error);
986 if (!MonoIO.Close (read, out error))
987 throw MonoIO.GetException (error);
993 static bool Start_noshell (ProcessStartInfo startInfo, Process process)
995 var proc_info = new ProcInfo ();
997 if (startInfo.HaveEnvVars) {
998 string [] strs = new string [startInfo.EnvironmentVariables.Count];
999 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
1000 proc_info.envKeys = strs;
1002 strs = new string [startInfo.EnvironmentVariables.Count];
1003 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
1004 proc_info.envValues = strs;
1008 IntPtr stdin_read = IntPtr.Zero, stdin_write = IntPtr.Zero;
1009 IntPtr stdout_read = IntPtr.Zero, stdout_write = IntPtr.Zero;
1010 IntPtr stderr_read = IntPtr.Zero, stderr_write = IntPtr.Zero;
1013 if (startInfo.RedirectStandardInput) {
1014 CreatePipe (out stdin_read, out stdin_write, true);
1016 stdin_read = MonoIO.ConsoleInput;
1017 stdin_write = IntPtr.Zero;
1020 if (startInfo.RedirectStandardOutput) {
1021 CreatePipe (out stdout_read, out stdout_write, false);
1022 process.stdout_rd = stdout_read;
1024 process.stdout_rd = IntPtr.Zero;
1025 stdout_write = MonoIO.ConsoleOutput;
1028 if (startInfo.RedirectStandardError) {
1029 CreatePipe (out stderr_read, out stderr_write, false);
1030 process.stderr_rd = stderr_read;
1032 process.stderr_rd = IntPtr.Zero;
1033 stderr_write = MonoIO.ConsoleError;
1036 FillUserInfo (startInfo, ref proc_info);
1039 // FIXME: For redirected pipes we need to send descriptors of
1040 // stdin_write, stdout_read, stderr_read to child process and
1041 // close them there (fork makes exact copy of parent's descriptors)
1043 if (!CreateProcess_internal (startInfo, stdin_read, stdout_write, stderr_write, ref proc_info)) {
1044 throw new Win32Exception (-proc_info.pid,
1045 "ApplicationName='" + startInfo.FileName +
1046 "', CommandLine='" + startInfo.Arguments +
1047 "', CurrentDirectory='" + startInfo.WorkingDirectory +
1048 "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
1051 if (startInfo.RedirectStandardInput) {
1052 if (stdin_read != IntPtr.Zero)
1053 MonoIO.Close (stdin_read, out error);
1054 if (stdin_write != IntPtr.Zero)
1055 MonoIO.Close (stdin_write, out error);
1058 if (startInfo.RedirectStandardOutput) {
1059 if (stdout_read != IntPtr.Zero)
1060 MonoIO.Close (stdout_read, out error);
1061 if (stdout_write != IntPtr.Zero)
1062 MonoIO.Close (stdout_write, out error);
1065 if (startInfo.RedirectStandardError) {
1066 if (stderr_read != IntPtr.Zero)
1067 MonoIO.Close (stderr_read, out error);
1068 if (stderr_write != IntPtr.Zero)
1069 MonoIO.Close (stderr_write, out error);
1074 if (proc_info.Password != IntPtr.Zero) {
1075 Marshal.ZeroFreeBSTR (proc_info.Password);
1076 proc_info.Password = IntPtr.Zero;
1080 process.process_handle = proc_info.process_handle;
1081 process.pid = proc_info.pid;
1083 if (startInfo.RedirectStandardInput) {
1085 // FIXME: The descriptor needs to be closed but due to wapi io-layer
1086 // not coping with duplicated descriptors any StandardInput write fails
1088 // MonoIO.Close (stdin_read, out error);
1091 var stdinEncoding = Encoding.Default;
1093 var stdinEncoding = Console.InputEncoding;
1095 process.input_stream = new StreamWriter (new FileStream (new SafeFileHandle (stdin_write, false), FileAccess.Write, 8192, false), stdinEncoding) {
1100 if (startInfo.RedirectStandardOutput) {
1101 MonoIO.Close (stdout_write, out error);
1103 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.OutputEncoding;
1105 process.output_stream = new StreamReader (new FileStream (new SafeFileHandle (stdout_read, false), FileAccess.Read, 8192, false), stdoutEncoding, true, 8192);
1108 if (startInfo.RedirectStandardError) {
1109 MonoIO.Close (stderr_write, out error);
1111 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.OutputEncoding;
1113 process.error_stream = new StreamReader (new FileStream (new SafeFileHandle (stderr_read, false), FileAccess.Read, 8192, false), stderrEncoding, true, 8192);
1116 process.StartBackgroundWaitForExit ();
1121 // Note that ProcInfo.Password must be freed.
1122 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1124 if (startInfo.UserName.Length != 0) {
1125 proc_info.UserName = startInfo.UserName;
1126 proc_info.Domain = startInfo.Domain;
1127 if (startInfo.Password != null)
1128 proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1130 proc_info.Password = IntPtr.Zero;
1131 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1135 private static bool Start_common (ProcessStartInfo startInfo,
1138 if (startInfo.FileName.Length == 0)
1139 throw new InvalidOperationException("File name has not been set");
1141 if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1142 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1143 if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1144 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1146 if (startInfo.UseShellExecute) {
1147 if (startInfo.UserName.Length != 0)
1148 throw new InvalidOperationException ("UseShellExecute must be false if an explicit UserName is specified when starting a process");
1149 return (Start_shell (startInfo, process));
1151 return (Start_noshell (startInfo, process));
1155 public bool Start ()
1157 if (process_handle != IntPtr.Zero) {
1158 Process_free_internal (process_handle);
1159 process_handle = IntPtr.Zero;
1161 return Start_common(start_info, this);
1164 public static Process Start (ProcessStartInfo startInfo)
1166 if (startInfo == null)
1167 throw new ArgumentNullException ("startInfo");
1169 Process process = new Process();
1170 process.StartInfo = startInfo;
1171 if (Start_common(startInfo, process) && process.process_handle != IntPtr.Zero)
1176 public static Process Start (string fileName)
1178 return Start (new ProcessStartInfo (fileName));
1181 public static Process Start(string fileName, string arguments)
1183 return Start (new ProcessStartInfo (fileName, arguments));
1186 public static Process Start(string fileName, string username, SecureString password, string domain) {
1187 return Start(fileName, null, username, password, domain);
1190 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1191 ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1192 psi.UserName = username;
1193 psi.Password = password;
1194 psi.Domain = domain;
1195 psi.UseShellExecute = false;
1199 public override string ToString()
1201 return(base.ToString() + " (" + this.ProcessName + ")");
1204 /* Waits up to ms milliseconds for process 'handle' to
1205 * exit. ms can be <0 to mean wait forever.
1207 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1208 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1210 public void WaitForExit ()
1215 public bool WaitForExit(int milliseconds) {
1216 int ms = milliseconds;
1217 if (ms == int.MaxValue)
1220 if (process_handle == IntPtr.Zero)
1221 throw new InvalidOperationException ("No process is associated with this object.");
1223 DateTime start = DateTime.UtcNow;
1225 if (!WaitForExit_internal (process_handle, ms))
1229 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1234 if (async_output != null && !async_output.IsCompleted) {
1235 if (false == async_output.AsyncWaitHandle.WaitOne (ms, false))
1236 return false; // Timed out
1239 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1245 if (async_error != null && !async_error.IsCompleted) {
1246 if (false == async_error.AsyncWaitHandle.WaitOne (ms, false))
1247 return false; // Timed out
1250 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1261 /* Waits up to ms milliseconds for process 'handle' to
1262 * wait for input. ms can be <0 to mean wait forever.
1264 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1265 private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
1267 // The internal call is only implemented properly on Windows.
1269 public bool WaitForInputIdle() {
1270 return WaitForInputIdle (-1);
1273 // The internal call is only implemented properly on Windows.
1275 public bool WaitForInputIdle(int milliseconds) {
1276 return WaitForInputIdle_internal (process_handle, milliseconds);
1279 private static bool IsLocalMachine (string machineName)
1281 if (machineName == "." || machineName.Length == 0)
1284 return (string.Compare (machineName, Environment.MachineName, true) == 0);
1288 [MonitoringDescription ("Raised when it receives output data")]
1289 public event DataReceivedEventHandler OutputDataReceived;
1291 [MonitoringDescription ("Raised when it receives error data")]
1292 public event DataReceivedEventHandler ErrorDataReceived;
1294 void OnOutputDataReceived (string str)
1296 DataReceivedEventHandler cb = OutputDataReceived;
1298 cb (this, new DataReceivedEventArgs (str));
1301 void OnErrorDataReceived (string str)
1303 DataReceivedEventHandler cb = ErrorDataReceived;
1305 cb (this, new DataReceivedEventArgs (str));
1313 AsyncOutput = 1 << 2,
1317 [StructLayout (LayoutKind.Sequential)]
1318 sealed class ProcessAsyncReader : IOAsyncResult
1325 StringBuilder sb = new StringBuilder ();
1326 byte[] buffer = new byte [4096];
1328 public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1331 this.process = process;
1332 this.handle = handle;
1333 this.stream = new FileStream (handle, FileAccess.Read, false);
1334 this.err_out = err_out;
1337 public void BeginRead ()
1339 IOSelector.Add (this.handle, new IOSelectorJob (IOOperation.Read, _ => AddInput (), null));
1342 public void AddInput ()
1347 nread = stream.Read (buffer, 0, buffer.Length);
1348 } catch (ObjectDisposedException) {
1349 } catch (NotSupportedException) {
1358 process.OnOutputDataReceived (null);
1360 process.OnErrorDataReceived (null);
1368 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1370 // Just in case the encoding fails...
1371 for (int i = 0; i < nread; i++) {
1372 sb.Append ((char) buffer [i]);
1378 IOSelector.Add (this.handle, new IOSelectorJob (IOOperation.Read, _ => AddInput (), null));
1381 void Flush (bool last)
1383 if (sb.Length == 0 || (err_out && process.output_canceled) || (!err_out && process.error_canceled))
1386 string[] strs = sb.ToString ().Split ('\n');
1390 if (strs.Length == 0)
1393 for (int i = 0; i < strs.Length - 1; i++) {
1395 process.OnOutputDataReceived (strs [i]);
1397 process.OnErrorDataReceived (strs [i]);
1400 string end = strs [strs.Length - 1];
1401 if (last || (strs.Length == 1 && end == "")) {
1403 process.OnOutputDataReceived (end);
1405 process.OnErrorDataReceived (end);
1411 public void Close ()
1413 IOSelector.Remove (handle);
1417 internal override void CompleteDisposed ()
1419 throw new NotSupportedException ();
1423 AsyncModes async_mode;
1424 bool output_canceled;
1425 bool error_canceled;
1426 ProcessAsyncReader async_output;
1427 ProcessAsyncReader async_error;
1429 [ComVisibleAttribute(false)]
1430 public void BeginOutputReadLine ()
1432 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1433 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1435 if ((async_mode & AsyncModes.SyncOutput) != 0)
1436 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1438 async_mode |= AsyncModes.AsyncOutput;
1439 output_canceled = false;
1440 if (async_output == null) {
1441 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1442 async_output.BeginRead ();
1446 [ComVisibleAttribute(false)]
1447 public void CancelOutputRead ()
1449 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1450 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1452 if ((async_mode & AsyncModes.SyncOutput) != 0)
1453 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1455 if (async_output == null)
1456 throw new InvalidOperationException ("No async operation in progress.");
1458 output_canceled = true;
1461 [ComVisibleAttribute(false)]
1462 public void BeginErrorReadLine ()
1464 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1465 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1467 if ((async_mode & AsyncModes.SyncError) != 0)
1468 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1470 async_mode |= AsyncModes.AsyncError;
1471 error_canceled = false;
1472 if (async_error == null) {
1473 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1474 async_error.BeginRead ();
1478 [ComVisibleAttribute(false)]
1479 public void CancelErrorRead ()
1481 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1482 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1484 if ((async_mode & AsyncModes.SyncOutput) != 0)
1485 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1487 if (async_error == null)
1488 throw new InvalidOperationException ("No async operation in progress.");
1490 error_canceled = true;
1493 [Category ("Behavior")]
1494 [MonitoringDescription ("Raised when this process exits.")]
1495 public event EventHandler Exited {
1497 if (process_handle != IntPtr.Zero && HasExited) {
1498 value.BeginInvoke (null, null, null, null);
1500 exited_event += value;
1501 if (exited_event != null)
1502 StartBackgroundWaitForExit ();
1506 exited_event -= value;
1510 // Closes the system process handle
1511 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1512 private extern void Process_free_internal(IntPtr handle);
1516 protected override void Dispose(bool disposing) {
1517 // Check to see if Dispose has already been called.
1518 if (disposed != 0 || Interlocked.CompareExchange (ref disposed, 1, 0) != 0)
1521 // If this is a call to Dispose,
1522 // dispose all managed resources.
1524 /* These have open FileStreams on the pipes we are about to close */
1525 if (async_output != null)
1526 async_output.Close ();
1527 if (async_error != null)
1528 async_error.Close ();
1530 if (input_stream != null) {
1531 if (!input_stream_exposed)
1532 input_stream.Close ();
1533 input_stream = null;
1535 if (output_stream != null) {
1536 if (!output_stream_exposed)
1537 output_stream.Close ();
1538 output_stream = null;
1540 if (error_stream != null) {
1541 if (!error_stream_exposed)
1542 error_stream.Close ();
1543 error_stream = null;
1547 // Release unmanaged resources
1549 if (process_handle!=IntPtr.Zero) {
1550 Process_free_internal (process_handle);
1551 process_handle = IntPtr.Zero;
1554 base.Dispose (disposing);
1562 int on_exited_called = 0;
1564 protected void OnExited()
1566 if (on_exited_called != 0 || Interlocked.CompareExchange (ref on_exited_called, 1, 0) != 0)
1569 var cb = exited_event;
1573 if (synchronizingObject != null) {
1574 synchronizingObject.BeginInvoke (cb, new object [] { this, EventArgs.Empty });
1576 foreach (EventHandler d in cb.GetInvocationList ()) {
1578 d (this, EventArgs.Empty);
1585 static bool IsWindows
1589 PlatformID platform = Environment.OSVersion.Platform;
1590 if (platform == PlatformID.Win32S ||
1591 platform == PlatformID.Win32Windows ||
1592 platform == PlatformID.Win32NT ||
1593 platform == PlatformID.WinCE) {
1600 void StartBackgroundWaitForExit ()
1602 if (enable_raising_events == 0)
1604 if (exited_event == null)
1606 if (process_handle == IntPtr.Zero)
1608 if (background_wait_for_exit_thread != null)
1611 Thread t = new Thread (_ => WaitForExit ());
1613 if (Interlocked.CompareExchange (ref background_wait_for_exit_thread, t, null) == null)
1617 class ProcessWaitHandle : WaitHandle
1619 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1620 private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1622 public ProcessWaitHandle (IntPtr handle)
1624 // Need to keep a reference to this handle,
1625 // in case the Process object is collected
1626 Handle = ProcessHandle_duplicate (handle);
1628 // When the wait handle is disposed, the duplicated handle will be
1629 // closed, so no need to override dispose (bug #464628).