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 private StreamReader error_stream=null;
581 bool error_stream_exposed;
583 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
584 [MonitoringDescription ("The standard error stream of this process.")]
585 public StreamReader StandardError {
587 if (error_stream == null)
588 throw new InvalidOperationException("Standard error has not been redirected");
590 if ((async_mode & AsyncModes.AsyncError) != 0)
591 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
593 async_mode |= AsyncModes.SyncError;
595 error_stream_exposed = true;
596 return(error_stream);
600 private StreamWriter input_stream=null;
601 bool input_stream_exposed;
603 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
604 [MonitoringDescription ("The standard input stream of this process.")]
605 public StreamWriter StandardInput {
607 if (input_stream == null)
608 throw new InvalidOperationException("Standard input has not been redirected");
610 input_stream_exposed = true;
611 return(input_stream);
615 private StreamReader output_stream=null;
616 bool output_stream_exposed;
618 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
619 [MonitoringDescription ("The standard output stream of this process.")]
620 public StreamReader StandardOutput {
622 if (output_stream == null)
623 throw new InvalidOperationException("Standard output has not been redirected");
625 if ((async_mode & AsyncModes.AsyncOutput) != 0)
626 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
628 async_mode |= AsyncModes.SyncOutput;
630 output_stream_exposed = true;
631 return(output_stream);
635 private ProcessStartInfo start_info=null;
637 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
638 [MonitoringDescription ("Information for the start of this process.")]
639 public ProcessStartInfo StartInfo {
641 if (start_info == null)
642 start_info = new ProcessStartInfo();
647 throw new ArgumentNullException("value");
652 /* Returns the process start time in Windows file
653 * times (ticks from DateTime(1/1/1601 00:00 GMT))
655 [MethodImplAttribute(MethodImplOptions.InternalCall)]
656 private extern static long StartTime_internal(IntPtr handle);
658 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
659 [MonitoringDescription ("The time this process started.")]
660 public DateTime StartTime {
662 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
666 [DefaultValue (null), Browsable (false)]
667 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
668 public ISynchronizeInvoke SynchronizingObject {
669 get { return synchronizingObject; }
670 set { synchronizingObject = value; }
674 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
675 [MonitoringDescription ("The number of threads of this process.")]
676 public ProcessThreadCollection Threads {
678 // This'll return a correctly-sized array of empty ProcessThreads for now.
680 return new ProcessThreadCollection(new ProcessThread[GetProcessData (pid, 0, out error)]);
684 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
685 [MonitoringDescription ("The total CPU time spent for this process.")]
686 public TimeSpan TotalProcessorTime {
688 return new TimeSpan (Times (process_handle, 2));
692 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
693 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
694 public TimeSpan UserProcessorTime {
696 return new TimeSpan (Times (process_handle, 0));
700 [Obsolete ("Use VirtualMemorySize64")]
701 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
702 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
703 public int VirtualMemorySize {
706 return (int)GetProcessData (pid, 7, out error);
710 [Obsolete ("Use WorkingSet64")]
711 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
712 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
713 public int WorkingSet {
716 return (int)GetProcessData (pid, 4, out error);
720 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
721 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
723 public long PrivateMemorySize64 {
726 return GetProcessData (pid, 6, out error);
730 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
731 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
733 public long VirtualMemorySize64 {
736 return GetProcessData (pid, 7, out error);
740 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
741 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
743 public long WorkingSet64 {
746 return GetProcessData (pid, 4, out error);
755 [MethodImplAttribute(MethodImplOptions.InternalCall)]
756 extern static bool Kill_internal (IntPtr handle, int signo);
758 /* int kill -> 1 KILL, 2 CloseMainWindow */
759 bool Close (int signo)
761 if (process_handle == IntPtr.Zero)
762 throw new SystemException ("No process to kill.");
764 int exitcode = ExitCode_internal (process_handle);
766 throw new InvalidOperationException ("The process already finished.");
768 return Kill_internal (process_handle, signo);
771 public bool CloseMainWindow ()
777 public static void EnterDebugMode() {
780 [MethodImplAttribute(MethodImplOptions.InternalCall)]
781 private extern static IntPtr GetProcess_internal(int pid);
783 [MethodImplAttribute(MethodImplOptions.InternalCall)]
784 private extern static int GetPid_internal();
786 public static Process GetCurrentProcess()
788 int pid = GetPid_internal();
789 IntPtr proc = GetProcess_internal(pid);
791 if (proc == IntPtr.Zero)
792 throw new SystemException("Can't find current process");
794 return (new Process (proc, pid));
797 public static Process GetProcessById(int processId)
799 IntPtr proc = GetProcess_internal(processId);
801 if (proc == IntPtr.Zero)
802 throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
804 return (new Process (proc, processId));
807 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
808 public static Process GetProcessById(int processId, string machineName) {
809 if (machineName == null)
810 throw new ArgumentNullException ("machineName");
812 if (!IsLocalMachine (machineName))
813 throw new NotImplementedException ();
815 return GetProcessById (processId);
818 [MethodImplAttribute(MethodImplOptions.InternalCall)]
819 private extern static int[] GetProcesses_internal();
821 public static Process[] GetProcesses ()
823 int [] pids = GetProcesses_internal ();
825 return new Process [0];
827 var proclist = new List<Process> (pids.Length);
828 for (int i = 0; i < pids.Length; i++) {
830 proclist.Add (GetProcessById (pids [i]));
831 } catch (SystemException) {
832 /* The process might exit
834 * GetProcesses_internal and
840 return proclist.ToArray ();
843 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
844 public static Process[] GetProcesses(string machineName) {
845 if (machineName == null)
846 throw new ArgumentNullException ("machineName");
848 if (!IsLocalMachine (machineName))
849 throw new NotImplementedException ();
851 return GetProcesses ();
854 public static Process[] GetProcessesByName(string processName)
856 int [] pids = GetProcesses_internal ();
858 return new Process [0];
860 var proclist = new List<Process> (pids.Length);
861 for (int i = 0; i < pids.Length; i++) {
863 Process p = GetProcessById (pids [i]);
864 if (String.Compare (processName, p.ProcessName, true) == 0)
866 } catch (SystemException) {
867 /* The process might exit
869 * GetProcesses_internal and
875 return proclist.ToArray ();
879 public static Process[] GetProcessesByName(string processName, string machineName) {
880 throw new NotImplementedException();
889 public static void LeaveDebugMode() {
892 public void Refresh ()
894 // FIXME: should refresh any cached data we might have about
895 // the process (currently we have none).
898 [MethodImplAttribute(MethodImplOptions.InternalCall)]
899 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
900 ref ProcInfo proc_info);
902 [MethodImplAttribute(MethodImplOptions.InternalCall)]
903 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
907 ref ProcInfo proc_info);
909 private static bool Start_shell (ProcessStartInfo startInfo, Process process)
911 ProcInfo proc_info=new ProcInfo();
914 if (startInfo.RedirectStandardInput ||
915 startInfo.RedirectStandardOutput ||
916 startInfo.RedirectStandardError) {
917 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
920 if (startInfo.HaveEnvVars)
921 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
923 FillUserInfo (startInfo, ref proc_info);
925 ret = ShellExecuteEx_internal (startInfo,
928 if (proc_info.Password != IntPtr.Zero)
929 Marshal.ZeroFreeBSTR (proc_info.Password);
930 proc_info.Password = IntPtr.Zero;
933 throw new Win32Exception (-proc_info.pid);
936 process.process_handle = proc_info.process_handle;
937 process.pid = proc_info.pid;
938 process.StartBackgroundWaitForExit ();
943 // Creates a pipe with read and write descriptors
945 static void CreatePipe (out IntPtr read, out IntPtr write, bool writeDirection)
950 // Creates read/write pipe from parent -> child perspective
951 // a child process uses same descriptors after fork. That's
952 // 4 descriptors in total where only 2. One in child, one in parent
953 // should be active and the other 2 closed. Which ones depends on
954 // comunication direction
956 // parent --------> child (parent can write, child can read)
958 // read: closed read: used
959 // write: used write: closed
962 // parent <-------- child (parent can read, child can write)
964 // read: used read: closed
965 // write: closed write: used
967 // It can still be tricky for predefined descriptiors http://unixwiz.net/techtips/remap-pipe-fds.html
969 if (!MonoIO.CreatePipe (out read, out write, out error))
970 throw MonoIO.GetException (error);
973 const int DUPLICATE_SAME_ACCESS = 0x00000002;
974 var tmp = writeDirection ? write : read;
976 if (!MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, tmp, Process.GetCurrentProcess ().Handle, out tmp, 0, 0, DUPLICATE_SAME_ACCESS, out error))
977 throw MonoIO.GetException (error);
979 if (writeDirection) {
980 if (!MonoIO.Close (write, out error))
981 throw MonoIO.GetException (error);
984 if (!MonoIO.Close (read, out error))
985 throw MonoIO.GetException (error);
991 static bool Start_noshell (ProcessStartInfo startInfo, Process process)
993 var proc_info = new ProcInfo ();
995 if (startInfo.HaveEnvVars) {
996 string [] strs = new string [startInfo.EnvironmentVariables.Count];
997 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
998 proc_info.envKeys = strs;
1000 strs = new string [startInfo.EnvironmentVariables.Count];
1001 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
1002 proc_info.envValues = strs;
1006 IntPtr stdin_read = IntPtr.Zero, stdin_write = IntPtr.Zero;
1007 IntPtr stdout_read = IntPtr.Zero, stdout_write = IntPtr.Zero;
1008 IntPtr stderr_read = IntPtr.Zero, stderr_write = IntPtr.Zero;
1011 if (startInfo.RedirectStandardInput) {
1012 CreatePipe (out stdin_read, out stdin_write, true);
1014 stdin_read = MonoIO.ConsoleInput;
1015 stdin_write = IntPtr.Zero;
1018 if (startInfo.RedirectStandardOutput) {
1019 CreatePipe (out stdout_read, out stdout_write, false);
1021 stdout_read = IntPtr.Zero;
1022 stdout_write = MonoIO.ConsoleOutput;
1025 if (startInfo.RedirectStandardError) {
1026 CreatePipe (out stderr_read, out stderr_write, false);
1028 stderr_read = IntPtr.Zero;
1029 stderr_write = MonoIO.ConsoleError;
1032 FillUserInfo (startInfo, ref proc_info);
1035 // FIXME: For redirected pipes we need to send descriptors of
1036 // stdin_write, stdout_read, stderr_read to child process and
1037 // close them there (fork makes exact copy of parent's descriptors)
1039 if (!CreateProcess_internal (startInfo, stdin_read, stdout_write, stderr_write, ref proc_info)) {
1040 throw new Win32Exception (-proc_info.pid,
1041 "ApplicationName='" + startInfo.FileName +
1042 "', CommandLine='" + startInfo.Arguments +
1043 "', CurrentDirectory='" + startInfo.WorkingDirectory +
1044 "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
1047 if (startInfo.RedirectStandardInput) {
1048 if (stdin_read != IntPtr.Zero)
1049 MonoIO.Close (stdin_read, out error);
1050 if (stdin_write != IntPtr.Zero)
1051 MonoIO.Close (stdin_write, out error);
1054 if (startInfo.RedirectStandardOutput) {
1055 if (stdout_read != IntPtr.Zero)
1056 MonoIO.Close (stdout_read, out error);
1057 if (stdout_write != IntPtr.Zero)
1058 MonoIO.Close (stdout_write, out error);
1061 if (startInfo.RedirectStandardError) {
1062 if (stderr_read != IntPtr.Zero)
1063 MonoIO.Close (stderr_read, out error);
1064 if (stderr_write != IntPtr.Zero)
1065 MonoIO.Close (stderr_write, out error);
1070 if (proc_info.Password != IntPtr.Zero) {
1071 Marshal.ZeroFreeBSTR (proc_info.Password);
1072 proc_info.Password = IntPtr.Zero;
1076 process.process_handle = proc_info.process_handle;
1077 process.pid = proc_info.pid;
1079 if (startInfo.RedirectStandardInput) {
1081 // FIXME: The descriptor needs to be closed but due to wapi io-layer
1082 // not coping with duplicated descriptors any StandardInput write fails
1084 // MonoIO.Close (stdin_read, out error);
1087 var stdinEncoding = Encoding.Default;
1089 var stdinEncoding = Console.InputEncoding;
1091 process.input_stream = new StreamWriter (new FileStream (stdin_write, FileAccess.Write, true, 8192), stdinEncoding) {
1096 if (startInfo.RedirectStandardOutput) {
1097 MonoIO.Close (stdout_write, out error);
1099 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1101 process.output_stream = new StreamReader (new FileStream (stdout_read, FileAccess.Read, true, 8192), stdoutEncoding, true);
1104 if (startInfo.RedirectStandardError) {
1105 MonoIO.Close (stderr_write, out error);
1107 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1109 process.error_stream = new StreamReader (new FileStream (stderr_read, FileAccess.Read, true, 8192), stderrEncoding, true);
1112 process.StartBackgroundWaitForExit ();
1117 // Note that ProcInfo.Password must be freed.
1118 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1120 if (startInfo.UserName.Length != 0) {
1121 proc_info.UserName = startInfo.UserName;
1122 proc_info.Domain = startInfo.Domain;
1123 if (startInfo.Password != null)
1124 proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1126 proc_info.Password = IntPtr.Zero;
1127 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1131 private static bool Start_common (ProcessStartInfo startInfo,
1134 if (startInfo.FileName.Length == 0)
1135 throw new InvalidOperationException("File name has not been set");
1137 if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1138 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1139 if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1140 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1142 if (startInfo.UseShellExecute) {
1143 if (startInfo.UserName.Length != 0)
1144 throw new InvalidOperationException ("UseShellExecute must be false if an explicit UserName is specified when starting a process");
1145 return (Start_shell (startInfo, process));
1147 return (Start_noshell (startInfo, process));
1151 public bool Start ()
1153 if (process_handle != IntPtr.Zero) {
1154 Process_free_internal (process_handle);
1155 process_handle = IntPtr.Zero;
1157 return Start_common(start_info, this);
1160 public static Process Start (ProcessStartInfo startInfo)
1162 if (startInfo == null)
1163 throw new ArgumentNullException ("startInfo");
1165 Process process = new Process();
1166 process.StartInfo = startInfo;
1167 if (Start_common(startInfo, process) && process.process_handle != IntPtr.Zero)
1172 public static Process Start (string fileName)
1174 return Start (new ProcessStartInfo (fileName));
1177 public static Process Start(string fileName, string arguments)
1179 return Start (new ProcessStartInfo (fileName, arguments));
1182 public static Process Start(string fileName, string username, SecureString password, string domain) {
1183 return Start(fileName, null, username, password, domain);
1186 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1187 ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1188 psi.UserName = username;
1189 psi.Password = password;
1190 psi.Domain = domain;
1191 psi.UseShellExecute = false;
1195 public override string ToString()
1197 return(base.ToString() + " (" + this.ProcessName + ")");
1200 /* Waits up to ms milliseconds for process 'handle' to
1201 * exit. ms can be <0 to mean wait forever.
1203 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1204 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1206 public void WaitForExit ()
1211 public bool WaitForExit(int milliseconds) {
1212 int ms = milliseconds;
1213 if (ms == int.MaxValue)
1216 if (process_handle == IntPtr.Zero)
1217 throw new InvalidOperationException ("No process is associated with this object.");
1219 if (!WaitForExit_internal (process_handle, ms))
1222 if (async_output != null && !async_output.IsCompleted)
1223 async_output.AsyncWaitHandle.WaitOne ();
1225 if (async_error != null && !async_error.IsCompleted)
1226 async_error.AsyncWaitHandle.WaitOne ();
1233 /* Waits up to ms milliseconds for process 'handle' to
1234 * wait for input. ms can be <0 to mean wait forever.
1236 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1237 private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
1239 // The internal call is only implemented properly on Windows.
1241 public bool WaitForInputIdle() {
1242 return WaitForInputIdle (-1);
1245 // The internal call is only implemented properly on Windows.
1247 public bool WaitForInputIdle(int milliseconds) {
1248 return WaitForInputIdle_internal (process_handle, milliseconds);
1251 private static bool IsLocalMachine (string machineName)
1253 if (machineName == "." || machineName.Length == 0)
1256 return (string.Compare (machineName, Environment.MachineName, true) == 0);
1260 [MonitoringDescription ("Raised when it receives output data")]
1261 public event DataReceivedEventHandler OutputDataReceived;
1263 [MonitoringDescription ("Raised when it receives error data")]
1264 public event DataReceivedEventHandler ErrorDataReceived;
1266 void OnOutputDataReceived (string str)
1268 DataReceivedEventHandler cb = OutputDataReceived;
1270 cb (this, new DataReceivedEventArgs (str));
1273 void OnErrorDataReceived (string str)
1275 DataReceivedEventHandler cb = ErrorDataReceived;
1277 cb (this, new DataReceivedEventArgs (str));
1285 AsyncOutput = 1 << 2,
1289 [StructLayout (LayoutKind.Sequential)]
1290 sealed class ProcessAsyncReader : IOAsyncResult
1297 StringBuilder sb = new StringBuilder ();
1298 byte[] buffer = new byte [4096];
1300 const int ERROR_INVALID_HANDLE = 6;
1302 public ProcessAsyncReader (Process process, FileStream stream, bool err_out)
1305 this.process = process;
1306 this.handle = stream.SafeFileHandle.DangerousGetHandle ();
1307 this.stream = stream;
1308 this.err_out = err_out;
1311 public void BeginReadLine ()
1313 IOSelector.Add (this.handle, new IOSelectorJob (IOOperation.Read, _ => Read (), null));
1321 nread = stream.Read (buffer, 0, buffer.Length);
1322 } catch (ObjectDisposedException) {
1323 } catch (IOException ex) {
1324 if (ex.HResult != (unchecked((int) 0x80070000) | (int) ERROR_INVALID_HANDLE))
1326 } catch (NotSupportedException) {
1335 process.OnOutputDataReceived (null);
1337 process.OnErrorDataReceived (null);
1345 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1347 // Just in case the encoding fails...
1348 for (int i = 0; i < nread; i++) {
1349 sb.Append ((char) buffer [i]);
1355 IOSelector.Add (this.handle, new IOSelectorJob (IOOperation.Read, _ => Read (), null));
1358 void Flush (bool last)
1360 if (sb.Length == 0 || (err_out && process.output_canceled) || (!err_out && process.error_canceled))
1363 string[] strs = sb.ToString ().Split ('\n');
1367 if (strs.Length == 0)
1370 for (int i = 0; i < strs.Length - 1; i++) {
1372 process.OnOutputDataReceived (strs [i]);
1374 process.OnErrorDataReceived (strs [i]);
1377 string end = strs [strs.Length - 1];
1378 if (last || (strs.Length == 1 && end == "")) {
1380 process.OnOutputDataReceived (end);
1382 process.OnErrorDataReceived (end);
1388 public void Close ()
1390 IOSelector.Remove (handle);
1393 internal override void CompleteDisposed ()
1395 throw new NotSupportedException ();
1399 AsyncModes async_mode;
1400 bool output_canceled;
1401 bool error_canceled;
1402 ProcessAsyncReader async_output;
1403 ProcessAsyncReader async_error;
1405 [ComVisibleAttribute(false)]
1406 public void BeginOutputReadLine ()
1408 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1409 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1411 if ((async_mode & AsyncModes.SyncOutput) != 0)
1412 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1414 async_mode |= AsyncModes.AsyncOutput;
1415 output_canceled = false;
1416 if (async_output == null) {
1417 async_output = new ProcessAsyncReader (this, (FileStream) output_stream.BaseStream, true);
1418 async_output.BeginReadLine ();
1422 [ComVisibleAttribute(false)]
1423 public void CancelOutputRead ()
1425 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1426 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1428 if ((async_mode & AsyncModes.SyncOutput) != 0)
1429 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1431 if (async_output == null)
1432 throw new InvalidOperationException ("No async operation in progress.");
1434 output_canceled = true;
1437 [ComVisibleAttribute(false)]
1438 public void BeginErrorReadLine ()
1440 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1441 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1443 if ((async_mode & AsyncModes.SyncError) != 0)
1444 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1446 async_mode |= AsyncModes.AsyncError;
1447 error_canceled = false;
1448 if (async_error == null) {
1449 async_error = new ProcessAsyncReader (this, (FileStream) error_stream.BaseStream, false);
1450 async_error.BeginReadLine ();
1454 [ComVisibleAttribute(false)]
1455 public void CancelErrorRead ()
1457 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1458 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1460 if ((async_mode & AsyncModes.SyncOutput) != 0)
1461 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1463 if (async_error == null)
1464 throw new InvalidOperationException ("No async operation in progress.");
1466 error_canceled = true;
1469 [Category ("Behavior")]
1470 [MonitoringDescription ("Raised when this process exits.")]
1471 public event EventHandler Exited {
1473 if (process_handle != IntPtr.Zero && HasExited) {
1474 value.BeginInvoke (null, null, null, null);
1476 exited_event += value;
1477 if (exited_event != null)
1478 StartBackgroundWaitForExit ();
1482 exited_event -= value;
1486 // Closes the system process handle
1487 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1488 private extern void Process_free_internal(IntPtr handle);
1492 protected override void Dispose(bool disposing) {
1493 // Check to see if Dispose has already been called.
1494 if (disposed != 0 || Interlocked.CompareExchange (ref disposed, 1, 0) != 0)
1497 // If this is a call to Dispose,
1498 // dispose all managed resources.
1500 /* These have open FileStreams on the pipes we are about to close */
1501 if (async_output != null)
1502 async_output.Close ();
1503 if (async_error != null)
1504 async_error.Close ();
1506 if (input_stream != null) {
1507 if (!input_stream_exposed)
1508 input_stream.Close ();
1509 input_stream = null;
1511 if (output_stream != null) {
1512 if (!output_stream_exposed)
1513 output_stream.Close ();
1514 output_stream = null;
1516 if (error_stream != null) {
1517 if (!error_stream_exposed)
1518 error_stream.Close ();
1519 error_stream = null;
1523 // Release unmanaged resources
1525 if (process_handle!=IntPtr.Zero) {
1526 Process_free_internal (process_handle);
1527 process_handle = IntPtr.Zero;
1530 base.Dispose (disposing);
1538 int on_exited_called = 0;
1540 protected void OnExited()
1542 if (on_exited_called != 0 || Interlocked.CompareExchange (ref on_exited_called, 1, 0) != 0)
1545 var cb = exited_event;
1549 if (synchronizingObject != null) {
1550 synchronizingObject.BeginInvoke (cb, new object [] { this, EventArgs.Empty });
1552 foreach (EventHandler d in cb.GetInvocationList ()) {
1554 d (this, EventArgs.Empty);
1561 static bool IsWindows
1565 PlatformID platform = Environment.OSVersion.Platform;
1566 if (platform == PlatformID.Win32S ||
1567 platform == PlatformID.Win32Windows ||
1568 platform == PlatformID.Win32NT ||
1569 platform == PlatformID.WinCE) {
1576 void StartBackgroundWaitForExit ()
1578 if (enable_raising_events == 0)
1580 if (exited_event == null)
1582 if (process_handle == IntPtr.Zero)
1584 if (background_wait_for_exit_thread != null)
1587 Thread t = new Thread (_ => WaitForExit ()) { IsBackground = true };
1589 if (Interlocked.CompareExchange (ref background_wait_for_exit_thread, t, null) == null)
1593 class ProcessWaitHandle : WaitHandle
1595 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1596 private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1598 public ProcessWaitHandle (IntPtr handle)
1600 // Need to keep a reference to this handle,
1601 // in case the Process object is collected
1602 Handle = ProcessHandle_duplicate (handle);
1604 // When the wait handle is disposed, the duplicated handle will be
1605 // closed, so no need to override dispose (bug #464628).