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))
511 throw new Win32Exception (error);
515 [MethodImplAttribute(MethodImplOptions.InternalCall)]
516 static extern int GetPriorityClass (IntPtr handle, out int error);
518 [MethodImplAttribute(MethodImplOptions.InternalCall)]
519 static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);
521 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
522 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
524 [Obsolete ("Use PrivateMemorySize64")]
526 public int PrivateMemorySize {
529 return (int)GetProcessData (pid, 6, out error);
534 [MonoNotSupported ("")]
535 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
536 [MonitoringDescription ("The session ID for this process.")]
537 public int SessionId {
538 get { throw new NotImplementedException (); }
542 /* the meaning of type is as follows: 0: user, 1: system, 2: total */
543 [MethodImplAttribute(MethodImplOptions.InternalCall)]
544 private extern static long Times (IntPtr handle, int type);
546 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
547 [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
548 public TimeSpan PrivilegedProcessorTime {
550 return new TimeSpan (Times (process_handle, 1));
554 [MethodImplAttribute(MethodImplOptions.InternalCall)]
555 private extern static string ProcessName_internal(IntPtr handle);
557 private string process_name=null;
559 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
560 [MonitoringDescription ("The name of this process.")]
561 public string ProcessName {
563 if(process_name==null) {
564 process_name=ProcessName_internal(process_handle);
565 /* If process_name is _still_
566 * null, assume the process
569 if (process_name == null)
570 throw new SystemException("The process has exited");
572 /* Strip the suffix (if it
573 * exists) simplistically
574 * instead of removing any
575 * trailing \.???, so we dont
576 * get stupid results on sane
579 if(process_name.EndsWith(".exe") ||
580 process_name.EndsWith(".bat") ||
581 process_name.EndsWith(".com")) {
582 process_name=process_name.Substring(0, process_name.Length-4);
585 return(process_name);
590 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
591 [MonitoringDescription ("Allowed processor that can be used by this process.")]
592 public IntPtr ProcessorAffinity {
601 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
602 [MonitoringDescription ("Is this process responsive.")]
603 public bool Responding {
609 private StreamReader error_stream=null;
611 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
612 [MonitoringDescription ("The standard error stream of this process.")]
613 public StreamReader StandardError {
615 if (error_stream == null)
616 throw new InvalidOperationException("Standard error has not been redirected");
619 if ((async_mode & AsyncModes.AsyncError) != 0)
620 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
622 async_mode |= AsyncModes.SyncError;
625 return(error_stream);
629 private StreamWriter input_stream=null;
631 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
632 [MonitoringDescription ("The standard input stream of this process.")]
633 public StreamWriter StandardInput {
635 if (input_stream == null)
636 throw new InvalidOperationException("Standard input has not been redirected");
638 return(input_stream);
642 private StreamReader output_stream=null;
644 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
645 [MonitoringDescription ("The standard output stream of this process.")]
646 public StreamReader StandardOutput {
648 if (output_stream == null)
649 throw new InvalidOperationException("Standard output has not been redirected");
652 if ((async_mode & AsyncModes.AsyncOutput) != 0)
653 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
655 async_mode |= AsyncModes.SyncOutput;
658 return(output_stream);
662 private ProcessStartInfo start_info=null;
664 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
665 [MonitoringDescription ("Information for the start of this process.")]
666 public ProcessStartInfo StartInfo {
668 if (start_info == null)
669 start_info = new ProcessStartInfo();
674 throw new ArgumentNullException("value");
679 /* Returns the process start time in Windows file
680 * times (ticks from DateTime(1/1/1601 00:00 GMT))
682 [MethodImplAttribute(MethodImplOptions.InternalCall)]
683 private extern static long StartTime_internal(IntPtr handle);
685 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
686 [MonitoringDescription ("The time this process started.")]
687 public DateTime StartTime {
689 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
693 [DefaultValue (null), Browsable (false)]
694 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
695 public ISynchronizeInvoke SynchronizingObject {
696 get { return synchronizingObject; }
697 set { synchronizingObject = value; }
701 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
702 [MonitoringDescription ("The number of threads of this process.")]
703 public ProcessThreadCollection Threads {
705 return ProcessThreadCollection.GetEmpty ();
709 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
710 [MonitoringDescription ("The total CPU time spent for this process.")]
711 public TimeSpan TotalProcessorTime {
713 return new TimeSpan (Times (process_handle, 2));
717 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
718 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
719 public TimeSpan UserProcessorTime {
721 return new TimeSpan (Times (process_handle, 0));
726 [Obsolete ("Use VirtualMemorySize64")]
728 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
729 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
730 public int VirtualMemorySize {
733 return (int)GetProcessData (pid, 7, out error);
738 [Obsolete ("Use WorkingSet64")]
740 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
741 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
742 public int WorkingSet {
745 return (int)GetProcessData (pid, 4, out error);
750 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
751 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
753 public long PrivateMemorySize64 {
756 return GetProcessData (pid, 6, out error);
760 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
761 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
763 public long VirtualMemorySize64 {
766 return GetProcessData (pid, 7, out error);
770 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
771 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
773 public long WorkingSet64 {
776 return GetProcessData (pid, 4, out error);
786 [MethodImplAttribute(MethodImplOptions.InternalCall)]
787 extern static bool Kill_internal (IntPtr handle, int signo);
789 /* int kill -> 1 KILL, 2 CloseMainWindow */
790 bool Close (int signo)
792 if (process_handle == IntPtr.Zero)
793 throw new SystemException ("No process to kill.");
795 int exitcode = ExitCode_internal (process_handle);
797 throw new InvalidOperationException ("The process already finished.");
799 return Kill_internal (process_handle, signo);
802 public bool CloseMainWindow ()
808 public static void EnterDebugMode() {
811 [MethodImplAttribute(MethodImplOptions.InternalCall)]
812 private extern static IntPtr GetProcess_internal(int pid);
814 [MethodImplAttribute(MethodImplOptions.InternalCall)]
815 private extern static int GetPid_internal();
817 public static Process GetCurrentProcess()
819 int pid = GetPid_internal();
820 IntPtr proc = GetProcess_internal(pid);
822 if (proc == IntPtr.Zero)
823 throw new SystemException("Can't find current process");
825 return (new Process (proc, pid));
828 public static Process GetProcessById(int processId)
830 IntPtr proc = GetProcess_internal(processId);
832 if (proc == IntPtr.Zero)
833 throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
835 return (new Process (proc, processId));
838 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
839 public static Process GetProcessById(int processId, string machineName) {
840 if (machineName == null)
841 throw new ArgumentNullException ("machineName");
843 if (!IsLocalMachine (machineName))
844 throw new NotImplementedException ();
846 return GetProcessById (processId);
849 [MethodImplAttribute(MethodImplOptions.InternalCall)]
850 private extern static int[] GetProcesses_internal();
852 public static Process[] GetProcesses()
854 int [] pids = GetProcesses_internal ();
855 ArrayList proclist = new ArrayList ();
857 for (int i = 0; i < pids.Length; i++) {
859 proclist.Add (GetProcessById (pids [i]));
860 } catch (SystemException) {
861 /* The process might exit
863 * GetProcesses_internal and
869 return ((Process []) proclist.ToArray (typeof (Process)));
872 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
873 public static Process[] GetProcesses(string machineName) {
874 if (machineName == null)
875 throw new ArgumentNullException ("machineName");
877 if (!IsLocalMachine (machineName))
878 throw new NotImplementedException ();
880 return GetProcesses ();
883 public static Process[] GetProcessesByName(string processName)
885 Process [] procs = GetProcesses();
886 ArrayList proclist = new ArrayList();
888 for (int i = 0; i < procs.Length; i++) {
890 if (String.Compare (processName,
891 procs [i].ProcessName,
893 proclist.Add (procs [i]);
897 return ((Process[]) proclist.ToArray (typeof(Process)));
901 public static Process[] GetProcessesByName(string processName, string machineName) {
902 throw new NotImplementedException();
911 public static void LeaveDebugMode() {
914 public void Refresh ()
916 // FIXME: should refresh any cached data we might have about
917 // the process (currently we have none).
920 [MethodImplAttribute(MethodImplOptions.InternalCall)]
921 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
922 ref ProcInfo proc_info);
924 [MethodImplAttribute(MethodImplOptions.InternalCall)]
925 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
929 ref ProcInfo proc_info);
931 private static bool Start_shell (ProcessStartInfo startInfo,
934 ProcInfo proc_info=new ProcInfo();
937 if (startInfo.RedirectStandardInput ||
938 startInfo.RedirectStandardOutput ||
939 startInfo.RedirectStandardError) {
940 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
943 if (startInfo.HaveEnvVars)
944 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
946 FillUserInfo (startInfo, ref proc_info);
948 ret = ShellExecuteEx_internal (startInfo,
951 if (proc_info.Password != IntPtr.Zero)
952 Marshal.FreeBSTR (proc_info.Password);
953 proc_info.Password = IntPtr.Zero;
956 throw new Win32Exception (-proc_info.pid);
959 process.process_handle = proc_info.process_handle;
960 process.pid = proc_info.pid;
962 process.StartExitCallbackIfNeeded ();
967 private static bool Start_noshell (ProcessStartInfo startInfo,
970 ProcInfo proc_info=new ProcInfo();
971 IntPtr stdin_rd = IntPtr.Zero, stdin_wr = IntPtr.Zero;
977 if (startInfo.HaveEnvVars) {
978 string [] strs = new string [startInfo.EnvironmentVariables.Count];
979 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
980 proc_info.envKeys = strs;
982 strs = new string [startInfo.EnvironmentVariables.Count];
983 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
984 proc_info.envValues = strs;
987 if (startInfo.RedirectStandardInput == true) {
989 int DUPLICATE_SAME_ACCESS = 0x00000002;
992 ret = MonoIO.CreatePipe (out stdin_rd,
995 ret = MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, stdin_wr_tmp,
996 Process.GetCurrentProcess ().Handle, out stdin_wr, 0, 0, DUPLICATE_SAME_ACCESS);
997 MonoIO.Close (stdin_wr_tmp, out error);
1002 ret = MonoIO.CreatePipe (out stdin_rd,
1006 throw new IOException ("Error creating standard input pipe");
1009 stdin_rd = MonoIO.ConsoleInput;
1010 /* This is required to stop the
1011 * &$*£ing stupid compiler moaning
1012 * that stdin_wr is unassigned, below.
1014 stdin_wr = (IntPtr)0;
1017 if (startInfo.RedirectStandardOutput == true) {
1018 IntPtr out_rd = IntPtr.Zero;
1021 int DUPLICATE_SAME_ACCESS = 0x00000002;
1023 ret = MonoIO.CreatePipe (out out_rd_tmp,
1026 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, out_rd_tmp,
1027 Process.GetCurrentProcess ().Handle, out out_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1028 MonoIO.Close (out_rd_tmp, out error);
1032 ret = MonoIO.CreatePipe (out out_rd,
1036 process.stdout_rd = out_rd;
1038 if (startInfo.RedirectStandardInput == true) {
1039 MonoIO.Close (stdin_rd, out error);
1040 MonoIO.Close (stdin_wr, out error);
1043 throw new IOException ("Error creating standard output pipe");
1046 process.stdout_rd = (IntPtr)0;
1047 stdout_wr = MonoIO.ConsoleOutput;
1050 if (startInfo.RedirectStandardError == true) {
1051 IntPtr err_rd = IntPtr.Zero;
1054 int DUPLICATE_SAME_ACCESS = 0x00000002;
1056 ret = MonoIO.CreatePipe (out err_rd_tmp,
1059 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, err_rd_tmp,
1060 Process.GetCurrentProcess ().Handle, out err_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1061 MonoIO.Close (err_rd_tmp, out error);
1065 ret = MonoIO.CreatePipe (out err_rd,
1069 process.stderr_rd = err_rd;
1071 if (startInfo.RedirectStandardInput == true) {
1072 MonoIO.Close (stdin_rd, out error);
1073 MonoIO.Close (stdin_wr, out error);
1075 if (startInfo.RedirectStandardOutput == true) {
1076 MonoIO.Close (process.stdout_rd, out error);
1077 MonoIO.Close (stdout_wr, out error);
1080 throw new IOException ("Error creating standard error pipe");
1083 process.stderr_rd = (IntPtr)0;
1084 stderr_wr = MonoIO.ConsoleError;
1087 FillUserInfo (startInfo, ref proc_info);
1089 ret = CreateProcess_internal (startInfo,
1090 stdin_rd, stdout_wr, stderr_wr,
1093 if (proc_info.Password != IntPtr.Zero)
1094 Marshal.FreeBSTR (proc_info.Password);
1095 proc_info.Password = IntPtr.Zero;
1098 if (startInfo.RedirectStandardInput == true) {
1099 MonoIO.Close (stdin_rd, out error);
1100 MonoIO.Close (stdin_wr, out error);
1103 if (startInfo.RedirectStandardOutput == true) {
1104 MonoIO.Close (process.stdout_rd, out error);
1105 MonoIO.Close (stdout_wr, out error);
1108 if (startInfo.RedirectStandardError == true) {
1109 MonoIO.Close (process.stderr_rd, out error);
1110 MonoIO.Close (stderr_wr, out error);
1113 throw new Win32Exception (-proc_info.pid,
1114 "ApplicationName='" + startInfo.FileName +
1115 "', CommandLine='" + startInfo.Arguments +
1116 "', CurrentDirectory='" + startInfo.WorkingDirectory + "'");
1119 process.process_handle = proc_info.process_handle;
1120 process.pid = proc_info.pid;
1122 if (startInfo.RedirectStandardInput == true) {
1123 MonoIO.Close (stdin_rd, out error);
1124 process.input_stream = new StreamWriter (new MonoSyncFileStream (stdin_wr, FileAccess.Write, true, 8192), Console.Out.Encoding);
1125 process.input_stream.AutoFlush = true;
1129 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1130 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1132 Encoding stdoutEncoding = Console.Out.Encoding;
1133 Encoding stderrEncoding = stdoutEncoding;
1136 if (startInfo.RedirectStandardOutput == true) {
1137 MonoIO.Close (stdout_wr, out error);
1138 process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding, true, 8192);
1141 if (startInfo.RedirectStandardError == true) {
1142 MonoIO.Close (stderr_wr, out error);
1143 process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding, true, 8192);
1146 process.StartExitCallbackIfNeeded ();
1151 // Note that ProcInfo.Password must be freed.
1152 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1155 if (startInfo.UserName != null) {
1156 proc_info.UserName = startInfo.UserName;
1157 proc_info.Domain = startInfo.Domain;
1158 if (startInfo.Password != null)
1159 proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1161 proc_info.Password = IntPtr.Zero;
1162 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1167 private static bool Start_common (ProcessStartInfo startInfo,
1170 if (startInfo.FileName == null || startInfo.FileName.Length == 0)
1171 throw new InvalidOperationException("File name has not been set");
1174 if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1175 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1176 if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1177 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1180 if (startInfo.UseShellExecute) {
1182 if (!String.IsNullOrEmpty (startInfo.UserName))
1183 throw new InvalidOperationException ("UserShellExecute must be false if an explicit UserName is specified when starting a process");
1185 return (Start_shell (startInfo, process));
1187 return (Start_noshell (startInfo, process));
1191 public bool Start ()
1193 if (process_handle != IntPtr.Zero) {
1194 Process_free_internal (process_handle);
1195 process_handle = IntPtr.Zero;
1197 return Start_common(start_info, this);
1200 public static Process Start (ProcessStartInfo startInfo)
1202 if (startInfo == null)
1203 throw new ArgumentNullException ("startInfo");
1205 Process process=new Process();
1206 process.StartInfo = startInfo;
1207 if (Start_common(startInfo, process))
1212 public static Process Start (string fileName)
1214 return Start (new ProcessStartInfo (fileName));
1217 public static Process Start(string fileName, string arguments)
1219 return Start (new ProcessStartInfo (fileName, arguments));
1223 public static Process Start(string fileName, string username, SecureString password, string domain) {
1224 return Start(fileName, null, username, password, domain);
1227 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1228 ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1229 psi.UserName = username;
1230 psi.Password = password;
1231 psi.Domain = domain;
1232 psi.UseShellExecute = false;
1237 public override string ToString()
1239 return(base.ToString() + " (" + this.ProcessName + ")");
1242 /* Waits up to ms milliseconds for process 'handle' to
1243 * exit. ms can be <0 to mean wait forever.
1245 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1246 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1248 public void WaitForExit ()
1253 public bool WaitForExit(int milliseconds) {
1254 int ms = milliseconds;
1255 if (ms == int.MaxValue)
1259 DateTime start = DateTime.UtcNow;
1260 if (async_output != null && !async_output.IsCompleted) {
1261 if (false == async_output.WaitHandle.WaitOne (ms, false))
1262 return false; // Timed out
1265 DateTime now = DateTime.UtcNow;
1266 ms -= (int) (now - start).TotalMilliseconds;
1273 if (async_error != null && !async_error.IsCompleted) {
1274 if (false == async_error.WaitHandle.WaitOne (ms, false))
1275 return false; // Timed out
1278 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1284 return WaitForExit_internal (process_handle, ms);
1287 /* Waits up to ms milliseconds for process 'handle' to
1288 * wait for input. ms can be <0 to mean wait forever.
1290 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1291 private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
1293 // The internal call is only implemented properly on Windows.
1295 public bool WaitForInputIdle() {
1296 return WaitForInputIdle (-1);
1299 // The internal call is only implemented properly on Windows.
1301 public bool WaitForInputIdle(int milliseconds) {
1302 return WaitForInputIdle_internal (process_handle, milliseconds);
1305 private static bool IsLocalMachine (string machineName)
1307 if (machineName == "." || machineName.Length == 0)
1310 return (string.Compare (machineName, Environment.MachineName, true) == 0);
1315 [MonitoringDescription ("Raised when it receives output data")]
1316 public event DataReceivedEventHandler OutputDataReceived;
1318 [MonitoringDescription ("Raised when it receives error data")]
1319 public event DataReceivedEventHandler ErrorDataReceived;
1321 void OnOutputDataReceived (string str)
1323 if (OutputDataReceived != null)
1324 OutputDataReceived (this, new DataReceivedEventArgs (str));
1327 void OnErrorDataReceived (string str)
1329 if (ErrorDataReceived != null)
1330 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1338 AsyncOutput = 1 << 2,
1342 [StructLayout (LayoutKind.Sequential)]
1343 sealed class ProcessAsyncReader
1346 The following fields match those of SocketAsyncResult.
1347 This is so that changes needed in the runtime to handle
1348 asynchronous reads are trivial
1349 Keep this in sync with SocketAsyncResult in
1350 ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
1351 in metadata/socket-io.h.
1353 /* DON'T shuffle fields around. DON'T remove fields */
1355 public IntPtr handle;
1356 public object state;
1357 public AsyncCallback callback;
1358 public ManualResetEvent wait_handle;
1360 public Exception delayedException;
1362 public object EndPoint;
1363 byte [] buffer = new byte [4196];
1366 public int SockFlags;
1368 public object AcceptSocket;
1369 public object[] Addresses;
1371 public object Buffers; // Reserve this slot in older profiles
1372 public bool ReuseSocket; // Disconnect
1373 public object acc_socket;
1375 public bool completed_sync;
1377 bool err_out; // true -> stdout, false -> stderr
1379 public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1383 // These fields are not in SocketAsyncResult
1386 StringBuilder sb = new StringBuilder ();
1387 public AsyncReadHandler ReadHandler;
1389 public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1391 this.process = process;
1392 this.handle = handle;
1393 stream = new FileStream (handle, FileAccess.Read, false);
1394 this.ReadHandler = new AsyncReadHandler (AddInput);
1395 this.err_out = err_out;
1398 public void AddInput ()
1401 int nread = stream.Read (buffer, 0, buffer.Length);
1404 if (wait_handle != null)
1411 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1413 // Just in case the encoding fails...
1414 for (int i = 0; i < nread; i++) {
1415 sb.Append ((char) buffer [i]);
1420 ReadHandler.BeginInvoke (null, this);
1424 void Flush (bool last)
1426 if (sb.Length == 0 ||
1427 (err_out && process.output_canceled) ||
1428 (!err_out && process.error_canceled))
1431 string total = sb.ToString ();
1433 string [] strs = total.Split ('\n');
1434 int len = strs.Length;
1438 for (int i = 0; i < len - 1; i++) {
1440 process.OnOutputDataReceived (strs [i]);
1442 process.OnErrorDataReceived (strs [i]);
1445 string end = strs [len - 1];
1446 if (last || (len == 1 && end == "")) {
1448 process.OnOutputDataReceived (end);
1450 process.OnErrorDataReceived (end);
1457 public bool IsCompleted {
1458 get { return completed; }
1461 public WaitHandle WaitHandle {
1464 if (wait_handle == null)
1465 wait_handle = new ManualResetEvent (completed);
1472 AsyncModes async_mode;
1473 bool output_canceled;
1474 bool error_canceled;
1475 ProcessAsyncReader async_output;
1476 ProcessAsyncReader async_error;
1477 delegate void AsyncReadHandler ();
1479 [ComVisibleAttribute(false)]
1480 public void BeginOutputReadLine ()
1482 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1483 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1485 if ((async_mode & AsyncModes.SyncOutput) != 0)
1486 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1488 async_mode |= AsyncModes.AsyncOutput;
1489 output_canceled = false;
1490 if (async_output == null) {
1491 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1492 async_output.ReadHandler.BeginInvoke (null, async_output);
1496 [ComVisibleAttribute(false)]
1497 public void CancelOutputRead ()
1499 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1500 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1502 if ((async_mode & AsyncModes.SyncOutput) != 0)
1503 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1505 if (async_output == null)
1506 throw new InvalidOperationException ("No async operation in progress.");
1508 output_canceled = true;
1511 [ComVisibleAttribute(false)]
1512 public void BeginErrorReadLine ()
1514 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1515 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1517 if ((async_mode & AsyncModes.SyncError) != 0)
1518 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1520 async_mode |= AsyncModes.AsyncError;
1521 error_canceled = false;
1522 if (async_error == null) {
1523 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1524 async_error.ReadHandler.BeginInvoke (null, async_error);
1528 [ComVisibleAttribute(false)]
1529 public void CancelErrorRead ()
1531 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1532 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1534 if ((async_mode & AsyncModes.SyncOutput) != 0)
1535 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1537 if (async_error == null)
1538 throw new InvalidOperationException ("No async operation in progress.");
1540 error_canceled = true;
1544 [Category ("Behavior")]
1545 [MonitoringDescription ("Raised when this process exits.")]
1546 public event EventHandler Exited {
1548 if (process_handle != IntPtr.Zero && HasExited) {
1549 value.BeginInvoke (null, null, null, null);
1551 exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1552 if (exited_event != null)
1553 StartExitCallbackIfNeeded ();
1557 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1561 // Closes the system process handle
1562 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1563 private extern void Process_free_internal(IntPtr handle);
1565 private bool disposed = false;
1567 protected override void Dispose(bool disposing) {
1568 // Check to see if Dispose has already been called.
1569 if(this.disposed == false) {
1571 // If this is a call to Dispose,
1572 // dispose all managed resources.
1577 // Release unmanaged resources
1580 if(process_handle!=IntPtr.Zero) {
1581 Process_free_internal(process_handle);
1582 process_handle=IntPtr.Zero;
1585 if (input_stream != null) {
1586 input_stream.Close();
1587 input_stream = null;
1590 if (output_stream != null) {
1591 output_stream.Close();
1592 output_stream = null;
1595 if (error_stream != null) {
1596 error_stream.Close();
1597 error_stream = null;
1601 base.Dispose (disposing);
1609 static void CBOnExit (object state, bool unused)
1611 Process p = (Process) state;
1615 protected void OnExited()
1617 if (exited_event == null)
1620 if (synchronizingObject == null) {
1621 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1623 d (this, EventArgs.Empty);
1629 object [] args = new object [] {this, EventArgs.Empty};
1630 synchronizingObject.BeginInvoke (exited_event, args);
1633 static bool IsWindows
1637 PlatformID platform = Environment.OSVersion.Platform;
1638 if (platform == PlatformID.Win32S ||
1639 platform == PlatformID.Win32Windows ||
1640 platform == PlatformID.Win32NT ||
1641 platform == PlatformID.WinCE) {
1648 class ProcessWaitHandle : WaitHandle
1650 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1651 private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1653 public ProcessWaitHandle (IntPtr handle)
1655 // Need to keep a reference to this handle,
1656 // in case the Process object is collected
1657 Handle = ProcessHandle_duplicate (handle);
1660 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1661 private extern static void ProcessHandle_close (IntPtr handle);
1663 private bool disposed = false;
1665 protected override void Dispose (bool explicitDisposing)
1667 if (this.disposed == false) {
1668 this.disposed = true;
1670 ProcessHandle_close (Handle);
1671 Handle = IntPtr.Zero;
1673 base.Dispose (explicitDisposing);
1676 ~ProcessWaitHandle ()