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.Security.Permissions;
42 using System.Collections;
43 using System.Security;
44 using System.Threading;
46 namespace System.Diagnostics {
48 [DefaultEvent ("Exited"), DefaultProperty ("StartInfo")]
49 [Designer ("System.Diagnostics.Design.ProcessDesigner, " + Consts.AssemblySystem_Design)]
50 [PermissionSet (SecurityAction.LinkDemand, Unrestricted = true)]
51 [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
52 [MonitoringDescription ("Represents a system process")]
53 public class Process : Component
55 [StructLayout(LayoutKind.Sequential)]
56 private struct ProcInfo
58 public IntPtr process_handle;
59 /* If thread_handle is ever needed for
60 * something, take out the CloseHandle() in
61 * the Start_internal icall in
62 * mono/metadata/process.c
64 public IntPtr thread_handle;
65 public int pid; // Contains -GetLastError () on failure.
67 public string [] envKeys;
68 public string [] envValues;
69 public string UserName;
71 public IntPtr Password;
72 public bool LoadUserProfile;
75 IntPtr process_handle;
77 bool enableRaisingEvents;
79 ISynchronizeInvoke synchronizingObject;
80 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 {
103 void StartExitCallbackIfNeeded ()
105 bool start = (!already_waiting && enableRaisingEvents && exited_event != null);
106 if (start && process_handle != IntPtr.Zero) {
107 WaitOrTimerCallback cb = new WaitOrTimerCallback (CBOnExit);
108 ProcessWaitHandle h = new ProcessWaitHandle (process_handle);
109 ThreadPool.RegisterWaitForSingleObject (h, cb, this, -1, true);
110 already_waiting = true;
114 [DefaultValue (false), Browsable (false)]
115 [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
116 public bool EnableRaisingEvents {
118 return enableRaisingEvents;
121 bool prev = enableRaisingEvents;
122 enableRaisingEvents = value;
123 if (enableRaisingEvents && !prev)
124 StartExitCallbackIfNeeded ();
129 [MethodImplAttribute(MethodImplOptions.InternalCall)]
130 private extern static int ExitCode_internal(IntPtr handle);
132 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
133 [MonitoringDescription ("The exit code of the process.")]
134 public int ExitCode {
136 if (process_handle == IntPtr.Zero)
137 throw new InvalidOperationException ("Process has not been started.");
139 int code = ExitCode_internal (process_handle);
141 throw new InvalidOperationException ("The process must exit before " +
142 "getting the requested information.");
148 /* Returns the process start time in Windows file
149 * times (ticks from DateTime(1/1/1601 00:00 GMT))
151 [MethodImplAttribute(MethodImplOptions.InternalCall)]
152 private extern static long ExitTime_internal(IntPtr handle);
154 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
155 [MonitoringDescription ("The exit time of the process.")]
156 public DateTime ExitTime {
158 if (process_handle == IntPtr.Zero)
159 throw new InvalidOperationException ("Process has not been started.");
162 throw new InvalidOperationException ("The process must exit before " +
163 "getting the requested information.");
165 return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
169 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
170 [MonitoringDescription ("Handle for this process.")]
171 public IntPtr Handle {
173 return(process_handle);
178 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
179 [MonitoringDescription ("Handles for this process.")]
180 public int HandleCount {
186 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
187 [MonitoringDescription ("Determines if the process is still running.")]
188 public bool HasExited {
190 if (process_handle == IntPtr.Zero)
191 throw new InvalidOperationException ("Process has not been started.");
193 int exitcode = ExitCode_internal (process_handle);
204 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
205 [MonitoringDescription ("Process identifier.")]
209 throw new InvalidOperationException ("Process ID has not been set.");
216 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
217 [MonitoringDescription ("The name of the computer running the process.")]
218 public string MachineName {
224 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
225 [MonitoringDescription ("The main module of the process.")]
226 public ProcessModule MainModule {
228 return(this.Modules[0]);
233 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
234 [MonitoringDescription ("The handle of the main window of the process.")]
235 public IntPtr MainWindowHandle {
242 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
243 [MonitoringDescription ("The title of the main window of the process.")]
244 public string MainWindowTitle {
250 [MethodImplAttribute(MethodImplOptions.InternalCall)]
251 private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
252 [MethodImplAttribute(MethodImplOptions.InternalCall)]
253 private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);
255 /* LAMESPEC: why is this an IntPtr not a plain int? */
256 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
257 [MonitoringDescription ("The maximum working set for this process.")]
258 public IntPtr MaxWorkingSet {
261 throw new InvalidOperationException(
262 "The process " + ProcessName +
263 " (ID " + Id + ") has exited");
267 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
269 throw new Win32Exception();
276 throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
279 bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
281 throw new Win32Exception();
286 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
287 [MonitoringDescription ("The minimum working set for this process.")]
288 public IntPtr MinWorkingSet {
291 throw new InvalidOperationException(
292 "The process " + ProcessName +
293 " (ID " + Id + ") has exited");
297 bool ok= GetWorkingSet_internal (process_handle, out min, out max);
299 throw new Win32Exception();
300 return ((IntPtr) min);
304 throw new InvalidOperationException(
305 "The process " + ProcessName +
306 " (ID " + Id + ") has exited");
308 bool ok = SetWorkingSet_internal (process_handle, value.ToInt32(), 0, true);
310 throw new Win32Exception();
314 /* Returns the list of process modules. The main module is
317 [MethodImplAttribute(MethodImplOptions.InternalCall)]
318 private extern ProcessModule[] GetModules_internal(IntPtr handle);
320 private ProcessModuleCollection module_collection;
322 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
323 [MonitoringDescription ("The modules that are loaded as part of this process.")]
324 public ProcessModuleCollection Modules {
326 if (module_collection == null)
327 module_collection = new ProcessModuleCollection(
328 GetModules_internal (process_handle));
329 return(module_collection);
333 /* data type is from the MonoProcessData enum in mono-proclib.h in the runtime */
334 [MethodImplAttribute(MethodImplOptions.InternalCall)]
335 private extern static long GetProcessData (int pid, int data_type, out int error);
338 [Obsolete ("Use NonpagedSystemMemorySize64")]
339 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
340 [MonitoringDescription ("The number of bytes that are not pageable.")]
341 public int NonpagedSystemMemorySize {
348 [Obsolete ("Use PagedMemorySize64")]
349 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
350 [MonitoringDescription ("The number of bytes that are paged.")]
351 public int PagedMemorySize {
358 [Obsolete ("Use PagedSystemMemorySize64")]
359 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
360 [MonitoringDescription ("The amount of paged system memory in bytes.")]
361 public int PagedSystemMemorySize {
368 [Obsolete ("Use PeakPagedMemorySize64")]
369 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
370 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
371 public int PeakPagedMemorySize {
377 [Obsolete ("Use PeakVirtualMemorySize64")]
378 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
379 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
380 public int PeakVirtualMemorySize {
383 return (int)GetProcessData (pid, 8, out error);
387 [Obsolete ("Use PeakWorkingSet64")]
388 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
389 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
390 public int PeakWorkingSet {
393 return (int)GetProcessData (pid, 5, out error);
398 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
399 [MonitoringDescription ("The number of bytes that are not pageable.")]
401 public long NonpagedSystemMemorySize64 {
408 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
409 [MonitoringDescription ("The number of bytes that are paged.")]
411 public long PagedMemorySize64 {
418 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
419 [MonitoringDescription ("The amount of paged system memory in bytes.")]
421 public long PagedSystemMemorySize64 {
428 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
429 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
431 public long PeakPagedMemorySize64 {
437 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
438 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
440 public long PeakVirtualMemorySize64 {
443 return GetProcessData (pid, 8, out error);
447 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
448 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
450 public long PeakWorkingSet64 {
453 return GetProcessData (pid, 5, out error);
458 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
459 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
460 public bool PriorityBoostEnabled {
468 [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
469 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
470 [MonitoringDescription ("The relative process priority.")]
471 public ProcessPriorityClass PriorityClass {
473 if (process_handle == IntPtr.Zero)
474 throw new InvalidOperationException ("Process has not been started.");
477 int prio = GetPriorityClass (process_handle, out error);
479 throw new Win32Exception (error);
480 return (ProcessPriorityClass) prio;
483 if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
484 throw new InvalidEnumArgumentException (
485 "value", (int) value,
486 typeof (ProcessPriorityClass));
488 if (process_handle == IntPtr.Zero)
489 throw new InvalidOperationException ("Process has not been started.");
492 if (!SetPriorityClass (process_handle, (int) value, out error)) {
494 throw new Win32Exception (error);
499 void CheckExited () {
501 throw new InvalidOperationException (String.Format ("Cannot process request because the process ({0}) has exited.", Id));
504 [MethodImplAttribute(MethodImplOptions.InternalCall)]
505 static extern int GetPriorityClass (IntPtr handle, out int error);
507 [MethodImplAttribute(MethodImplOptions.InternalCall)]
508 static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);
510 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
511 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
512 [Obsolete ("Use PrivateMemorySize64")]
513 public int PrivateMemorySize {
516 return (int)GetProcessData (pid, 6, out error);
520 [MonoNotSupported ("")]
521 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
522 [MonitoringDescription ("The session ID for this process.")]
523 public int SessionId {
524 get { throw new NotImplementedException (); }
527 /* the meaning of type is as follows: 0: user, 1: system, 2: total */
528 [MethodImplAttribute(MethodImplOptions.InternalCall)]
529 private extern static long Times (IntPtr handle, int type);
531 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
532 [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
533 public TimeSpan PrivilegedProcessorTime {
535 return new TimeSpan (Times (process_handle, 1));
539 [MethodImplAttribute(MethodImplOptions.InternalCall)]
540 private extern static string ProcessName_internal(IntPtr handle);
542 private string process_name=null;
544 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
545 [MonitoringDescription ("The name of this process.")]
546 public string ProcessName {
548 if(process_name==null) {
550 if (process_handle == IntPtr.Zero)
551 throw new InvalidOperationException ("No process is associated with this object.");
553 process_name=ProcessName_internal(process_handle);
554 /* If process_name is _still_
555 * null, assume the process
558 if (process_name == null)
559 throw new InvalidOperationException ("Process has exited, so the requested information is not available.");
561 /* Strip the suffix (if it
562 * exists) simplistically
563 * instead of removing any
564 * trailing \.???, so we dont
565 * get stupid results on sane
568 if(process_name.EndsWith(".exe") ||
569 process_name.EndsWith(".bat") ||
570 process_name.EndsWith(".com")) {
571 process_name=process_name.Substring(0, process_name.Length-4);
574 return(process_name);
579 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
580 [MonitoringDescription ("Allowed processor that can be used by this process.")]
581 public IntPtr ProcessorAffinity {
590 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
591 [MonitoringDescription ("Is this process responsive.")]
592 public bool Responding {
598 private StreamReader error_stream=null;
600 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
601 [MonitoringDescription ("The standard error stream of this process.")]
602 public StreamReader StandardError {
604 if (error_stream == null)
605 throw new InvalidOperationException("Standard error has not been redirected");
607 if ((async_mode & AsyncModes.AsyncError) != 0)
608 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
610 async_mode |= AsyncModes.SyncError;
612 return(error_stream);
616 private StreamWriter input_stream=null;
618 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
619 [MonitoringDescription ("The standard input stream of this process.")]
620 public StreamWriter StandardInput {
622 if (input_stream == null)
623 throw new InvalidOperationException("Standard input has not been redirected");
625 return(input_stream);
629 private StreamReader output_stream=null;
631 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
632 [MonitoringDescription ("The standard output stream of this process.")]
633 public StreamReader StandardOutput {
635 if (output_stream == null)
636 throw new InvalidOperationException("Standard output has not been redirected");
638 if ((async_mode & AsyncModes.AsyncOutput) != 0)
639 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
641 async_mode |= AsyncModes.SyncOutput;
643 return(output_stream);
647 private ProcessStartInfo start_info=null;
649 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
650 [MonitoringDescription ("Information for the start of this process.")]
651 public ProcessStartInfo StartInfo {
653 if (start_info == null)
654 start_info = new ProcessStartInfo();
659 throw new ArgumentNullException("value");
664 /* Returns the process start time in Windows file
665 * times (ticks from DateTime(1/1/1601 00:00 GMT))
667 [MethodImplAttribute(MethodImplOptions.InternalCall)]
668 private extern static long StartTime_internal(IntPtr handle);
670 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
671 [MonitoringDescription ("The time this process started.")]
672 public DateTime StartTime {
674 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
678 [DefaultValue (null), Browsable (false)]
679 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
680 public ISynchronizeInvoke SynchronizingObject {
681 get { return synchronizingObject; }
682 set { synchronizingObject = value; }
686 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
687 [MonitoringDescription ("The number of threads of this process.")]
688 public ProcessThreadCollection Threads {
690 // This'll return a correctly-sized array of empty ProcessThreads for now.
692 return new ProcessThreadCollection(new ProcessThread[GetProcessData (pid, 0, out error)]);
696 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
697 [MonitoringDescription ("The total CPU time spent for this process.")]
698 public TimeSpan TotalProcessorTime {
700 return new TimeSpan (Times (process_handle, 2));
704 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
705 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
706 public TimeSpan UserProcessorTime {
708 return new TimeSpan (Times (process_handle, 0));
712 [Obsolete ("Use VirtualMemorySize64")]
713 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
714 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
715 public int VirtualMemorySize {
718 return (int)GetProcessData (pid, 7, out error);
722 [Obsolete ("Use WorkingSet64")]
723 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
724 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
725 public int WorkingSet {
728 return (int)GetProcessData (pid, 4, out error);
732 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
733 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
735 public long PrivateMemorySize64 {
738 return GetProcessData (pid, 6, out error);
742 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
743 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
745 public long VirtualMemorySize64 {
748 return GetProcessData (pid, 7, out error);
752 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
753 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
755 public long WorkingSet64 {
758 return GetProcessData (pid, 4, out error);
767 [MethodImplAttribute(MethodImplOptions.InternalCall)]
768 extern static bool Kill_internal (IntPtr handle, int signo);
770 /* int kill -> 1 KILL, 2 CloseMainWindow */
771 bool Close (int signo)
773 if (process_handle == IntPtr.Zero)
774 throw new SystemException ("No process to kill.");
776 int exitcode = ExitCode_internal (process_handle);
778 throw new InvalidOperationException ("The process already finished.");
780 return Kill_internal (process_handle, signo);
783 public bool CloseMainWindow ()
789 public static void EnterDebugMode() {
792 [MethodImplAttribute(MethodImplOptions.InternalCall)]
793 private extern static IntPtr GetProcess_internal(int pid);
795 [MethodImplAttribute(MethodImplOptions.InternalCall)]
796 private extern static int GetPid_internal();
798 public static Process GetCurrentProcess()
800 int pid = GetPid_internal();
801 IntPtr proc = GetProcess_internal(pid);
803 if (proc == IntPtr.Zero)
804 throw new SystemException("Can't find current process");
806 return (new Process (proc, pid));
809 public static Process GetProcessById(int processId)
811 IntPtr proc = GetProcess_internal(processId);
813 if (proc == IntPtr.Zero)
814 throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
816 return (new Process (proc, processId));
819 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
820 public static Process GetProcessById(int processId, string machineName) {
821 if (machineName == null)
822 throw new ArgumentNullException ("machineName");
824 if (!IsLocalMachine (machineName))
825 throw new NotImplementedException ();
827 return GetProcessById (processId);
830 [MethodImplAttribute(MethodImplOptions.InternalCall)]
831 private extern static int[] GetProcesses_internal();
833 public static Process[] GetProcesses()
835 int [] pids = GetProcesses_internal ();
837 return new Process [0];
839 ArrayList proclist = new ArrayList (pids.Length);
840 for (int i = 0; i < pids.Length; i++) {
842 proclist.Add (GetProcessById (pids [i]));
843 } catch (SystemException) {
844 /* The process might exit
846 * GetProcesses_internal and
852 return ((Process []) proclist.ToArray (typeof (Process)));
855 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
856 public static Process[] GetProcesses(string machineName) {
857 if (machineName == null)
858 throw new ArgumentNullException ("machineName");
860 if (!IsLocalMachine (machineName))
861 throw new NotImplementedException ();
863 return GetProcesses ();
866 public static Process[] GetProcessesByName(string processName)
868 int [] pids = GetProcesses_internal ();
870 return new Process [0];
872 ArrayList proclist = new ArrayList (pids.Length);
873 for (int i = 0; i < pids.Length; i++) {
875 Process p = GetProcessById (pids [i]);
876 if (String.Compare (processName, p.ProcessName, true) == 0)
878 } catch (SystemException) {
879 /* The process might exit
881 * GetProcesses_internal and
887 return ((Process []) proclist.ToArray (typeof (Process)));
891 public static Process[] GetProcessesByName(string processName, string machineName) {
892 throw new NotImplementedException();
901 public static void LeaveDebugMode() {
904 public void Refresh ()
906 // FIXME: should refresh any cached data we might have about
907 // the process (currently we have none).
910 [MethodImplAttribute(MethodImplOptions.InternalCall)]
911 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
912 ref ProcInfo proc_info);
914 [MethodImplAttribute(MethodImplOptions.InternalCall)]
915 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
919 ref ProcInfo proc_info);
921 private static bool Start_shell (ProcessStartInfo startInfo, Process process)
923 ProcInfo proc_info=new ProcInfo();
926 if (startInfo.RedirectStandardInput ||
927 startInfo.RedirectStandardOutput ||
928 startInfo.RedirectStandardError) {
929 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
932 if (startInfo.HaveEnvVars)
933 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
935 FillUserInfo (startInfo, ref proc_info);
937 ret = ShellExecuteEx_internal (startInfo,
940 if (proc_info.Password != IntPtr.Zero)
941 Marshal.FreeBSTR (proc_info.Password);
942 proc_info.Password = IntPtr.Zero;
945 throw new Win32Exception (-proc_info.pid);
948 process.process_handle = proc_info.process_handle;
949 process.pid = proc_info.pid;
950 process.StartExitCallbackIfNeeded ();
954 private static bool Start_noshell (ProcessStartInfo startInfo,
957 ProcInfo proc_info=new ProcInfo();
958 IntPtr stdin_rd = IntPtr.Zero, stdin_wr = IntPtr.Zero;
964 if (startInfo.HaveEnvVars) {
965 string [] strs = new string [startInfo.EnvironmentVariables.Count];
966 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
967 proc_info.envKeys = strs;
969 strs = new string [startInfo.EnvironmentVariables.Count];
970 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
971 proc_info.envValues = strs;
974 if (startInfo.RedirectStandardInput == true) {
976 int DUPLICATE_SAME_ACCESS = 0x00000002;
979 ret = MonoIO.CreatePipe (out stdin_rd,
982 ret = MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, stdin_wr_tmp,
983 Process.GetCurrentProcess ().Handle, out stdin_wr, 0, 0, DUPLICATE_SAME_ACCESS);
984 MonoIO.Close (stdin_wr_tmp, out error);
989 ret = MonoIO.CreatePipe (out stdin_rd,
993 throw new IOException ("Error creating standard input pipe");
996 stdin_rd = MonoIO.ConsoleInput;
997 /* This is required to stop the
998 * &$*£ing stupid compiler moaning
999 * that stdin_wr is unassigned, below.
1001 stdin_wr = (IntPtr)0;
1004 if (startInfo.RedirectStandardOutput == true) {
1005 IntPtr out_rd = IntPtr.Zero;
1008 int DUPLICATE_SAME_ACCESS = 0x00000002;
1010 ret = MonoIO.CreatePipe (out out_rd_tmp,
1013 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, out_rd_tmp,
1014 Process.GetCurrentProcess ().Handle, out out_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1015 MonoIO.Close (out_rd_tmp, out error);
1019 ret = MonoIO.CreatePipe (out out_rd,
1023 process.stdout_rd = out_rd;
1025 if (startInfo.RedirectStandardInput == true) {
1026 MonoIO.Close (stdin_rd, out error);
1027 MonoIO.Close (stdin_wr, out error);
1030 throw new IOException ("Error creating standard output pipe");
1033 process.stdout_rd = (IntPtr)0;
1034 stdout_wr = MonoIO.ConsoleOutput;
1037 if (startInfo.RedirectStandardError == true) {
1038 IntPtr err_rd = IntPtr.Zero;
1041 int DUPLICATE_SAME_ACCESS = 0x00000002;
1043 ret = MonoIO.CreatePipe (out err_rd_tmp,
1046 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, err_rd_tmp,
1047 Process.GetCurrentProcess ().Handle, out err_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1048 MonoIO.Close (err_rd_tmp, out error);
1052 ret = MonoIO.CreatePipe (out err_rd,
1056 process.stderr_rd = err_rd;
1058 if (startInfo.RedirectStandardInput == true) {
1059 MonoIO.Close (stdin_rd, out error);
1060 MonoIO.Close (stdin_wr, out error);
1062 if (startInfo.RedirectStandardOutput == true) {
1063 MonoIO.Close (process.stdout_rd, out error);
1064 MonoIO.Close (stdout_wr, out error);
1067 throw new IOException ("Error creating standard error pipe");
1070 process.stderr_rd = (IntPtr)0;
1071 stderr_wr = MonoIO.ConsoleError;
1074 FillUserInfo (startInfo, ref proc_info);
1076 ret = CreateProcess_internal (startInfo,
1077 stdin_rd, stdout_wr, stderr_wr,
1080 if (proc_info.Password != IntPtr.Zero)
1081 Marshal.FreeBSTR (proc_info.Password);
1082 proc_info.Password = IntPtr.Zero;
1085 if (startInfo.RedirectStandardInput == true) {
1086 MonoIO.Close (stdin_rd, out error);
1087 MonoIO.Close (stdin_wr, out error);
1090 if (startInfo.RedirectStandardOutput == true) {
1091 MonoIO.Close (process.stdout_rd, out error);
1092 MonoIO.Close (stdout_wr, out error);
1095 if (startInfo.RedirectStandardError == true) {
1096 MonoIO.Close (process.stderr_rd, out error);
1097 MonoIO.Close (stderr_wr, out error);
1100 throw new Win32Exception (-proc_info.pid,
1101 "ApplicationName='" + startInfo.FileName +
1102 "', CommandLine='" + startInfo.Arguments +
1103 "', CurrentDirectory='" + startInfo.WorkingDirectory +
1104 "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
1107 process.process_handle = proc_info.process_handle;
1108 process.pid = proc_info.pid;
1110 if (startInfo.RedirectStandardInput == true) {
1111 MonoIO.Close (stdin_rd, out error);
1112 process.input_stream = new StreamWriter (new MonoSyncFileStream (stdin_wr, FileAccess.Write, true, 8192), Console.Out.Encoding);
1113 process.input_stream.AutoFlush = true;
1116 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1117 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1119 if (startInfo.RedirectStandardOutput == true) {
1120 MonoIO.Close (stdout_wr, out error);
1121 process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding, true, 8192);
1124 if (startInfo.RedirectStandardError == true) {
1125 MonoIO.Close (stderr_wr, out error);
1126 process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding, true, 8192);
1129 process.StartExitCallbackIfNeeded ();
1134 // Note that ProcInfo.Password must be freed.
1135 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1137 if (startInfo.UserName != null) {
1138 proc_info.UserName = startInfo.UserName;
1139 proc_info.Domain = startInfo.Domain;
1140 if (startInfo.Password != null)
1141 proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1143 proc_info.Password = IntPtr.Zero;
1144 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1148 private static bool Start_common (ProcessStartInfo startInfo,
1151 if (startInfo.FileName == null || startInfo.FileName.Length == 0)
1152 throw new InvalidOperationException("File name has not been set");
1154 if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1155 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1156 if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1157 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1159 if (startInfo.UseShellExecute) {
1160 if (!String.IsNullOrEmpty (startInfo.UserName))
1161 throw new InvalidOperationException ("UserShellExecute must be false if an explicit UserName is specified when starting a process");
1162 return (Start_shell (startInfo, process));
1164 return (Start_noshell (startInfo, process));
1168 public bool Start ()
1170 if (process_handle != IntPtr.Zero) {
1171 Process_free_internal (process_handle);
1172 process_handle = IntPtr.Zero;
1174 return Start_common(start_info, this);
1177 public static Process Start (ProcessStartInfo startInfo)
1179 if (startInfo == null)
1180 throw new ArgumentNullException ("startInfo");
1182 Process process = new Process();
1183 process.StartInfo = startInfo;
1184 if (Start_common(startInfo, process) && process.process_handle != IntPtr.Zero)
1189 public static Process Start (string fileName)
1191 return Start (new ProcessStartInfo (fileName));
1194 public static Process Start(string fileName, string arguments)
1196 return Start (new ProcessStartInfo (fileName, arguments));
1199 public static Process Start(string fileName, string username, SecureString password, string domain) {
1200 return Start(fileName, null, username, password, domain);
1203 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1204 ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1205 psi.UserName = username;
1206 psi.Password = password;
1207 psi.Domain = domain;
1208 psi.UseShellExecute = false;
1212 public override string ToString()
1214 return(base.ToString() + " (" + this.ProcessName + ")");
1217 /* Waits up to ms milliseconds for process 'handle' to
1218 * exit. ms can be <0 to mean wait forever.
1220 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1221 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1223 public void WaitForExit ()
1228 public bool WaitForExit(int milliseconds) {
1229 int ms = milliseconds;
1230 if (ms == int.MaxValue)
1233 DateTime start = DateTime.UtcNow;
1234 if (async_output != null && !async_output.IsCompleted) {
1235 if (false == async_output.WaitHandle.WaitOne (ms, false))
1236 return false; // Timed out
1239 DateTime now = DateTime.UtcNow;
1240 ms -= (int) (now - start).TotalMilliseconds;
1247 if (async_error != null && !async_error.IsCompleted) {
1248 if (false == async_error.WaitHandle.WaitOne (ms, false))
1249 return false; // Timed out
1252 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1257 return WaitForExit_internal (process_handle, ms);
1260 /* Waits up to ms milliseconds for process 'handle' to
1261 * wait for input. ms can be <0 to mean wait forever.
1263 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1264 private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
1266 // The internal call is only implemented properly on Windows.
1268 public bool WaitForInputIdle() {
1269 return WaitForInputIdle (-1);
1272 // The internal call is only implemented properly on Windows.
1274 public bool WaitForInputIdle(int milliseconds) {
1275 return WaitForInputIdle_internal (process_handle, milliseconds);
1278 private static bool IsLocalMachine (string machineName)
1280 if (machineName == "." || machineName.Length == 0)
1283 return (string.Compare (machineName, Environment.MachineName, true) == 0);
1287 [MonitoringDescription ("Raised when it receives output data")]
1288 public event DataReceivedEventHandler OutputDataReceived;
1290 [MonitoringDescription ("Raised when it receives error data")]
1291 public event DataReceivedEventHandler ErrorDataReceived;
1293 void OnOutputDataReceived (string str)
1295 if (OutputDataReceived != null)
1296 OutputDataReceived (this, new DataReceivedEventArgs (str));
1299 void OnErrorDataReceived (string str)
1301 if (ErrorDataReceived != null)
1302 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1310 AsyncOutput = 1 << 2,
1314 [StructLayout (LayoutKind.Sequential)]
1315 sealed class ProcessAsyncReader
1318 The following fields match those of SocketAsyncResult.
1319 This is so that changes needed in the runtime to handle
1320 asynchronous reads are trivial
1321 Keep this in sync with SocketAsyncResult in
1322 ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
1323 in metadata/socket-io.h.
1325 /* DON'T shuffle fields around. DON'T remove fields */
1327 public IntPtr handle;
1328 public object state;
1329 public AsyncCallback callback;
1330 public ManualResetEvent wait_handle;
1332 public Exception delayedException;
1334 public object EndPoint;
1335 byte [] buffer = new byte [4196];
1338 public int SockFlags;
1340 public object AcceptSocket;
1341 public object[] Addresses;
1343 public object Buffers; // Reserve this slot in older profiles
1344 public bool ReuseSocket; // Disconnect
1345 public object acc_socket;
1347 public bool completed_sync;
1349 bool err_out; // true -> stdout, false -> stderr
1351 public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1353 public int EndCalled;
1355 // These fields are not in SocketAsyncResult
1358 StringBuilder sb = new StringBuilder ();
1359 public AsyncReadHandler ReadHandler;
1361 public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1363 this.process = process;
1364 this.handle = handle;
1365 stream = new FileStream (handle, FileAccess.Read, false);
1366 this.ReadHandler = new AsyncReadHandler (AddInput);
1367 this.err_out = err_out;
1370 public void AddInput ()
1373 int nread = stream.Read (buffer, 0, buffer.Length);
1376 if (wait_handle != null)
1383 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1385 // Just in case the encoding fails...
1386 for (int i = 0; i < nread; i++) {
1387 sb.Append ((char) buffer [i]);
1392 ReadHandler.BeginInvoke (null, this);
1400 process.OnOutputDataReceived (null);
1402 process.OnErrorDataReceived (null);
1406 void Flush (bool last)
1408 if (sb.Length == 0 ||
1409 (err_out && process.output_canceled) ||
1410 (!err_out && process.error_canceled))
1413 string total = sb.ToString ();
1415 string [] strs = total.Split ('\n');
1416 int len = strs.Length;
1420 for (int i = 0; i < len - 1; i++) {
1422 process.OnOutputDataReceived (strs [i]);
1424 process.OnErrorDataReceived (strs [i]);
1427 string end = strs [len - 1];
1428 if (last || (len == 1 && end == "")) {
1430 process.OnOutputDataReceived (end);
1432 process.OnErrorDataReceived (end);
1439 public bool IsCompleted {
1440 get { return completed; }
1443 public WaitHandle WaitHandle {
1446 if (wait_handle == null)
1447 wait_handle = new ManualResetEvent (completed);
1453 public void Close () {
1458 AsyncModes async_mode;
1459 bool output_canceled;
1460 bool error_canceled;
1461 ProcessAsyncReader async_output;
1462 ProcessAsyncReader async_error;
1463 delegate void AsyncReadHandler ();
1465 [ComVisibleAttribute(false)]
1466 public void BeginOutputReadLine ()
1468 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1469 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1471 if ((async_mode & AsyncModes.SyncOutput) != 0)
1472 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1474 async_mode |= AsyncModes.AsyncOutput;
1475 output_canceled = false;
1476 if (async_output == null) {
1477 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1478 async_output.ReadHandler.BeginInvoke (null, async_output);
1482 [ComVisibleAttribute(false)]
1483 public void CancelOutputRead ()
1485 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1486 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1488 if ((async_mode & AsyncModes.SyncOutput) != 0)
1489 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1491 if (async_output == null)
1492 throw new InvalidOperationException ("No async operation in progress.");
1494 output_canceled = true;
1497 [ComVisibleAttribute(false)]
1498 public void BeginErrorReadLine ()
1500 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1501 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1503 if ((async_mode & AsyncModes.SyncError) != 0)
1504 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1506 async_mode |= AsyncModes.AsyncError;
1507 error_canceled = false;
1508 if (async_error == null) {
1509 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1510 async_error.ReadHandler.BeginInvoke (null, async_error);
1514 [ComVisibleAttribute(false)]
1515 public void CancelErrorRead ()
1517 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1518 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1520 if ((async_mode & AsyncModes.SyncOutput) != 0)
1521 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1523 if (async_error == null)
1524 throw new InvalidOperationException ("No async operation in progress.");
1526 error_canceled = true;
1529 [Category ("Behavior")]
1530 [MonitoringDescription ("Raised when this process exits.")]
1531 public event EventHandler Exited {
1533 if (process_handle != IntPtr.Zero && HasExited) {
1534 value.BeginInvoke (null, null, null, null);
1536 exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1537 if (exited_event != null)
1538 StartExitCallbackIfNeeded ();
1542 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1546 // Closes the system process handle
1547 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1548 private extern void Process_free_internal(IntPtr handle);
1550 private bool disposed = false;
1552 protected override void Dispose(bool disposing) {
1553 // Check to see if Dispose has already been called.
1554 if(this.disposed == false) {
1556 // If this is a call to Dispose,
1557 // dispose all managed resources.
1561 /* These have open FileStreams on the pipes we are about to close */
1562 if (async_output != null)
1563 async_output.Close ();
1564 if (async_error != null)
1565 async_error.Close ();
1567 if (input_stream != null) {
1568 input_stream.Close();
1569 input_stream = null;
1572 if (output_stream != null) {
1573 output_stream.Close();
1574 output_stream = null;
1577 if (error_stream != null) {
1578 error_stream.Close();
1579 error_stream = null;
1584 // Release unmanaged resources
1587 if(process_handle!=IntPtr.Zero) {
1588 Process_free_internal(process_handle);
1589 process_handle=IntPtr.Zero;
1593 base.Dispose (disposing);
1601 static void CBOnExit (object state, bool unused)
1603 Process p = (Process) state;
1604 p.already_waiting = false;
1608 protected void OnExited()
1610 if (exited_event == null)
1613 if (synchronizingObject == null) {
1614 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1616 d (this, EventArgs.Empty);
1622 object [] args = new object [] {this, EventArgs.Empty};
1623 synchronizingObject.BeginInvoke (exited_event, args);
1626 static bool IsWindows
1630 PlatformID platform = Environment.OSVersion.Platform;
1631 if (platform == PlatformID.Win32S ||
1632 platform == PlatformID.Win32Windows ||
1633 platform == PlatformID.Win32NT ||
1634 platform == PlatformID.WinCE) {
1641 class ProcessWaitHandle : WaitHandle
1643 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1644 private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1646 public ProcessWaitHandle (IntPtr handle)
1648 // Need to keep a reference to this handle,
1649 // in case the Process object is collected
1650 Handle = ProcessHandle_duplicate (handle);
1652 // When the wait handle is disposed, the duplicated handle will be
1653 // closed, so no need to override dispose (bug #464628).