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)]
53 [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 bool enableRaisingEvents;
81 ISynchronizeInvoke synchronizingObject;
82 EventHandler exited_event;
86 /* Private constructor called from other methods */
87 private Process(IntPtr handle, int id) {
88 process_handle=handle;
97 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
98 [MonitoringDescription ("Base process priority.")]
99 public int BasePriority {
105 void StartExitCallbackIfNeeded ()
108 bool start = (!already_waiting && enableRaisingEvents && exited_event != null);
109 if (start && process_handle != IntPtr.Zero) {
110 WaitOrTimerCallback cb = new WaitOrTimerCallback (CBOnExit);
111 ProcessWaitHandle h = new ProcessWaitHandle (process_handle);
112 ThreadPool.RegisterWaitForSingleObject (h, cb, this, -1, true);
113 already_waiting = true;
118 [DefaultValue (false), Browsable (false)]
119 [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
120 public bool EnableRaisingEvents {
122 return enableRaisingEvents;
125 bool prev = enableRaisingEvents;
126 enableRaisingEvents = value;
127 if (enableRaisingEvents && !prev)
128 StartExitCallbackIfNeeded ();
133 [MethodImplAttribute(MethodImplOptions.InternalCall)]
134 private extern static int ExitCode_internal(IntPtr handle);
136 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
137 [MonitoringDescription ("The exit code of the process.")]
138 public int ExitCode {
140 if (process_handle == IntPtr.Zero)
141 throw new InvalidOperationException ("Process has not been started.");
143 int code = ExitCode_internal (process_handle);
145 throw new InvalidOperationException ("The process must exit before " +
146 "getting the requested information.");
152 /* Returns the process start time in Windows file
153 * times (ticks from DateTime(1/1/1601 00:00 GMT))
155 [MethodImplAttribute(MethodImplOptions.InternalCall)]
156 private extern static long ExitTime_internal(IntPtr handle);
158 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
159 [MonitoringDescription ("The exit time of the process.")]
160 public DateTime ExitTime {
162 if (process_handle == IntPtr.Zero)
163 throw new InvalidOperationException ("Process has not been started.");
166 throw new InvalidOperationException ("The process must exit before " +
167 "getting the requested information.");
169 return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
173 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
174 [MonitoringDescription ("Handle for this process.")]
175 public IntPtr Handle {
177 return(process_handle);
182 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
183 [MonitoringDescription ("Handles for this process.")]
184 public int HandleCount {
190 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
191 [MonitoringDescription ("Determines if the process is still running.")]
192 public bool HasExited {
194 if (process_handle == IntPtr.Zero)
195 throw new InvalidOperationException ("Process has not been started.");
197 int exitcode = ExitCode_internal (process_handle);
208 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
209 [MonitoringDescription ("Process identifier.")]
213 throw new InvalidOperationException ("Process ID has not been set.");
220 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
221 [MonitoringDescription ("The name of the computer running the process.")]
222 public string MachineName {
228 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
229 [MonitoringDescription ("The main module of the process.")]
230 public ProcessModule MainModule {
232 return(this.Modules[0]);
237 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
238 [MonitoringDescription ("The handle of the main window of the process.")]
239 public IntPtr MainWindowHandle {
246 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
247 [MonitoringDescription ("The title of the main window of the process.")]
248 public string MainWindowTitle {
254 [MethodImplAttribute(MethodImplOptions.InternalCall)]
255 private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
256 [MethodImplAttribute(MethodImplOptions.InternalCall)]
257 private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);
259 /* LAMESPEC: why is this an IntPtr not a plain int? */
260 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
261 [MonitoringDescription ("The maximum working set for this process.")]
262 public IntPtr MaxWorkingSet {
265 throw new InvalidOperationException(
266 "The process " + ProcessName +
267 " (ID " + Id + ") has exited");
271 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
273 throw new Win32Exception();
280 throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
283 bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
285 throw new Win32Exception();
290 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
291 [MonitoringDescription ("The minimum working set for this process.")]
292 public IntPtr MinWorkingSet {
295 throw new InvalidOperationException(
296 "The process " + ProcessName +
297 " (ID " + Id + ") has exited");
301 bool ok= GetWorkingSet_internal (process_handle, out min, out max);
303 throw new Win32Exception();
304 return ((IntPtr) min);
308 throw new InvalidOperationException(
309 "The process " + ProcessName +
310 " (ID " + Id + ") has exited");
312 bool ok = SetWorkingSet_internal (process_handle, value.ToInt32(), 0, true);
314 throw new Win32Exception();
318 /* Returns the list of process modules. The main module is
321 [MethodImplAttribute(MethodImplOptions.InternalCall)]
322 private extern ProcessModule[] GetModules_internal(IntPtr handle);
324 private ProcessModuleCollection module_collection;
326 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
327 [MonitoringDescription ("The modules that are loaded as part of this process.")]
328 public ProcessModuleCollection Modules {
330 if (module_collection == null)
331 module_collection = new ProcessModuleCollection(
332 GetModules_internal (process_handle));
333 return(module_collection);
337 /* data type is from the MonoProcessData enum in mono-proclib.h in the runtime */
338 [MethodImplAttribute(MethodImplOptions.InternalCall)]
339 private extern static long GetProcessData (int pid, int data_type, out int error);
343 [Obsolete ("Use NonpagedSystemMemorySize64")]
345 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
346 [MonitoringDescription ("The number of bytes that are not pageable.")]
347 public int NonpagedSystemMemorySize {
355 [Obsolete ("Use PagedMemorySize64")]
357 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
358 [MonitoringDescription ("The number of bytes that are paged.")]
359 public int PagedMemorySize {
367 [Obsolete ("Use PagedSystemMemorySize64")]
369 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
370 [MonitoringDescription ("The amount of paged system memory in bytes.")]
371 public int PagedSystemMemorySize {
379 [Obsolete ("Use PeakPagedMemorySize64")]
381 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
382 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
383 public int PeakPagedMemorySize {
390 [Obsolete ("Use PeakVirtualMemorySize64")]
392 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
393 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
394 public int PeakVirtualMemorySize {
397 return (int)GetProcessData (pid, 8, out error);
402 [Obsolete ("Use PeakWorkingSet64")]
404 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
405 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
406 public int PeakWorkingSet {
409 return (int)GetProcessData (pid, 5, out error);
415 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
416 [MonitoringDescription ("The number of bytes that are not pageable.")]
418 public long NonpagedSystemMemorySize64 {
425 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
426 [MonitoringDescription ("The number of bytes that are paged.")]
428 public long PagedMemorySize64 {
435 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
436 [MonitoringDescription ("The amount of paged system memory in bytes.")]
438 public long PagedSystemMemorySize64 {
445 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
446 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
448 public long PeakPagedMemorySize64 {
454 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
455 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
457 public long PeakVirtualMemorySize64 {
460 return GetProcessData (pid, 8, out error);
464 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
465 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
467 public long PeakWorkingSet64 {
470 return GetProcessData (pid, 5, out error);
476 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
477 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
478 public bool PriorityBoostEnabled {
486 [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
487 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
488 [MonitoringDescription ("The relative process priority.")]
489 public ProcessPriorityClass PriorityClass {
491 if (process_handle == IntPtr.Zero)
492 throw new InvalidOperationException ("Process has not been started.");
495 int prio = GetPriorityClass (process_handle, out error);
497 throw new Win32Exception (error);
498 return (ProcessPriorityClass) prio;
501 if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
502 throw new InvalidEnumArgumentException (
503 "value", (int) value,
504 typeof (ProcessPriorityClass));
506 if (process_handle == IntPtr.Zero)
507 throw new InvalidOperationException ("Process has not been started.");
510 if (!SetPriorityClass (process_handle, (int) value, out error)) {
512 throw new Win32Exception (error);
517 void CheckExited () {
519 throw new InvalidOperationException (String.Format ("Cannot process request because the process ({0}) has exited.", Id));
522 [MethodImplAttribute(MethodImplOptions.InternalCall)]
523 static extern int GetPriorityClass (IntPtr handle, out int error);
525 [MethodImplAttribute(MethodImplOptions.InternalCall)]
526 static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);
528 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
529 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
531 [Obsolete ("Use PrivateMemorySize64")]
533 public int PrivateMemorySize {
536 return (int)GetProcessData (pid, 6, out error);
541 [MonoNotSupported ("")]
542 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
543 [MonitoringDescription ("The session ID for this process.")]
544 public int SessionId {
545 get { throw new NotImplementedException (); }
549 /* the meaning of type is as follows: 0: user, 1: system, 2: total */
550 [MethodImplAttribute(MethodImplOptions.InternalCall)]
551 private extern static long Times (IntPtr handle, int type);
553 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
554 [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
555 public TimeSpan PrivilegedProcessorTime {
557 return new TimeSpan (Times (process_handle, 1));
561 [MethodImplAttribute(MethodImplOptions.InternalCall)]
562 private extern static string ProcessName_internal(IntPtr handle);
564 private string process_name=null;
566 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
567 [MonitoringDescription ("The name of this process.")]
568 public string ProcessName {
570 if(process_name==null) {
572 if (process_handle == IntPtr.Zero)
573 throw new InvalidOperationException ("No process is associated with this object.");
575 process_name=ProcessName_internal(process_handle);
576 /* If process_name is _still_
577 * null, assume the process
580 if (process_name == null)
581 throw new InvalidOperationException ("Process has exited, so the requested information is not available.");
583 /* Strip the suffix (if it
584 * exists) simplistically
585 * instead of removing any
586 * trailing \.???, so we dont
587 * get stupid results on sane
590 if(process_name.EndsWith(".exe") ||
591 process_name.EndsWith(".bat") ||
592 process_name.EndsWith(".com")) {
593 process_name=process_name.Substring(0, process_name.Length-4);
596 return(process_name);
601 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
602 [MonitoringDescription ("Allowed processor that can be used by this process.")]
603 public IntPtr ProcessorAffinity {
612 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
613 [MonitoringDescription ("Is this process responsive.")]
614 public bool Responding {
620 private StreamReader error_stream=null;
622 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
623 [MonitoringDescription ("The standard error stream of this process.")]
624 public StreamReader StandardError {
626 if (error_stream == null)
627 throw new InvalidOperationException("Standard error has not been redirected");
630 if ((async_mode & AsyncModes.AsyncError) != 0)
631 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
633 async_mode |= AsyncModes.SyncError;
636 return(error_stream);
640 private StreamWriter input_stream=null;
642 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
643 [MonitoringDescription ("The standard input stream of this process.")]
644 public StreamWriter StandardInput {
646 if (input_stream == null)
647 throw new InvalidOperationException("Standard input has not been redirected");
649 return(input_stream);
653 private StreamReader output_stream=null;
655 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
656 [MonitoringDescription ("The standard output stream of this process.")]
657 public StreamReader StandardOutput {
659 if (output_stream == null)
660 throw new InvalidOperationException("Standard output has not been redirected");
663 if ((async_mode & AsyncModes.AsyncOutput) != 0)
664 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
666 async_mode |= AsyncModes.SyncOutput;
669 return(output_stream);
673 private ProcessStartInfo start_info=null;
675 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
676 [MonitoringDescription ("Information for the start of this process.")]
677 public ProcessStartInfo StartInfo {
679 if (start_info == null)
680 start_info = new ProcessStartInfo();
685 throw new ArgumentNullException("value");
690 /* Returns the process start time in Windows file
691 * times (ticks from DateTime(1/1/1601 00:00 GMT))
693 [MethodImplAttribute(MethodImplOptions.InternalCall)]
694 private extern static long StartTime_internal(IntPtr handle);
696 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
697 [MonitoringDescription ("The time this process started.")]
698 public DateTime StartTime {
700 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
704 [DefaultValue (null), Browsable (false)]
705 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
706 public ISynchronizeInvoke SynchronizingObject {
707 get { return synchronizingObject; }
708 set { synchronizingObject = value; }
712 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
713 [MonitoringDescription ("The number of threads of this process.")]
714 public ProcessThreadCollection Threads {
716 return ProcessThreadCollection.GetEmpty ();
720 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
721 [MonitoringDescription ("The total CPU time spent for this process.")]
722 public TimeSpan TotalProcessorTime {
724 return new TimeSpan (Times (process_handle, 2));
728 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
729 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
730 public TimeSpan UserProcessorTime {
732 return new TimeSpan (Times (process_handle, 0));
737 [Obsolete ("Use VirtualMemorySize64")]
739 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
740 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
741 public int VirtualMemorySize {
744 return (int)GetProcessData (pid, 7, out error);
749 [Obsolete ("Use WorkingSet64")]
751 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
752 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
753 public int WorkingSet {
756 return (int)GetProcessData (pid, 4, out error);
761 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
762 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
764 public long PrivateMemorySize64 {
767 return GetProcessData (pid, 6, out error);
771 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
772 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
774 public long VirtualMemorySize64 {
777 return GetProcessData (pid, 7, out error);
781 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
782 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
784 public long WorkingSet64 {
787 return GetProcessData (pid, 4, out error);
797 [MethodImplAttribute(MethodImplOptions.InternalCall)]
798 extern static bool Kill_internal (IntPtr handle, int signo);
800 /* int kill -> 1 KILL, 2 CloseMainWindow */
801 bool Close (int signo)
803 if (process_handle == IntPtr.Zero)
804 throw new SystemException ("No process to kill.");
806 int exitcode = ExitCode_internal (process_handle);
808 throw new InvalidOperationException ("The process already finished.");
810 return Kill_internal (process_handle, signo);
813 public bool CloseMainWindow ()
819 public static void EnterDebugMode() {
822 [MethodImplAttribute(MethodImplOptions.InternalCall)]
823 private extern static IntPtr GetProcess_internal(int pid);
825 [MethodImplAttribute(MethodImplOptions.InternalCall)]
826 private extern static int GetPid_internal();
828 public static Process GetCurrentProcess()
830 int pid = GetPid_internal();
831 IntPtr proc = GetProcess_internal(pid);
833 if (proc == IntPtr.Zero)
834 throw new SystemException("Can't find current process");
836 return (new Process (proc, pid));
839 public static Process GetProcessById(int processId)
841 IntPtr proc = GetProcess_internal(processId);
843 if (proc == IntPtr.Zero)
844 throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
846 return (new Process (proc, processId));
849 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
850 public static Process GetProcessById(int processId, string machineName) {
851 if (machineName == null)
852 throw new ArgumentNullException ("machineName");
854 if (!IsLocalMachine (machineName))
855 throw new NotImplementedException ();
857 return GetProcessById (processId);
860 [MethodImplAttribute(MethodImplOptions.InternalCall)]
861 private extern static int[] GetProcesses_internal();
863 public static Process[] GetProcesses()
865 int [] pids = GetProcesses_internal ();
867 return new Process [0];
869 ArrayList proclist = new ArrayList (pids.Length);
870 for (int i = 0; i < pids.Length; i++) {
872 proclist.Add (GetProcessById (pids [i]));
873 } catch (SystemException) {
874 /* The process might exit
876 * GetProcesses_internal and
882 return ((Process []) proclist.ToArray (typeof (Process)));
885 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
886 public static Process[] GetProcesses(string machineName) {
887 if (machineName == null)
888 throw new ArgumentNullException ("machineName");
890 if (!IsLocalMachine (machineName))
891 throw new NotImplementedException ();
893 return GetProcesses ();
896 public static Process[] GetProcessesByName(string processName)
898 int [] pids = GetProcesses_internal ();
900 return new Process [0];
902 ArrayList proclist = new ArrayList (pids.Length);
903 for (int i = 0; i < pids.Length; i++) {
905 Process p = GetProcessById (pids [i]);
906 if (String.Compare (processName, p.ProcessName, true) == 0)
908 } catch (SystemException) {
909 /* The process might exit
911 * GetProcesses_internal and
917 return ((Process []) proclist.ToArray (typeof (Process)));
921 public static Process[] GetProcessesByName(string processName, string machineName) {
922 throw new NotImplementedException();
931 public static void LeaveDebugMode() {
934 public void Refresh ()
936 // FIXME: should refresh any cached data we might have about
937 // the process (currently we have none).
940 [MethodImplAttribute(MethodImplOptions.InternalCall)]
941 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
942 ref ProcInfo proc_info);
944 [MethodImplAttribute(MethodImplOptions.InternalCall)]
945 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
949 ref ProcInfo proc_info);
951 private static bool Start_shell (ProcessStartInfo startInfo,
954 ProcInfo proc_info=new ProcInfo();
957 if (startInfo.RedirectStandardInput ||
958 startInfo.RedirectStandardOutput ||
959 startInfo.RedirectStandardError) {
960 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
963 if (startInfo.HaveEnvVars)
964 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
966 FillUserInfo (startInfo, ref proc_info);
968 ret = ShellExecuteEx_internal (startInfo,
971 if (proc_info.Password != IntPtr.Zero)
972 Marshal.FreeBSTR (proc_info.Password);
973 proc_info.Password = IntPtr.Zero;
976 throw new Win32Exception (-proc_info.pid);
979 process.process_handle = proc_info.process_handle;
980 process.pid = proc_info.pid;
982 process.StartExitCallbackIfNeeded ();
987 private static bool Start_noshell (ProcessStartInfo startInfo,
990 ProcInfo proc_info=new ProcInfo();
991 IntPtr stdin_rd = IntPtr.Zero, stdin_wr = IntPtr.Zero;
997 if (startInfo.HaveEnvVars) {
998 string [] strs = new string [startInfo.EnvironmentVariables.Count];
999 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
1000 proc_info.envKeys = strs;
1002 strs = new string [startInfo.EnvironmentVariables.Count];
1003 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
1004 proc_info.envValues = strs;
1007 if (startInfo.RedirectStandardInput == true) {
1009 int DUPLICATE_SAME_ACCESS = 0x00000002;
1010 IntPtr stdin_wr_tmp;
1012 ret = MonoIO.CreatePipe (out stdin_rd,
1015 ret = MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, stdin_wr_tmp,
1016 Process.GetCurrentProcess ().Handle, out stdin_wr, 0, 0, DUPLICATE_SAME_ACCESS);
1017 MonoIO.Close (stdin_wr_tmp, out error);
1022 ret = MonoIO.CreatePipe (out stdin_rd,
1026 throw new IOException ("Error creating standard input pipe");
1029 stdin_rd = MonoIO.ConsoleInput;
1030 /* This is required to stop the
1031 * &$*£ing stupid compiler moaning
1032 * that stdin_wr is unassigned, below.
1034 stdin_wr = (IntPtr)0;
1037 if (startInfo.RedirectStandardOutput == true) {
1038 IntPtr out_rd = IntPtr.Zero;
1041 int DUPLICATE_SAME_ACCESS = 0x00000002;
1043 ret = MonoIO.CreatePipe (out out_rd_tmp,
1046 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, out_rd_tmp,
1047 Process.GetCurrentProcess ().Handle, out out_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1048 MonoIO.Close (out_rd_tmp, out error);
1052 ret = MonoIO.CreatePipe (out out_rd,
1056 process.stdout_rd = out_rd;
1058 if (startInfo.RedirectStandardInput == true) {
1059 MonoIO.Close (stdin_rd, out error);
1060 MonoIO.Close (stdin_wr, out error);
1063 throw new IOException ("Error creating standard output pipe");
1066 process.stdout_rd = (IntPtr)0;
1067 stdout_wr = MonoIO.ConsoleOutput;
1070 if (startInfo.RedirectStandardError == true) {
1071 IntPtr err_rd = IntPtr.Zero;
1074 int DUPLICATE_SAME_ACCESS = 0x00000002;
1076 ret = MonoIO.CreatePipe (out err_rd_tmp,
1079 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, err_rd_tmp,
1080 Process.GetCurrentProcess ().Handle, out err_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1081 MonoIO.Close (err_rd_tmp, out error);
1085 ret = MonoIO.CreatePipe (out err_rd,
1089 process.stderr_rd = err_rd;
1091 if (startInfo.RedirectStandardInput == true) {
1092 MonoIO.Close (stdin_rd, out error);
1093 MonoIO.Close (stdin_wr, out error);
1095 if (startInfo.RedirectStandardOutput == true) {
1096 MonoIO.Close (process.stdout_rd, out error);
1097 MonoIO.Close (stdout_wr, out error);
1100 throw new IOException ("Error creating standard error pipe");
1103 process.stderr_rd = (IntPtr)0;
1104 stderr_wr = MonoIO.ConsoleError;
1107 FillUserInfo (startInfo, ref proc_info);
1109 ret = CreateProcess_internal (startInfo,
1110 stdin_rd, stdout_wr, stderr_wr,
1113 if (proc_info.Password != IntPtr.Zero)
1114 Marshal.FreeBSTR (proc_info.Password);
1115 proc_info.Password = IntPtr.Zero;
1118 if (startInfo.RedirectStandardInput == true) {
1119 MonoIO.Close (stdin_rd, out error);
1120 MonoIO.Close (stdin_wr, out error);
1123 if (startInfo.RedirectStandardOutput == true) {
1124 MonoIO.Close (process.stdout_rd, out error);
1125 MonoIO.Close (stdout_wr, out error);
1128 if (startInfo.RedirectStandardError == true) {
1129 MonoIO.Close (process.stderr_rd, out error);
1130 MonoIO.Close (stderr_wr, out error);
1133 throw new Win32Exception (-proc_info.pid,
1134 "ApplicationName='" + startInfo.FileName +
1135 "', CommandLine='" + startInfo.Arguments +
1136 "', CurrentDirectory='" + startInfo.WorkingDirectory +
1137 "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
1140 process.process_handle = proc_info.process_handle;
1141 process.pid = proc_info.pid;
1143 if (startInfo.RedirectStandardInput == true) {
1144 MonoIO.Close (stdin_rd, out error);
1145 process.input_stream = new StreamWriter (new MonoSyncFileStream (stdin_wr, FileAccess.Write, true, 8192), Console.Out.Encoding);
1146 process.input_stream.AutoFlush = true;
1150 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1151 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1153 Encoding stdoutEncoding = Console.Out.Encoding;
1154 Encoding stderrEncoding = stdoutEncoding;
1157 if (startInfo.RedirectStandardOutput == true) {
1158 MonoIO.Close (stdout_wr, out error);
1159 process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding, true, 8192);
1162 if (startInfo.RedirectStandardError == true) {
1163 MonoIO.Close (stderr_wr, out error);
1164 process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding, true, 8192);
1167 process.StartExitCallbackIfNeeded ();
1172 // Note that ProcInfo.Password must be freed.
1173 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1176 if (startInfo.UserName != null) {
1177 proc_info.UserName = startInfo.UserName;
1178 proc_info.Domain = startInfo.Domain;
1179 if (startInfo.Password != null)
1180 proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1182 proc_info.Password = IntPtr.Zero;
1183 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1188 private static bool Start_common (ProcessStartInfo startInfo,
1191 if (startInfo.FileName == null || startInfo.FileName.Length == 0)
1192 throw new InvalidOperationException("File name has not been set");
1195 if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1196 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1197 if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1198 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1201 if (startInfo.UseShellExecute) {
1203 if (!String.IsNullOrEmpty (startInfo.UserName))
1204 throw new InvalidOperationException ("UserShellExecute must be false if an explicit UserName is specified when starting a process");
1206 return (Start_shell (startInfo, process));
1208 return (Start_noshell (startInfo, process));
1212 public bool Start ()
1214 if (process_handle != IntPtr.Zero) {
1215 Process_free_internal (process_handle);
1216 process_handle = IntPtr.Zero;
1218 return Start_common(start_info, this);
1221 public static Process Start (ProcessStartInfo startInfo)
1223 if (startInfo == null)
1224 throw new ArgumentNullException ("startInfo");
1226 Process process=new Process();
1227 process.StartInfo = startInfo;
1228 if (Start_common(startInfo, process))
1233 public static Process Start (string fileName)
1235 return Start (new ProcessStartInfo (fileName));
1238 public static Process Start(string fileName, string arguments)
1240 return Start (new ProcessStartInfo (fileName, arguments));
1244 public static Process Start(string fileName, string username, SecureString password, string domain) {
1245 return Start(fileName, null, username, password, domain);
1248 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1249 ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1250 psi.UserName = username;
1251 psi.Password = password;
1252 psi.Domain = domain;
1253 psi.UseShellExecute = false;
1258 public override string ToString()
1260 return(base.ToString() + " (" + this.ProcessName + ")");
1263 /* Waits up to ms milliseconds for process 'handle' to
1264 * exit. ms can be <0 to mean wait forever.
1266 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1267 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1269 public void WaitForExit ()
1274 public bool WaitForExit(int milliseconds) {
1275 int ms = milliseconds;
1276 if (ms == int.MaxValue)
1280 DateTime start = DateTime.UtcNow;
1281 if (async_output != null && !async_output.IsCompleted) {
1282 if (false == async_output.WaitHandle.WaitOne (ms, false))
1283 return false; // Timed out
1286 DateTime now = DateTime.UtcNow;
1287 ms -= (int) (now - start).TotalMilliseconds;
1294 if (async_error != null && !async_error.IsCompleted) {
1295 if (false == async_error.WaitHandle.WaitOne (ms, false))
1296 return false; // Timed out
1299 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1305 return WaitForExit_internal (process_handle, ms);
1308 /* Waits up to ms milliseconds for process 'handle' to
1309 * wait for input. ms can be <0 to mean wait forever.
1311 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1312 private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
1314 // The internal call is only implemented properly on Windows.
1316 public bool WaitForInputIdle() {
1317 return WaitForInputIdle (-1);
1320 // The internal call is only implemented properly on Windows.
1322 public bool WaitForInputIdle(int milliseconds) {
1323 return WaitForInputIdle_internal (process_handle, milliseconds);
1326 private static bool IsLocalMachine (string machineName)
1328 if (machineName == "." || machineName.Length == 0)
1331 return (string.Compare (machineName, Environment.MachineName, true) == 0);
1336 [MonitoringDescription ("Raised when it receives output data")]
1337 public event DataReceivedEventHandler OutputDataReceived;
1339 [MonitoringDescription ("Raised when it receives error data")]
1340 public event DataReceivedEventHandler ErrorDataReceived;
1342 void OnOutputDataReceived (string str)
1344 if (OutputDataReceived != null)
1345 OutputDataReceived (this, new DataReceivedEventArgs (str));
1348 void OnErrorDataReceived (string str)
1350 if (ErrorDataReceived != null)
1351 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1359 AsyncOutput = 1 << 2,
1363 [StructLayout (LayoutKind.Sequential)]
1364 sealed class ProcessAsyncReader
1367 The following fields match those of SocketAsyncResult.
1368 This is so that changes needed in the runtime to handle
1369 asynchronous reads are trivial
1370 Keep this in sync with SocketAsyncResult in
1371 ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
1372 in metadata/socket-io.h.
1374 /* DON'T shuffle fields around. DON'T remove fields */
1376 public IntPtr handle;
1377 public object state;
1378 public AsyncCallback callback;
1379 public ManualResetEvent wait_handle;
1381 public Exception delayedException;
1383 public object EndPoint;
1384 byte [] buffer = new byte [4196];
1387 public int SockFlags;
1389 public object AcceptSocket;
1390 public object[] Addresses;
1392 public object Buffers; // Reserve this slot in older profiles
1393 public bool ReuseSocket; // Disconnect
1394 public object acc_socket;
1396 public bool completed_sync;
1398 bool err_out; // true -> stdout, false -> stderr
1400 public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1402 public int EndCalled;
1404 // These fields are not in SocketAsyncResult
1407 StringBuilder sb = new StringBuilder ();
1408 public AsyncReadHandler ReadHandler;
1410 public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1412 this.process = process;
1413 this.handle = handle;
1414 stream = new FileStream (handle, FileAccess.Read, false);
1415 this.ReadHandler = new AsyncReadHandler (AddInput);
1416 this.err_out = err_out;
1419 public void AddInput ()
1422 int nread = stream.Read (buffer, 0, buffer.Length);
1425 if (wait_handle != null)
1432 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1434 // Just in case the encoding fails...
1435 for (int i = 0; i < nread; i++) {
1436 sb.Append ((char) buffer [i]);
1441 ReadHandler.BeginInvoke (null, this);
1449 process.OnOutputDataReceived (null);
1451 process.OnErrorDataReceived (null);
1455 void Flush (bool last)
1457 if (sb.Length == 0 ||
1458 (err_out && process.output_canceled) ||
1459 (!err_out && process.error_canceled))
1462 string total = sb.ToString ();
1464 string [] strs = total.Split ('\n');
1465 int len = strs.Length;
1469 for (int i = 0; i < len - 1; i++) {
1471 process.OnOutputDataReceived (strs [i]);
1473 process.OnErrorDataReceived (strs [i]);
1476 string end = strs [len - 1];
1477 if (last || (len == 1 && end == "")) {
1479 process.OnOutputDataReceived (end);
1481 process.OnErrorDataReceived (end);
1488 public bool IsCompleted {
1489 get { return completed; }
1492 public WaitHandle WaitHandle {
1495 if (wait_handle == null)
1496 wait_handle = new ManualResetEvent (completed);
1502 public void Close () {
1507 AsyncModes async_mode;
1508 bool output_canceled;
1509 bool error_canceled;
1510 ProcessAsyncReader async_output;
1511 ProcessAsyncReader async_error;
1512 delegate void AsyncReadHandler ();
1514 [ComVisibleAttribute(false)]
1515 public void BeginOutputReadLine ()
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 ("Cannot mix asynchronous and synchonous reads.");
1523 async_mode |= AsyncModes.AsyncOutput;
1524 output_canceled = false;
1525 if (async_output == null) {
1526 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1527 async_output.ReadHandler.BeginInvoke (null, async_output);
1531 [ComVisibleAttribute(false)]
1532 public void CancelOutputRead ()
1534 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1535 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1537 if ((async_mode & AsyncModes.SyncOutput) != 0)
1538 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1540 if (async_output == null)
1541 throw new InvalidOperationException ("No async operation in progress.");
1543 output_canceled = true;
1546 [ComVisibleAttribute(false)]
1547 public void BeginErrorReadLine ()
1549 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1550 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1552 if ((async_mode & AsyncModes.SyncError) != 0)
1553 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1555 async_mode |= AsyncModes.AsyncError;
1556 error_canceled = false;
1557 if (async_error == null) {
1558 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1559 async_error.ReadHandler.BeginInvoke (null, async_error);
1563 [ComVisibleAttribute(false)]
1564 public void CancelErrorRead ()
1566 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1567 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1569 if ((async_mode & AsyncModes.SyncOutput) != 0)
1570 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1572 if (async_error == null)
1573 throw new InvalidOperationException ("No async operation in progress.");
1575 error_canceled = true;
1579 [Category ("Behavior")]
1580 [MonitoringDescription ("Raised when this process exits.")]
1581 public event EventHandler Exited {
1583 if (process_handle != IntPtr.Zero && HasExited) {
1584 value.BeginInvoke (null, null, null, null);
1586 exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1587 if (exited_event != null)
1588 StartExitCallbackIfNeeded ();
1592 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1596 // Closes the system process handle
1597 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1598 private extern void Process_free_internal(IntPtr handle);
1600 private bool disposed = false;
1602 protected override void Dispose(bool disposing) {
1603 // Check to see if Dispose has already been called.
1604 if(this.disposed == false) {
1606 // If this is a call to Dispose,
1607 // dispose all managed resources.
1611 /* These have open FileStreams on the pipes we are about to close */
1612 if (async_output != null)
1613 async_output.Close ();
1614 if (async_error != null)
1615 async_error.Close ();
1619 // Release unmanaged resources
1622 if(process_handle!=IntPtr.Zero) {
1623 Process_free_internal(process_handle);
1624 process_handle=IntPtr.Zero;
1627 if (input_stream != null) {
1628 input_stream.Close();
1629 input_stream = null;
1632 if (output_stream != null) {
1633 output_stream.Close();
1634 output_stream = null;
1637 if (error_stream != null) {
1638 error_stream.Close();
1639 error_stream = null;
1643 base.Dispose (disposing);
1651 static void CBOnExit (object state, bool unused)
1653 Process p = (Process) state;
1654 p.already_waiting = false;
1658 protected void OnExited()
1660 if (exited_event == null)
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).