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 ()
106 bool start = (!already_waiting && enableRaisingEvents && exited_event != null);
107 if (start && process_handle != IntPtr.Zero) {
108 WaitOrTimerCallback cb = new WaitOrTimerCallback (CBOnExit);
109 ProcessWaitHandle h = new ProcessWaitHandle (process_handle);
110 ThreadPool.RegisterWaitForSingleObject (h, cb, this, -1, true);
111 already_waiting = true;
116 [DefaultValue (false), Browsable (false)]
117 [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
118 public bool EnableRaisingEvents {
120 return enableRaisingEvents;
123 bool prev = enableRaisingEvents;
124 enableRaisingEvents = value;
125 if (enableRaisingEvents && !prev)
126 StartExitCallbackIfNeeded ();
131 [MethodImplAttribute(MethodImplOptions.InternalCall)]
132 private extern static int ExitCode_internal(IntPtr handle);
134 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
135 [MonitoringDescription ("The exit code of the process.")]
136 public int ExitCode {
138 if (process_handle == IntPtr.Zero)
139 throw new InvalidOperationException ("Process has not been started.");
141 int code = ExitCode_internal (process_handle);
143 throw new InvalidOperationException ("The process must exit before " +
144 "getting the requested information.");
150 /* Returns the process start time in Windows file
151 * times (ticks from DateTime(1/1/1601 00:00 GMT))
153 [MethodImplAttribute(MethodImplOptions.InternalCall)]
154 private extern static long ExitTime_internal(IntPtr handle);
156 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
157 [MonitoringDescription ("The exit time of the process.")]
158 public DateTime ExitTime {
160 if (process_handle == IntPtr.Zero)
161 throw new InvalidOperationException ("Process has not been started.");
164 throw new InvalidOperationException ("The process must exit before " +
165 "getting the requested information.");
167 return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
171 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
172 [MonitoringDescription ("Handle for this process.")]
173 public IntPtr Handle {
175 return(process_handle);
180 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
181 [MonitoringDescription ("Handles for this process.")]
182 public int HandleCount {
188 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
189 [MonitoringDescription ("Determines if the process is still running.")]
190 public bool HasExited {
192 if (process_handle == IntPtr.Zero)
193 throw new InvalidOperationException ("Process has not been started.");
195 int exitcode = ExitCode_internal (process_handle);
206 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
207 [MonitoringDescription ("Process identifier.")]
211 throw new InvalidOperationException ("Process ID has not been set.");
218 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
219 [MonitoringDescription ("The name of the computer running the process.")]
220 public string MachineName {
226 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
227 [MonitoringDescription ("The main module of the process.")]
228 public ProcessModule MainModule {
230 return(this.Modules[0]);
235 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
236 [MonitoringDescription ("The handle of the main window of the process.")]
237 public IntPtr MainWindowHandle {
244 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
245 [MonitoringDescription ("The title of the main window of the process.")]
246 public string MainWindowTitle {
252 [MethodImplAttribute(MethodImplOptions.InternalCall)]
253 private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
254 [MethodImplAttribute(MethodImplOptions.InternalCall)]
255 private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);
257 /* LAMESPEC: why is this an IntPtr not a plain int? */
258 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
259 [MonitoringDescription ("The maximum working set for this process.")]
260 public IntPtr MaxWorkingSet {
263 throw new InvalidOperationException(
264 "The process " + ProcessName +
265 " (ID " + Id + ") has exited");
269 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
271 throw new Win32Exception();
278 throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
281 bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
283 throw new Win32Exception();
288 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
289 [MonitoringDescription ("The minimum working set for this process.")]
290 public IntPtr MinWorkingSet {
293 throw new InvalidOperationException(
294 "The process " + ProcessName +
295 " (ID " + Id + ") has exited");
299 bool ok= GetWorkingSet_internal (process_handle, out min, out max);
301 throw new Win32Exception();
302 return ((IntPtr) min);
306 throw new InvalidOperationException(
307 "The process " + ProcessName +
308 " (ID " + Id + ") has exited");
310 bool ok = SetWorkingSet_internal (process_handle, value.ToInt32(), 0, true);
312 throw new Win32Exception();
316 /* Returns the list of process modules. The main module is
319 [MethodImplAttribute(MethodImplOptions.InternalCall)]
320 private extern ProcessModule[] GetModules_internal(IntPtr handle);
322 private ProcessModuleCollection module_collection;
324 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
325 [MonitoringDescription ("The modules that are loaded as part of this process.")]
326 public ProcessModuleCollection Modules {
328 if (module_collection == null)
329 module_collection = new ProcessModuleCollection(
330 GetModules_internal (process_handle));
331 return(module_collection);
335 /* data type is from the MonoProcessData enum in mono-proclib.h in the runtime */
336 [MethodImplAttribute(MethodImplOptions.InternalCall)]
337 private extern static long GetProcessData (int pid, int data_type, out int error);
340 [Obsolete ("Use NonpagedSystemMemorySize64")]
341 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
342 [MonitoringDescription ("The number of bytes that are not pageable.")]
343 public int NonpagedSystemMemorySize {
350 [Obsolete ("Use PagedMemorySize64")]
351 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
352 [MonitoringDescription ("The number of bytes that are paged.")]
353 public int PagedMemorySize {
360 [Obsolete ("Use PagedSystemMemorySize64")]
361 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
362 [MonitoringDescription ("The amount of paged system memory in bytes.")]
363 public int PagedSystemMemorySize {
370 [Obsolete ("Use PeakPagedMemorySize64")]
371 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
372 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
373 public int PeakPagedMemorySize {
379 [Obsolete ("Use PeakVirtualMemorySize64")]
380 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
381 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
382 public int PeakVirtualMemorySize {
385 return (int)GetProcessData (pid, 8, out error);
389 [Obsolete ("Use PeakWorkingSet64")]
390 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
391 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
392 public int PeakWorkingSet {
395 return (int)GetProcessData (pid, 5, out error);
400 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
401 [MonitoringDescription ("The number of bytes that are not pageable.")]
403 public long NonpagedSystemMemorySize64 {
410 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
411 [MonitoringDescription ("The number of bytes that are paged.")]
413 public long PagedMemorySize64 {
420 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
421 [MonitoringDescription ("The amount of paged system memory in bytes.")]
423 public long PagedSystemMemorySize64 {
430 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
431 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
433 public long PeakPagedMemorySize64 {
439 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
440 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
442 public long PeakVirtualMemorySize64 {
445 return GetProcessData (pid, 8, out error);
449 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
450 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
452 public long PeakWorkingSet64 {
455 return GetProcessData (pid, 5, out error);
460 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
461 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
462 public bool PriorityBoostEnabled {
470 [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
471 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
472 [MonitoringDescription ("The relative process priority.")]
473 public ProcessPriorityClass PriorityClass {
475 if (process_handle == IntPtr.Zero)
476 throw new InvalidOperationException ("Process has not been started.");
479 int prio = GetPriorityClass (process_handle, out error);
481 throw new Win32Exception (error);
482 return (ProcessPriorityClass) prio;
485 if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
486 throw new InvalidEnumArgumentException (
487 "value", (int) value,
488 typeof (ProcessPriorityClass));
490 if (process_handle == IntPtr.Zero)
491 throw new InvalidOperationException ("Process has not been started.");
494 if (!SetPriorityClass (process_handle, (int) value, out error)) {
496 throw new Win32Exception (error);
501 void CheckExited () {
503 throw new InvalidOperationException (String.Format ("Cannot process request because the process ({0}) has exited.", Id));
506 [MethodImplAttribute(MethodImplOptions.InternalCall)]
507 static extern int GetPriorityClass (IntPtr handle, out int error);
509 [MethodImplAttribute(MethodImplOptions.InternalCall)]
510 static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);
512 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
513 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
514 [Obsolete ("Use PrivateMemorySize64")]
515 public int PrivateMemorySize {
518 return (int)GetProcessData (pid, 6, out error);
522 [MonoNotSupported ("")]
523 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
524 [MonitoringDescription ("The session ID for this process.")]
525 public int SessionId {
526 get { throw new NotImplementedException (); }
529 /* the meaning of type is as follows: 0: user, 1: system, 2: total */
530 [MethodImplAttribute(MethodImplOptions.InternalCall)]
531 private extern static long Times (IntPtr handle, int type);
533 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
534 [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
535 public TimeSpan PrivilegedProcessorTime {
537 return new TimeSpan (Times (process_handle, 1));
541 [MethodImplAttribute(MethodImplOptions.InternalCall)]
542 private extern static string ProcessName_internal(IntPtr handle);
544 private string process_name=null;
546 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
547 [MonitoringDescription ("The name of this process.")]
548 public string ProcessName {
550 if(process_name==null) {
552 if (process_handle == IntPtr.Zero)
553 throw new InvalidOperationException ("No process is associated with this object.");
555 process_name=ProcessName_internal(process_handle);
556 /* If process_name is _still_
557 * null, assume the process
560 if (process_name == null)
561 throw new InvalidOperationException ("Process has exited, so the requested information is not available.");
563 /* Strip the suffix (if it
564 * exists) simplistically
565 * instead of removing any
566 * trailing \.???, so we dont
567 * get stupid results on sane
570 if(process_name.EndsWith(".exe") ||
571 process_name.EndsWith(".bat") ||
572 process_name.EndsWith(".com")) {
573 process_name=process_name.Substring(0, process_name.Length-4);
576 return(process_name);
581 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
582 [MonitoringDescription ("Allowed processor that can be used by this process.")]
583 public IntPtr ProcessorAffinity {
592 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
593 [MonitoringDescription ("Is this process responsive.")]
594 public bool Responding {
600 private StreamReader error_stream=null;
602 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
603 [MonitoringDescription ("The standard error stream of this process.")]
604 public StreamReader StandardError {
606 if (error_stream == null)
607 throw new InvalidOperationException("Standard error has not been redirected");
609 if ((async_mode & AsyncModes.AsyncError) != 0)
610 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
612 async_mode |= AsyncModes.SyncError;
614 return(error_stream);
618 private StreamWriter input_stream=null;
620 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
621 [MonitoringDescription ("The standard input stream of this process.")]
622 public StreamWriter StandardInput {
624 if (input_stream == null)
625 throw new InvalidOperationException("Standard input has not been redirected");
627 return(input_stream);
631 private StreamReader output_stream=null;
633 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
634 [MonitoringDescription ("The standard output stream of this process.")]
635 public StreamReader StandardOutput {
637 if (output_stream == null)
638 throw new InvalidOperationException("Standard output has not been redirected");
640 if ((async_mode & AsyncModes.AsyncOutput) != 0)
641 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
643 async_mode |= AsyncModes.SyncOutput;
645 return(output_stream);
649 private ProcessStartInfo start_info=null;
651 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
652 [MonitoringDescription ("Information for the start of this process.")]
653 public ProcessStartInfo StartInfo {
655 if (start_info == null)
656 start_info = new ProcessStartInfo();
661 throw new ArgumentNullException("value");
666 /* Returns the process start time in Windows file
667 * times (ticks from DateTime(1/1/1601 00:00 GMT))
669 [MethodImplAttribute(MethodImplOptions.InternalCall)]
670 private extern static long StartTime_internal(IntPtr handle);
672 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
673 [MonitoringDescription ("The time this process started.")]
674 public DateTime StartTime {
676 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
680 [DefaultValue (null), Browsable (false)]
681 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
682 public ISynchronizeInvoke SynchronizingObject {
683 get { return synchronizingObject; }
684 set { synchronizingObject = value; }
688 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
689 [MonitoringDescription ("The number of threads of this process.")]
690 public ProcessThreadCollection Threads {
692 return ProcessThreadCollection.GetEmpty ();
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,
924 ProcInfo proc_info=new ProcInfo();
927 if (startInfo.RedirectStandardInput ||
928 startInfo.RedirectStandardOutput ||
929 startInfo.RedirectStandardError) {
930 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
933 if (startInfo.HaveEnvVars)
934 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
936 FillUserInfo (startInfo, ref proc_info);
938 ret = ShellExecuteEx_internal (startInfo,
941 if (proc_info.Password != IntPtr.Zero)
942 Marshal.FreeBSTR (proc_info.Password);
943 proc_info.Password = IntPtr.Zero;
946 throw new Win32Exception (-proc_info.pid);
949 process.process_handle = proc_info.process_handle;
950 process.pid = proc_info.pid;
952 process.StartExitCallbackIfNeeded ();
957 private static bool Start_noshell (ProcessStartInfo startInfo,
960 ProcInfo proc_info=new ProcInfo();
961 IntPtr stdin_rd = IntPtr.Zero, stdin_wr = IntPtr.Zero;
967 if (startInfo.HaveEnvVars) {
968 string [] strs = new string [startInfo.EnvironmentVariables.Count];
969 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
970 proc_info.envKeys = strs;
972 strs = new string [startInfo.EnvironmentVariables.Count];
973 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
974 proc_info.envValues = strs;
977 if (startInfo.RedirectStandardInput == true) {
979 int DUPLICATE_SAME_ACCESS = 0x00000002;
982 ret = MonoIO.CreatePipe (out stdin_rd,
985 ret = MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, stdin_wr_tmp,
986 Process.GetCurrentProcess ().Handle, out stdin_wr, 0, 0, DUPLICATE_SAME_ACCESS);
987 MonoIO.Close (stdin_wr_tmp, out error);
992 ret = MonoIO.CreatePipe (out stdin_rd,
996 throw new IOException ("Error creating standard input pipe");
999 stdin_rd = MonoIO.ConsoleInput;
1000 /* This is required to stop the
1001 * &$*£ing stupid compiler moaning
1002 * that stdin_wr is unassigned, below.
1004 stdin_wr = (IntPtr)0;
1007 if (startInfo.RedirectStandardOutput == true) {
1008 IntPtr out_rd = IntPtr.Zero;
1011 int DUPLICATE_SAME_ACCESS = 0x00000002;
1013 ret = MonoIO.CreatePipe (out out_rd_tmp,
1016 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, out_rd_tmp,
1017 Process.GetCurrentProcess ().Handle, out out_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1018 MonoIO.Close (out_rd_tmp, out error);
1022 ret = MonoIO.CreatePipe (out out_rd,
1026 process.stdout_rd = out_rd;
1028 if (startInfo.RedirectStandardInput == true) {
1029 MonoIO.Close (stdin_rd, out error);
1030 MonoIO.Close (stdin_wr, out error);
1033 throw new IOException ("Error creating standard output pipe");
1036 process.stdout_rd = (IntPtr)0;
1037 stdout_wr = MonoIO.ConsoleOutput;
1040 if (startInfo.RedirectStandardError == true) {
1041 IntPtr err_rd = IntPtr.Zero;
1044 int DUPLICATE_SAME_ACCESS = 0x00000002;
1046 ret = MonoIO.CreatePipe (out err_rd_tmp,
1049 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, err_rd_tmp,
1050 Process.GetCurrentProcess ().Handle, out err_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1051 MonoIO.Close (err_rd_tmp, out error);
1055 ret = MonoIO.CreatePipe (out err_rd,
1059 process.stderr_rd = err_rd;
1061 if (startInfo.RedirectStandardInput == true) {
1062 MonoIO.Close (stdin_rd, out error);
1063 MonoIO.Close (stdin_wr, out error);
1065 if (startInfo.RedirectStandardOutput == true) {
1066 MonoIO.Close (process.stdout_rd, out error);
1067 MonoIO.Close (stdout_wr, out error);
1070 throw new IOException ("Error creating standard error pipe");
1073 process.stderr_rd = (IntPtr)0;
1074 stderr_wr = MonoIO.ConsoleError;
1077 FillUserInfo (startInfo, ref proc_info);
1079 ret = CreateProcess_internal (startInfo,
1080 stdin_rd, stdout_wr, stderr_wr,
1083 if (proc_info.Password != IntPtr.Zero)
1084 Marshal.FreeBSTR (proc_info.Password);
1085 proc_info.Password = IntPtr.Zero;
1088 if (startInfo.RedirectStandardInput == true) {
1089 MonoIO.Close (stdin_rd, out error);
1090 MonoIO.Close (stdin_wr, out error);
1093 if (startInfo.RedirectStandardOutput == true) {
1094 MonoIO.Close (process.stdout_rd, out error);
1095 MonoIO.Close (stdout_wr, out error);
1098 if (startInfo.RedirectStandardError == true) {
1099 MonoIO.Close (process.stderr_rd, out error);
1100 MonoIO.Close (stderr_wr, out error);
1103 throw new Win32Exception (-proc_info.pid,
1104 "ApplicationName='" + startInfo.FileName +
1105 "', CommandLine='" + startInfo.Arguments +
1106 "', CurrentDirectory='" + startInfo.WorkingDirectory +
1107 "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
1110 process.process_handle = proc_info.process_handle;
1111 process.pid = proc_info.pid;
1113 if (startInfo.RedirectStandardInput == true) {
1114 MonoIO.Close (stdin_rd, out error);
1115 process.input_stream = new StreamWriter (new MonoSyncFileStream (stdin_wr, FileAccess.Write, true, 8192), Console.Out.Encoding);
1116 process.input_stream.AutoFlush = true;
1119 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1120 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1122 if (startInfo.RedirectStandardOutput == true) {
1123 MonoIO.Close (stdout_wr, out error);
1124 process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding, true, 8192);
1127 if (startInfo.RedirectStandardError == true) {
1128 MonoIO.Close (stderr_wr, out error);
1129 process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding, true, 8192);
1132 process.StartExitCallbackIfNeeded ();
1137 // Note that ProcInfo.Password must be freed.
1138 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1140 if (startInfo.UserName != null) {
1141 proc_info.UserName = startInfo.UserName;
1142 proc_info.Domain = startInfo.Domain;
1143 if (startInfo.Password != null)
1144 proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1146 proc_info.Password = IntPtr.Zero;
1147 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1151 private static bool Start_common (ProcessStartInfo startInfo,
1154 if (startInfo.FileName == null || startInfo.FileName.Length == 0)
1155 throw new InvalidOperationException("File name has not been set");
1157 if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1158 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1159 if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1160 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1162 if (startInfo.UseShellExecute) {
1163 if (!String.IsNullOrEmpty (startInfo.UserName))
1164 throw new InvalidOperationException ("UserShellExecute must be false if an explicit UserName is specified when starting a process");
1165 return (Start_shell (startInfo, process));
1167 return (Start_noshell (startInfo, process));
1171 public bool Start ()
1173 if (process_handle != IntPtr.Zero) {
1174 Process_free_internal (process_handle);
1175 process_handle = IntPtr.Zero;
1177 return Start_common(start_info, this);
1180 public static Process Start (ProcessStartInfo startInfo)
1182 if (startInfo == null)
1183 throw new ArgumentNullException ("startInfo");
1185 Process process=new Process();
1186 process.StartInfo = startInfo;
1187 if (Start_common(startInfo, process))
1192 public static Process Start (string fileName)
1194 return Start (new ProcessStartInfo (fileName));
1197 public static Process Start(string fileName, string arguments)
1199 return Start (new ProcessStartInfo (fileName, arguments));
1202 public static Process Start(string fileName, string username, SecureString password, string domain) {
1203 return Start(fileName, null, username, password, domain);
1206 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1207 ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1208 psi.UserName = username;
1209 psi.Password = password;
1210 psi.Domain = domain;
1211 psi.UseShellExecute = false;
1215 public override string ToString()
1217 return(base.ToString() + " (" + this.ProcessName + ")");
1220 /* Waits up to ms milliseconds for process 'handle' to
1221 * exit. ms can be <0 to mean wait forever.
1223 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1224 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1226 public void WaitForExit ()
1231 public bool WaitForExit(int milliseconds) {
1232 int ms = milliseconds;
1233 if (ms == int.MaxValue)
1236 DateTime start = DateTime.UtcNow;
1237 if (async_output != null && !async_output.IsCompleted) {
1238 if (false == async_output.WaitHandle.WaitOne (ms, false))
1239 return false; // Timed out
1242 DateTime now = DateTime.UtcNow;
1243 ms -= (int) (now - start).TotalMilliseconds;
1250 if (async_error != null && !async_error.IsCompleted) {
1251 if (false == async_error.WaitHandle.WaitOne (ms, false))
1252 return false; // Timed out
1255 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1260 return WaitForExit_internal (process_handle, ms);
1263 /* Waits up to ms milliseconds for process 'handle' to
1264 * wait for input. ms can be <0 to mean wait forever.
1266 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1267 private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
1269 // The internal call is only implemented properly on Windows.
1271 public bool WaitForInputIdle() {
1272 return WaitForInputIdle (-1);
1275 // The internal call is only implemented properly on Windows.
1277 public bool WaitForInputIdle(int milliseconds) {
1278 return WaitForInputIdle_internal (process_handle, milliseconds);
1281 private static bool IsLocalMachine (string machineName)
1283 if (machineName == "." || machineName.Length == 0)
1286 return (string.Compare (machineName, Environment.MachineName, true) == 0);
1290 [MonitoringDescription ("Raised when it receives output data")]
1291 public event DataReceivedEventHandler OutputDataReceived;
1293 [MonitoringDescription ("Raised when it receives error data")]
1294 public event DataReceivedEventHandler ErrorDataReceived;
1296 void OnOutputDataReceived (string str)
1298 if (OutputDataReceived != null)
1299 OutputDataReceived (this, new DataReceivedEventArgs (str));
1302 void OnErrorDataReceived (string str)
1304 if (ErrorDataReceived != null)
1305 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1313 AsyncOutput = 1 << 2,
1317 [StructLayout (LayoutKind.Sequential)]
1318 sealed class ProcessAsyncReader
1321 The following fields match those of SocketAsyncResult.
1322 This is so that changes needed in the runtime to handle
1323 asynchronous reads are trivial
1324 Keep this in sync with SocketAsyncResult in
1325 ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
1326 in metadata/socket-io.h.
1328 /* DON'T shuffle fields around. DON'T remove fields */
1330 public IntPtr handle;
1331 public object state;
1332 public AsyncCallback callback;
1333 public ManualResetEvent wait_handle;
1335 public Exception delayedException;
1337 public object EndPoint;
1338 byte [] buffer = new byte [4196];
1341 public int SockFlags;
1343 public object AcceptSocket;
1344 public object[] Addresses;
1346 public object Buffers; // Reserve this slot in older profiles
1347 public bool ReuseSocket; // Disconnect
1348 public object acc_socket;
1350 public bool completed_sync;
1352 bool err_out; // true -> stdout, false -> stderr
1354 public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1356 public int EndCalled;
1358 // These fields are not in SocketAsyncResult
1361 StringBuilder sb = new StringBuilder ();
1362 public AsyncReadHandler ReadHandler;
1364 public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1366 this.process = process;
1367 this.handle = handle;
1368 stream = new FileStream (handle, FileAccess.Read, false);
1369 this.ReadHandler = new AsyncReadHandler (AddInput);
1370 this.err_out = err_out;
1373 public void AddInput ()
1376 int nread = stream.Read (buffer, 0, buffer.Length);
1379 if (wait_handle != null)
1386 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1388 // Just in case the encoding fails...
1389 for (int i = 0; i < nread; i++) {
1390 sb.Append ((char) buffer [i]);
1395 ReadHandler.BeginInvoke (null, this);
1403 process.OnOutputDataReceived (null);
1405 process.OnErrorDataReceived (null);
1409 void Flush (bool last)
1411 if (sb.Length == 0 ||
1412 (err_out && process.output_canceled) ||
1413 (!err_out && process.error_canceled))
1416 string total = sb.ToString ();
1418 string [] strs = total.Split ('\n');
1419 int len = strs.Length;
1423 for (int i = 0; i < len - 1; i++) {
1425 process.OnOutputDataReceived (strs [i]);
1427 process.OnErrorDataReceived (strs [i]);
1430 string end = strs [len - 1];
1431 if (last || (len == 1 && end == "")) {
1433 process.OnOutputDataReceived (end);
1435 process.OnErrorDataReceived (end);
1442 public bool IsCompleted {
1443 get { return completed; }
1446 public WaitHandle WaitHandle {
1449 if (wait_handle == null)
1450 wait_handle = new ManualResetEvent (completed);
1456 public void Close () {
1461 AsyncModes async_mode;
1462 bool output_canceled;
1463 bool error_canceled;
1464 ProcessAsyncReader async_output;
1465 ProcessAsyncReader async_error;
1466 delegate void AsyncReadHandler ();
1468 [ComVisibleAttribute(false)]
1469 public void BeginOutputReadLine ()
1471 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1472 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1474 if ((async_mode & AsyncModes.SyncOutput) != 0)
1475 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1477 async_mode |= AsyncModes.AsyncOutput;
1478 output_canceled = false;
1479 if (async_output == null) {
1480 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1481 async_output.ReadHandler.BeginInvoke (null, async_output);
1485 [ComVisibleAttribute(false)]
1486 public void CancelOutputRead ()
1488 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1489 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1491 if ((async_mode & AsyncModes.SyncOutput) != 0)
1492 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1494 if (async_output == null)
1495 throw new InvalidOperationException ("No async operation in progress.");
1497 output_canceled = true;
1500 [ComVisibleAttribute(false)]
1501 public void BeginErrorReadLine ()
1503 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1504 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1506 if ((async_mode & AsyncModes.SyncError) != 0)
1507 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1509 async_mode |= AsyncModes.AsyncError;
1510 error_canceled = false;
1511 if (async_error == null) {
1512 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1513 async_error.ReadHandler.BeginInvoke (null, async_error);
1517 [ComVisibleAttribute(false)]
1518 public void CancelErrorRead ()
1520 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1521 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1523 if ((async_mode & AsyncModes.SyncOutput) != 0)
1524 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1526 if (async_error == null)
1527 throw new InvalidOperationException ("No async operation in progress.");
1529 error_canceled = true;
1532 [Category ("Behavior")]
1533 [MonitoringDescription ("Raised when this process exits.")]
1534 public event EventHandler Exited {
1536 if (process_handle != IntPtr.Zero && HasExited) {
1537 value.BeginInvoke (null, null, null, null);
1539 exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1540 if (exited_event != null)
1541 StartExitCallbackIfNeeded ();
1545 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1549 // Closes the system process handle
1550 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1551 private extern void Process_free_internal(IntPtr handle);
1553 private bool disposed = false;
1555 protected override void Dispose(bool disposing) {
1556 // Check to see if Dispose has already been called.
1557 if(this.disposed == false) {
1559 // If this is a call to Dispose,
1560 // dispose all managed resources.
1564 /* These have open FileStreams on the pipes we are about to close */
1565 if (async_output != null)
1566 async_output.Close ();
1567 if (async_error != null)
1568 async_error.Close ();
1572 // Release unmanaged resources
1575 if(process_handle!=IntPtr.Zero) {
1576 Process_free_internal(process_handle);
1577 process_handle=IntPtr.Zero;
1580 if (input_stream != null) {
1581 input_stream.Close();
1582 input_stream = null;
1585 if (output_stream != null) {
1586 output_stream.Close();
1587 output_stream = null;
1590 if (error_stream != null) {
1591 error_stream.Close();
1592 error_stream = null;
1596 base.Dispose (disposing);
1604 static void CBOnExit (object state, bool unused)
1606 Process p = (Process) state;
1607 p.already_waiting = false;
1611 protected void OnExited()
1613 if (exited_event == null)
1616 if (synchronizingObject == null) {
1617 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1619 d (this, EventArgs.Empty);
1625 object [] args = new object [] {this, EventArgs.Empty};
1626 synchronizingObject.BeginInvoke (exited_event, args);
1629 static bool IsWindows
1633 PlatformID platform = Environment.OSVersion.Platform;
1634 if (platform == PlatformID.Win32S ||
1635 platform == PlatformID.Win32Windows ||
1636 platform == PlatformID.Win32NT ||
1637 platform == PlatformID.WinCE) {
1644 class ProcessWaitHandle : WaitHandle
1646 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1647 private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1649 public ProcessWaitHandle (IntPtr handle)
1651 // Need to keep a reference to this handle,
1652 // in case the Process object is collected
1653 Handle = ProcessHandle_duplicate (handle);
1655 // When the wait handle is disposed, the duplicated handle will be
1656 // closed, so no need to override dispose (bug #464628).