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;
47 namespace System.Diagnostics {
49 [DefaultEvent ("Exited"), DefaultProperty ("StartInfo")]
50 [Designer ("System.Diagnostics.Design.ProcessDesigner, " + Consts.AssemblySystem_Design)]
51 [PermissionSet (SecurityAction.LinkDemand, Unrestricted = true)]
52 [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
53 [MonitoringDescription ("Represents a system process")]
54 public class Process : Component
56 [StructLayout(LayoutKind.Sequential)]
57 private struct ProcInfo
59 public IntPtr process_handle;
60 /* If thread_handle is ever needed for
61 * something, take out the CloseHandle() in
62 * the Start_internal icall in
63 * mono/metadata/process.c
65 public IntPtr thread_handle;
66 public int pid; // Contains -GetLastError () on failure.
68 public string [] envKeys;
69 public string [] envValues;
70 public string UserName;
72 public IntPtr Password;
73 public bool LoadUserProfile;
76 IntPtr process_handle;
78 bool enableRaisingEvents;
79 RegisteredWaitHandle exitWaitHandle;
80 ISynchronizeInvoke synchronizingObject;
81 EventHandler exited_event;
85 object thisLock = new Object ();
87 /* Private constructor called from other methods */
88 private Process(IntPtr handle, int id) {
89 process_handle=handle;
98 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
99 [MonitoringDescription ("Base process priority.")]
100 public int BasePriority {
106 void StartExitCallbackIfNeeded ()
109 bool start = (exitWaitHandle == null && enableRaisingEvents && exited_event != null);
110 if (start && process_handle != IntPtr.Zero) {
111 WaitOrTimerCallback cb = new WaitOrTimerCallback (CBOnExit);
112 ProcessWaitHandle h = new ProcessWaitHandle (process_handle);
113 exitWaitHandle = ThreadPool.RegisterWaitForSingleObject (h, cb, this, -1, true);
118 void UnregisterExitCallback ()
121 if (exitWaitHandle != null) {
122 exitWaitHandle.Unregister (null);
123 exitWaitHandle = null;
128 bool IsExitCallbackPending ()
131 return exitWaitHandle != null;
135 [DefaultValue (false), Browsable (false)]
136 [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
137 public bool EnableRaisingEvents {
139 return enableRaisingEvents;
142 bool prev = enableRaisingEvents;
143 enableRaisingEvents = value;
144 if (enableRaisingEvents && !prev)
145 StartExitCallbackIfNeeded ();
150 [MethodImplAttribute(MethodImplOptions.InternalCall)]
151 private extern static int ExitCode_internal(IntPtr handle);
153 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
154 [MonitoringDescription ("The exit code of the process.")]
155 public int ExitCode {
157 if (process_handle == IntPtr.Zero)
158 throw new InvalidOperationException ("Process has not been started.");
160 int code = ExitCode_internal (process_handle);
162 throw new InvalidOperationException ("The process must exit before " +
163 "getting the requested information.");
169 /* Returns the process start time in Windows file
170 * times (ticks from DateTime(1/1/1601 00:00 GMT))
172 [MethodImplAttribute(MethodImplOptions.InternalCall)]
173 private extern static long ExitTime_internal(IntPtr handle);
175 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
176 [MonitoringDescription ("The exit time of the process.")]
177 public DateTime ExitTime {
179 if (process_handle == IntPtr.Zero)
180 throw new InvalidOperationException ("Process has not been started.");
183 throw new InvalidOperationException ("The process must exit before " +
184 "getting the requested information.");
186 return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
190 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
191 [MonitoringDescription ("Handle for this process.")]
192 public IntPtr Handle {
194 if (process_handle == IntPtr.Zero)
195 throw new InvalidOperationException ("No process is associated with this object.");
196 return(process_handle);
201 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
202 [MonitoringDescription ("Handles for this process.")]
203 public int HandleCount {
209 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
210 [MonitoringDescription ("Determines if the process is still running.")]
211 public bool HasExited {
213 if (process_handle == IntPtr.Zero)
214 throw new InvalidOperationException ("Process has not been started.");
216 int exitcode = ExitCode_internal (process_handle);
227 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
228 [MonitoringDescription ("Process identifier.")]
232 throw new InvalidOperationException ("Process ID has not been set.");
239 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
240 [MonitoringDescription ("The name of the computer running the process.")]
241 public string MachineName {
247 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
248 [MonitoringDescription ("The main module of the process.")]
249 public ProcessModule MainModule {
251 return(this.Modules[0]);
256 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
257 [MonitoringDescription ("The handle of the main window of the process.")]
258 public IntPtr MainWindowHandle {
265 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
266 [MonitoringDescription ("The title of the main window of the process.")]
267 public string MainWindowTitle {
273 [MethodImplAttribute(MethodImplOptions.InternalCall)]
274 private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
275 [MethodImplAttribute(MethodImplOptions.InternalCall)]
276 private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);
278 /* LAMESPEC: why is this an IntPtr not a plain int? */
279 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
280 [MonitoringDescription ("The maximum working set for this process.")]
281 public IntPtr MaxWorkingSet {
284 throw new InvalidOperationException(
285 "The process " + ProcessName +
286 " (ID " + Id + ") has exited");
290 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
292 throw new Win32Exception();
299 throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
302 bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
304 throw new Win32Exception();
309 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
310 [MonitoringDescription ("The minimum working set for this process.")]
311 public IntPtr MinWorkingSet {
314 throw new InvalidOperationException(
315 "The process " + ProcessName +
316 " (ID " + Id + ") has exited");
320 bool ok= GetWorkingSet_internal (process_handle, out min, out max);
322 throw new Win32Exception();
323 return ((IntPtr) min);
327 throw new InvalidOperationException(
328 "The process " + ProcessName +
329 " (ID " + Id + ") has exited");
331 bool ok = SetWorkingSet_internal (process_handle, value.ToInt32(), 0, true);
333 throw new Win32Exception();
337 /* Returns the list of process modules. The main module is
340 [MethodImplAttribute(MethodImplOptions.InternalCall)]
341 private extern ProcessModule[] GetModules_internal(IntPtr handle);
343 private ProcessModuleCollection module_collection;
345 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
346 [MonitoringDescription ("The modules that are loaded as part of this process.")]
347 public ProcessModuleCollection Modules {
349 if (module_collection == null)
350 module_collection = new ProcessModuleCollection(
351 GetModules_internal (process_handle));
352 return(module_collection);
356 /* data type is from the MonoProcessData enum in mono-proclib.h in the runtime */
357 [MethodImplAttribute(MethodImplOptions.InternalCall)]
358 private extern static long GetProcessData (int pid, int data_type, out int error);
361 [Obsolete ("Use NonpagedSystemMemorySize64")]
362 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
363 [MonitoringDescription ("The number of bytes that are not pageable.")]
364 public int NonpagedSystemMemorySize {
370 [Obsolete ("Use PagedMemorySize64")]
371 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
372 [MonitoringDescription ("The number of bytes that are paged.")]
373 public int PagedMemorySize {
375 return(int)PagedMemorySize64;
379 [Obsolete ("Use PagedSystemMemorySize64")]
380 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
381 [MonitoringDescription ("The amount of paged system memory in bytes.")]
382 public int PagedSystemMemorySize {
384 return(int)PagedMemorySize64;
389 [Obsolete ("Use PeakPagedMemorySize64")]
390 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
391 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
392 public int PeakPagedMemorySize {
398 [Obsolete ("Use PeakVirtualMemorySize64")]
399 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
400 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
401 public int PeakVirtualMemorySize {
404 return (int)GetProcessData (pid, 8, out error);
408 [Obsolete ("Use PeakWorkingSet64")]
409 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
410 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
411 public int PeakWorkingSet {
414 return (int)GetProcessData (pid, 5, out error);
419 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
420 [MonitoringDescription ("The number of bytes that are not pageable.")]
422 public long NonpagedSystemMemorySize64 {
428 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
429 [MonitoringDescription ("The number of bytes that are paged.")]
431 public long PagedMemorySize64 {
434 return GetProcessData (pid, 12, out error);
438 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
439 [MonitoringDescription ("The amount of paged system memory in bytes.")]
441 public long PagedSystemMemorySize64 {
443 return PagedMemorySize64;
448 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
449 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
451 public long PeakPagedMemorySize64 {
457 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
458 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
460 public long PeakVirtualMemorySize64 {
463 return GetProcessData (pid, 8, out error);
467 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
468 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
470 public long PeakWorkingSet64 {
473 return GetProcessData (pid, 5, out error);
478 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
479 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
480 public bool PriorityBoostEnabled {
488 [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
489 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
490 [MonitoringDescription ("The relative process priority.")]
491 public ProcessPriorityClass PriorityClass {
493 if (process_handle == IntPtr.Zero)
494 throw new InvalidOperationException ("Process has not been started.");
497 int prio = GetPriorityClass (process_handle, out error);
499 throw new Win32Exception (error);
500 return (ProcessPriorityClass) prio;
503 if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
504 throw new InvalidEnumArgumentException (
505 "value", (int) value,
506 typeof (ProcessPriorityClass));
508 if (process_handle == IntPtr.Zero)
509 throw new InvalidOperationException ("Process has not been started.");
512 if (!SetPriorityClass (process_handle, (int) value, out error)) {
514 throw new Win32Exception (error);
519 void CheckExited () {
521 throw new InvalidOperationException (String.Format ("Cannot process request because the process ({0}) has exited.", Id));
524 [MethodImplAttribute(MethodImplOptions.InternalCall)]
525 static extern int GetPriorityClass (IntPtr handle, out int error);
527 [MethodImplAttribute(MethodImplOptions.InternalCall)]
528 static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);
530 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
531 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
532 [Obsolete ("Use PrivateMemorySize64")]
533 public int PrivateMemorySize {
536 return (int)GetProcessData (pid, 6, out error);
540 [MonoNotSupported ("")]
541 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
542 [MonitoringDescription ("The session ID for this process.")]
543 public int SessionId {
544 get { throw new NotImplementedException (); }
547 /* the meaning of type is as follows: 0: user, 1: system, 2: total */
548 [MethodImplAttribute(MethodImplOptions.InternalCall)]
549 private extern static long Times (IntPtr handle, int type);
551 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
552 [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
553 public TimeSpan PrivilegedProcessorTime {
555 return new TimeSpan (Times (process_handle, 1));
559 [MethodImplAttribute(MethodImplOptions.InternalCall)]
560 private extern static string ProcessName_internal(IntPtr handle);
562 private string process_name=null;
564 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
565 [MonitoringDescription ("The name of this process.")]
566 public string ProcessName {
568 if(process_name==null) {
570 if (process_handle == IntPtr.Zero)
571 throw new InvalidOperationException ("No process is associated with this object.");
573 process_name=ProcessName_internal(process_handle);
574 /* If process_name is _still_
575 * null, assume the process
578 if (process_name == null)
579 throw new InvalidOperationException ("Process has exited, so the requested information is not available.");
581 /* Strip the suffix (if it
582 * exists) simplistically
583 * instead of removing any
584 * trailing \.???, so we dont
585 * get stupid results on sane
588 if(process_name.EndsWith(".exe") ||
589 process_name.EndsWith(".bat") ||
590 process_name.EndsWith(".com")) {
591 process_name=process_name.Substring(0, process_name.Length-4);
594 return(process_name);
599 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
600 [MonitoringDescription ("Allowed processor that can be used by this process.")]
601 public IntPtr ProcessorAffinity {
610 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
611 [MonitoringDescription ("Is this process responsive.")]
612 public bool Responding {
618 private StreamReader error_stream=null;
620 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
621 [MonitoringDescription ("The standard error stream of this process.")]
622 public StreamReader StandardError {
624 if (error_stream == null)
625 throw new InvalidOperationException("Standard error has not been redirected");
627 if ((async_mode & AsyncModes.AsyncError) != 0)
628 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
630 async_mode |= AsyncModes.SyncError;
632 return(error_stream);
636 private StreamWriter input_stream=null;
638 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
639 [MonitoringDescription ("The standard input stream of this process.")]
640 public StreamWriter StandardInput {
642 if (input_stream == null)
643 throw new InvalidOperationException("Standard input has not been redirected");
645 return(input_stream);
649 private StreamReader output_stream=null;
651 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
652 [MonitoringDescription ("The standard output stream of this process.")]
653 public StreamReader StandardOutput {
655 if (output_stream == null)
656 throw new InvalidOperationException("Standard output has not been redirected");
658 if ((async_mode & AsyncModes.AsyncOutput) != 0)
659 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
661 async_mode |= AsyncModes.SyncOutput;
663 return(output_stream);
667 private ProcessStartInfo start_info=null;
669 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
670 [MonitoringDescription ("Information for the start of this process.")]
671 public ProcessStartInfo StartInfo {
673 if (start_info == null)
674 start_info = new ProcessStartInfo();
679 throw new ArgumentNullException("value");
684 /* Returns the process start time in Windows file
685 * times (ticks from DateTime(1/1/1601 00:00 GMT))
687 [MethodImplAttribute(MethodImplOptions.InternalCall)]
688 private extern static long StartTime_internal(IntPtr handle);
690 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
691 [MonitoringDescription ("The time this process started.")]
692 public DateTime StartTime {
694 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
698 [DefaultValue (null), Browsable (false)]
699 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
700 public ISynchronizeInvoke SynchronizingObject {
701 get { return synchronizingObject; }
702 set { synchronizingObject = value; }
706 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
707 [MonitoringDescription ("The number of threads of this process.")]
708 public ProcessThreadCollection Threads {
710 // This'll return a correctly-sized array of empty ProcessThreads for now.
712 return new ProcessThreadCollection(new ProcessThread[GetProcessData (pid, 0, out error)]);
716 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
717 [MonitoringDescription ("The total CPU time spent for this process.")]
718 public TimeSpan TotalProcessorTime {
720 return new TimeSpan (Times (process_handle, 2));
724 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
725 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
726 public TimeSpan UserProcessorTime {
728 return new TimeSpan (Times (process_handle, 0));
732 [Obsolete ("Use VirtualMemorySize64")]
733 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
734 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
735 public int VirtualMemorySize {
738 return (int)GetProcessData (pid, 7, out error);
742 [Obsolete ("Use WorkingSet64")]
743 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
744 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
745 public int WorkingSet {
748 return (int)GetProcessData (pid, 4, out error);
752 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
753 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
755 public long PrivateMemorySize64 {
758 return GetProcessData (pid, 6, out error);
762 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
763 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
765 public long VirtualMemorySize64 {
768 return GetProcessData (pid, 7, out error);
772 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
773 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
775 public long WorkingSet64 {
778 return GetProcessData (pid, 4, out error);
787 [MethodImplAttribute(MethodImplOptions.InternalCall)]
788 extern static bool Kill_internal (IntPtr handle, int signo);
790 /* int kill -> 1 KILL, 2 CloseMainWindow */
791 bool Close (int signo)
793 if (process_handle == IntPtr.Zero)
794 throw new SystemException ("No process to kill.");
796 int exitcode = ExitCode_internal (process_handle);
798 throw new InvalidOperationException ("The process already finished.");
800 return Kill_internal (process_handle, signo);
803 public bool CloseMainWindow ()
809 public static void EnterDebugMode() {
812 [MethodImplAttribute(MethodImplOptions.InternalCall)]
813 private extern static IntPtr GetProcess_internal(int pid);
815 [MethodImplAttribute(MethodImplOptions.InternalCall)]
816 private extern static int GetPid_internal();
818 public static Process GetCurrentProcess()
820 int pid = GetPid_internal();
821 IntPtr proc = GetProcess_internal(pid);
823 if (proc == IntPtr.Zero)
824 throw new SystemException("Can't find current process");
826 return (new Process (proc, pid));
829 public static Process GetProcessById(int processId)
831 IntPtr proc = GetProcess_internal(processId);
833 if (proc == IntPtr.Zero)
834 throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
836 return (new Process (proc, processId));
839 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
840 public static Process GetProcessById(int processId, string machineName) {
841 if (machineName == null)
842 throw new ArgumentNullException ("machineName");
844 if (!IsLocalMachine (machineName))
845 throw new NotImplementedException ();
847 return GetProcessById (processId);
850 [MethodImplAttribute(MethodImplOptions.InternalCall)]
851 private extern static int[] GetProcesses_internal();
853 public static Process[] GetProcesses ()
855 int [] pids = GetProcesses_internal ();
857 return new Process [0];
859 var proclist = new List<Process> (pids.Length);
860 for (int i = 0; i < pids.Length; i++) {
862 proclist.Add (GetProcessById (pids [i]));
863 } catch (SystemException) {
864 /* The process might exit
866 * GetProcesses_internal and
872 return proclist.ToArray ();
875 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
876 public static Process[] GetProcesses(string machineName) {
877 if (machineName == null)
878 throw new ArgumentNullException ("machineName");
880 if (!IsLocalMachine (machineName))
881 throw new NotImplementedException ();
883 return GetProcesses ();
886 public static Process[] GetProcessesByName(string processName)
888 int [] pids = GetProcesses_internal ();
890 return new Process [0];
892 var proclist = new List<Process> (pids.Length);
893 for (int i = 0; i < pids.Length; i++) {
895 Process p = GetProcessById (pids [i]);
896 if (String.Compare (processName, p.ProcessName, true) == 0)
898 } catch (SystemException) {
899 /* The process might exit
901 * GetProcesses_internal and
907 return proclist.ToArray ();
911 public static Process[] GetProcessesByName(string processName, string machineName) {
912 throw new NotImplementedException();
921 public static void LeaveDebugMode() {
924 public void Refresh ()
926 // FIXME: should refresh any cached data we might have about
927 // the process (currently we have none).
930 [MethodImplAttribute(MethodImplOptions.InternalCall)]
931 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
932 ref ProcInfo proc_info);
934 [MethodImplAttribute(MethodImplOptions.InternalCall)]
935 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
939 ref ProcInfo proc_info);
941 private static bool Start_shell (ProcessStartInfo startInfo, Process process)
943 ProcInfo proc_info=new ProcInfo();
946 if (startInfo.RedirectStandardInput ||
947 startInfo.RedirectStandardOutput ||
948 startInfo.RedirectStandardError) {
949 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
952 if (startInfo.HaveEnvVars)
953 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
955 FillUserInfo (startInfo, ref proc_info);
957 ret = ShellExecuteEx_internal (startInfo,
960 if (proc_info.Password != IntPtr.Zero)
961 Marshal.ZeroFreeBSTR (proc_info.Password);
962 proc_info.Password = IntPtr.Zero;
965 throw new Win32Exception (-proc_info.pid);
968 process.process_handle = proc_info.process_handle;
969 process.pid = proc_info.pid;
970 process.StartExitCallbackIfNeeded ();
974 private static bool Start_noshell (ProcessStartInfo startInfo,
977 ProcInfo proc_info=new ProcInfo();
978 IntPtr stdin_rd = IntPtr.Zero, stdin_wr = IntPtr.Zero;
984 if (startInfo.HaveEnvVars) {
985 string [] strs = new string [startInfo.EnvironmentVariables.Count];
986 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
987 proc_info.envKeys = strs;
989 strs = new string [startInfo.EnvironmentVariables.Count];
990 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
991 proc_info.envValues = strs;
994 if (startInfo.RedirectStandardInput == true) {
996 int DUPLICATE_SAME_ACCESS = 0x00000002;
999 ret = MonoIO.CreatePipe (out stdin_rd,
1002 ret = MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, stdin_wr_tmp,
1003 Process.GetCurrentProcess ().Handle, out stdin_wr, 0, 0, DUPLICATE_SAME_ACCESS);
1004 MonoIO.Close (stdin_wr_tmp, out error);
1009 ret = MonoIO.CreatePipe (out stdin_rd,
1013 throw new IOException ("Error creating standard input pipe");
1016 stdin_rd = MonoIO.ConsoleInput;
1017 /* This is required to stop the
1018 * &$*£ing stupid compiler moaning
1019 * that stdin_wr is unassigned, below.
1021 stdin_wr = (IntPtr)0;
1024 if (startInfo.RedirectStandardOutput == true) {
1025 IntPtr out_rd = IntPtr.Zero;
1028 int DUPLICATE_SAME_ACCESS = 0x00000002;
1030 ret = MonoIO.CreatePipe (out out_rd_tmp,
1033 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, out_rd_tmp,
1034 Process.GetCurrentProcess ().Handle, out out_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1035 MonoIO.Close (out_rd_tmp, out error);
1039 ret = MonoIO.CreatePipe (out out_rd,
1043 process.stdout_rd = out_rd;
1045 if (startInfo.RedirectStandardInput == true) {
1046 MonoIO.Close (stdin_rd, out error);
1047 MonoIO.Close (stdin_wr, out error);
1050 throw new IOException ("Error creating standard output pipe");
1053 process.stdout_rd = (IntPtr)0;
1054 stdout_wr = MonoIO.ConsoleOutput;
1057 if (startInfo.RedirectStandardError == true) {
1058 IntPtr err_rd = IntPtr.Zero;
1061 int DUPLICATE_SAME_ACCESS = 0x00000002;
1063 ret = MonoIO.CreatePipe (out err_rd_tmp,
1066 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, err_rd_tmp,
1067 Process.GetCurrentProcess ().Handle, out err_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1068 MonoIO.Close (err_rd_tmp, out error);
1072 ret = MonoIO.CreatePipe (out err_rd,
1076 process.stderr_rd = err_rd;
1078 if (startInfo.RedirectStandardInput == true) {
1079 MonoIO.Close (stdin_rd, out error);
1080 MonoIO.Close (stdin_wr, out error);
1082 if (startInfo.RedirectStandardOutput == true) {
1083 MonoIO.Close (process.stdout_rd, out error);
1084 MonoIO.Close (stdout_wr, out error);
1087 throw new IOException ("Error creating standard error pipe");
1090 process.stderr_rd = (IntPtr)0;
1091 stderr_wr = MonoIO.ConsoleError;
1094 FillUserInfo (startInfo, ref proc_info);
1096 ret = CreateProcess_internal (startInfo,
1097 stdin_rd, stdout_wr, stderr_wr,
1100 if (proc_info.Password != IntPtr.Zero)
1101 Marshal.ZeroFreeBSTR (proc_info.Password);
1102 proc_info.Password = IntPtr.Zero;
1105 if (startInfo.RedirectStandardInput == true) {
1106 MonoIO.Close (stdin_rd, out error);
1107 MonoIO.Close (stdin_wr, out error);
1110 if (startInfo.RedirectStandardOutput == true) {
1111 MonoIO.Close (process.stdout_rd, out error);
1112 MonoIO.Close (stdout_wr, out error);
1115 if (startInfo.RedirectStandardError == true) {
1116 MonoIO.Close (process.stderr_rd, out error);
1117 MonoIO.Close (stderr_wr, out error);
1120 throw new Win32Exception (-proc_info.pid,
1121 "ApplicationName='" + startInfo.FileName +
1122 "', CommandLine='" + startInfo.Arguments +
1123 "', CurrentDirectory='" + startInfo.WorkingDirectory +
1124 "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
1127 process.process_handle = proc_info.process_handle;
1128 process.pid = proc_info.pid;
1130 if (startInfo.RedirectStandardInput == true) {
1131 MonoIO.Close (stdin_rd, out error);
1132 process.input_stream = new StreamWriter (new MonoSyncFileStream (stdin_wr, FileAccess.Write, true, 8192), Console.Out.Encoding);
1133 process.input_stream.AutoFlush = true;
1136 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1137 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1139 if (startInfo.RedirectStandardOutput == true) {
1140 MonoIO.Close (stdout_wr, out error);
1141 process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding, true, 8192);
1144 if (startInfo.RedirectStandardError == true) {
1145 MonoIO.Close (stderr_wr, out error);
1146 process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding, true, 8192);
1149 process.StartExitCallbackIfNeeded ();
1154 // Note that ProcInfo.Password must be freed.
1155 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1157 if (startInfo.UserName.Length != 0) {
1158 proc_info.UserName = startInfo.UserName;
1159 proc_info.Domain = startInfo.Domain;
1160 if (startInfo.Password != null)
1161 proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1163 proc_info.Password = IntPtr.Zero;
1164 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1168 private static bool Start_common (ProcessStartInfo startInfo,
1171 if (startInfo.FileName.Length == 0)
1172 throw new InvalidOperationException("File name has not been set");
1174 if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1175 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1176 if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1177 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1179 if (startInfo.UseShellExecute) {
1180 if (startInfo.UserName.Length != 0)
1181 throw new InvalidOperationException ("UseShellExecute must be false if an explicit UserName is specified when starting a process");
1182 return (Start_shell (startInfo, process));
1184 return (Start_noshell (startInfo, process));
1188 public bool Start ()
1190 if (process_handle != IntPtr.Zero) {
1191 Process_free_internal (process_handle);
1192 process_handle = IntPtr.Zero;
1194 return Start_common(start_info, this);
1197 public static Process Start (ProcessStartInfo startInfo)
1199 if (startInfo == null)
1200 throw new ArgumentNullException ("startInfo");
1202 Process process = new Process();
1203 process.StartInfo = startInfo;
1204 if (Start_common(startInfo, process) && process.process_handle != IntPtr.Zero)
1209 public static Process Start (string fileName)
1211 return Start (new ProcessStartInfo (fileName));
1214 public static Process Start(string fileName, string arguments)
1216 return Start (new ProcessStartInfo (fileName, arguments));
1219 public static Process Start(string fileName, string username, SecureString password, string domain) {
1220 return Start(fileName, null, username, password, domain);
1223 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1224 ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1225 psi.UserName = username;
1226 psi.Password = password;
1227 psi.Domain = domain;
1228 psi.UseShellExecute = false;
1232 public override string ToString()
1234 return(base.ToString() + " (" + this.ProcessName + ")");
1237 /* Waits up to ms milliseconds for process 'handle' to
1238 * exit. ms can be <0 to mean wait forever.
1240 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1241 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1243 public void WaitForExit ()
1248 public bool WaitForExit(int milliseconds) {
1249 int ms = milliseconds;
1250 if (ms == int.MaxValue)
1253 if (process_handle == IntPtr.Zero)
1254 throw new InvalidOperationException ("No process is associated with this object.");
1257 DateTime start = DateTime.UtcNow;
1258 if (async_output != null && !async_output.IsCompleted) {
1259 if (false == async_output.WaitHandle.WaitOne (ms, false))
1260 return false; // Timed out
1263 DateTime now = DateTime.UtcNow;
1264 ms -= (int) (now - start).TotalMilliseconds;
1271 if (async_error != null && !async_error.IsCompleted) {
1272 if (false == async_error.WaitHandle.WaitOne (ms, false))
1273 return false; // Timed out
1276 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1282 bool exited = WaitForExit_internal (process_handle, ms);
1290 /* Waits up to ms milliseconds for process 'handle' to
1291 * wait for input. ms can be <0 to mean wait forever.
1293 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1294 private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
1296 // The internal call is only implemented properly on Windows.
1298 public bool WaitForInputIdle() {
1299 return WaitForInputIdle (-1);
1302 // The internal call is only implemented properly on Windows.
1304 public bool WaitForInputIdle(int milliseconds) {
1305 return WaitForInputIdle_internal (process_handle, milliseconds);
1308 private static bool IsLocalMachine (string machineName)
1310 if (machineName == "." || machineName.Length == 0)
1313 return (string.Compare (machineName, Environment.MachineName, true) == 0);
1317 [MonitoringDescription ("Raised when it receives output data")]
1318 public event DataReceivedEventHandler OutputDataReceived;
1320 [MonitoringDescription ("Raised when it receives error data")]
1321 public event DataReceivedEventHandler ErrorDataReceived;
1323 void OnOutputDataReceived (string str)
1325 if (OutputDataReceived != null)
1326 OutputDataReceived (this, new DataReceivedEventArgs (str));
1329 void OnErrorDataReceived (string str)
1331 if (ErrorDataReceived != null)
1332 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1340 AsyncOutput = 1 << 2,
1344 [StructLayout (LayoutKind.Sequential)]
1345 sealed class ProcessAsyncReader : IThreadPoolWorkItem
1348 The following fields match those of SocketAsyncResult.
1349 This is so that changes needed in the runtime to handle
1350 asynchronous reads are trivial
1351 Keep this in sync with SocketAsyncResult in
1352 ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
1353 in metadata/socket-io.h.
1355 /* DON'T shuffle fields around. DON'T remove fields */
1357 public IntPtr handle;
1358 public object state;
1359 public AsyncCallback callback;
1360 public ManualResetEvent wait_handle;
1362 public Exception delayedException;
1364 public object EndPoint;
1365 byte [] buffer = new byte [4196];
1368 public int SockFlags;
1370 public object AcceptSocket;
1371 public object[] Addresses;
1373 public object Buffers; // Reserve this slot in older profiles
1374 public bool ReuseSocket; // Disconnect
1375 public object acc_socket;
1377 public bool completed_sync;
1379 bool err_out; // true -> stdout, false -> stderr
1381 public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1382 public AsyncResult async_result;
1383 public int EndCalled;
1385 // These fields are not in SocketAsyncResult
1388 StringBuilder sb = new StringBuilder ();
1389 public AsyncReadHandler ReadHandler;
1391 public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1393 this.process = process;
1394 this.handle = handle;
1395 stream = new FileStream (handle, FileAccess.Read, false);
1396 this.ReadHandler = new AsyncReadHandler (AddInput);
1397 this.err_out = err_out;
1400 public void AddInput ()
1403 int nread = stream.Read (buffer, 0, buffer.Length);
1406 if (wait_handle != null)
1413 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1415 // Just in case the encoding fails...
1416 for (int i = 0; i < nread; i++) {
1417 sb.Append ((char) buffer [i]);
1422 ReadHandler.BeginInvoke (null, this);
1430 process.OnOutputDataReceived (null);
1432 process.OnErrorDataReceived (null);
1436 void Flush (bool last)
1438 if (sb.Length == 0 ||
1439 (err_out && process.output_canceled) ||
1440 (!err_out && process.error_canceled))
1443 string total = sb.ToString ();
1445 string [] strs = total.Split ('\n');
1446 int len = strs.Length;
1450 for (int i = 0; i < len - 1; i++) {
1452 process.OnOutputDataReceived (strs [i]);
1454 process.OnErrorDataReceived (strs [i]);
1457 string end = strs [len - 1];
1458 if (last || (len == 1 && end == "")) {
1460 process.OnOutputDataReceived (end);
1462 process.OnErrorDataReceived (end);
1469 public bool IsCompleted {
1470 get { return completed; }
1473 public WaitHandle WaitHandle {
1476 if (wait_handle == null)
1477 wait_handle = new ManualResetEvent (completed);
1483 public void Close () {
1487 void IThreadPoolWorkItem.ExecuteWorkItem()
1489 async_result.Invoke ();
1492 void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae)
1497 AsyncModes async_mode;
1498 bool output_canceled;
1499 bool error_canceled;
1500 ProcessAsyncReader async_output;
1501 ProcessAsyncReader async_error;
1502 delegate void AsyncReadHandler ();
1504 [ComVisibleAttribute(false)]
1505 public void BeginOutputReadLine ()
1507 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1508 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1510 if ((async_mode & AsyncModes.SyncOutput) != 0)
1511 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1513 async_mode |= AsyncModes.AsyncOutput;
1514 output_canceled = false;
1515 if (async_output == null) {
1516 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1517 async_output.ReadHandler.BeginInvoke (null, async_output);
1521 [ComVisibleAttribute(false)]
1522 public void CancelOutputRead ()
1524 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1525 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1527 if ((async_mode & AsyncModes.SyncOutput) != 0)
1528 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1530 if (async_output == null)
1531 throw new InvalidOperationException ("No async operation in progress.");
1533 output_canceled = true;
1536 [ComVisibleAttribute(false)]
1537 public void BeginErrorReadLine ()
1539 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1540 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1542 if ((async_mode & AsyncModes.SyncError) != 0)
1543 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1545 async_mode |= AsyncModes.AsyncError;
1546 error_canceled = false;
1547 if (async_error == null) {
1548 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1549 async_error.ReadHandler.BeginInvoke (null, async_error);
1553 [ComVisibleAttribute(false)]
1554 public void CancelErrorRead ()
1556 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1557 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1559 if ((async_mode & AsyncModes.SyncOutput) != 0)
1560 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1562 if (async_error == null)
1563 throw new InvalidOperationException ("No async operation in progress.");
1565 error_canceled = true;
1568 [Category ("Behavior")]
1569 [MonitoringDescription ("Raised when this process exits.")]
1570 public event EventHandler Exited {
1572 if (process_handle != IntPtr.Zero && HasExited) {
1573 value.BeginInvoke (null, null, null, null);
1575 exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1576 if (exited_event != null)
1577 StartExitCallbackIfNeeded ();
1581 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1585 // Closes the system process handle
1586 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1587 private extern void Process_free_internal(IntPtr handle);
1589 private bool disposed = false;
1591 protected override void Dispose(bool disposing) {
1592 // Check to see if Dispose has already been called.
1593 if(this.disposed == false) {
1595 // If this is a call to Dispose,
1596 // dispose all managed resources.
1600 /* These have open FileStreams on the pipes we are about to close */
1601 if (async_output != null)
1602 async_output.Close ();
1603 if (async_error != null)
1604 async_error.Close ();
1606 if (input_stream != null) {
1607 input_stream.Close();
1608 input_stream = null;
1611 if (output_stream != null) {
1612 output_stream.Close();
1613 output_stream = null;
1616 if (error_stream != null) {
1617 error_stream.Close();
1618 error_stream = null;
1623 // Release unmanaged resources
1626 if(process_handle!=IntPtr.Zero) {
1627 Process_free_internal(process_handle);
1628 process_handle=IntPtr.Zero;
1632 base.Dispose (disposing);
1640 static void CBOnExit (object state, bool unused)
1642 Process p = (Process) state;
1644 if (!p.IsExitCallbackPending ())
1648 p.UnregisterExitCallback ();
1649 p.StartExitCallbackIfNeeded ();
1656 protected void OnExited()
1658 if (exited_event == null)
1661 UnregisterExitCallback ();
1663 if (synchronizingObject == null) {
1664 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1666 d (this, EventArgs.Empty);
1672 object [] args = new object [] {this, EventArgs.Empty};
1673 synchronizingObject.BeginInvoke (exited_event, args);
1676 static bool IsWindows
1680 PlatformID platform = Environment.OSVersion.Platform;
1681 if (platform == PlatformID.Win32S ||
1682 platform == PlatformID.Win32Windows ||
1683 platform == PlatformID.Win32NT ||
1684 platform == PlatformID.WinCE) {
1691 class ProcessWaitHandle : WaitHandle
1693 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1694 private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1696 public ProcessWaitHandle (IntPtr handle)
1698 // Need to keep a reference to this handle,
1699 // in case the Process object is collected
1700 Handle = ProcessHandle_duplicate (handle);
1702 // When the wait handle is disposed, the duplicated handle will be
1703 // closed, so no need to override dispose (bug #464628).