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 && !HasExited) {
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);
339 [Obsolete ("Use NonpagedSystemMemorySize64")]
341 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
342 [MonitoringDescription ("The number of bytes that are not pageable.")]
343 public int NonpagedSystemMemorySize {
351 [Obsolete ("Use PagedMemorySize64")]
353 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
354 [MonitoringDescription ("The number of bytes that are paged.")]
355 public int PagedMemorySize {
363 [Obsolete ("Use PagedSystemMemorySize64")]
365 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
366 [MonitoringDescription ("The amount of paged system memory in bytes.")]
367 public int PagedSystemMemorySize {
375 [Obsolete ("Use PeakPagedMemorySize64")]
377 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
378 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
379 public int PeakPagedMemorySize {
387 [Obsolete ("Use PeakVirtualMemorySize64")]
389 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
390 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
391 public int PeakVirtualMemorySize {
399 [Obsolete ("Use PeakWorkingSet64")]
401 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
402 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
403 public int PeakWorkingSet {
411 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
412 [MonitoringDescription ("The number of bytes that are not pageable.")]
414 public long NonpagedSystemMemorySize64 {
421 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
422 [MonitoringDescription ("The number of bytes that are paged.")]
424 public long PagedMemorySize64 {
431 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
432 [MonitoringDescription ("The amount of paged system memory in bytes.")]
434 public long PagedSystemMemorySize64 {
441 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
442 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
444 public long PeakPagedMemorySize64 {
451 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
452 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
454 public long PeakVirtualMemorySize64 {
461 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
462 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
464 public long PeakWorkingSet64 {
472 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
473 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
474 public bool PriorityBoostEnabled {
482 [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
483 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
484 [MonitoringDescription ("The relative process priority.")]
485 public ProcessPriorityClass PriorityClass {
487 if (process_handle == IntPtr.Zero)
488 throw new InvalidOperationException ("Process has not been started.");
491 int prio = GetPriorityClass (process_handle, out error);
493 throw new Win32Exception (error);
494 return (ProcessPriorityClass) prio;
497 if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
498 throw new InvalidEnumArgumentException (
499 "value", (int) value,
500 typeof (ProcessPriorityClass));
502 if (process_handle == IntPtr.Zero)
503 throw new InvalidOperationException ("Process has not been started.");
506 if (!SetPriorityClass (process_handle, (int) value, out error))
507 throw new Win32Exception (error);
511 [MethodImplAttribute(MethodImplOptions.InternalCall)]
512 static extern int GetPriorityClass (IntPtr handle, out int error);
514 [MethodImplAttribute(MethodImplOptions.InternalCall)]
515 static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);
518 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
519 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
521 [Obsolete ("Use PrivateMemorySize64")]
523 public int PrivateMemorySize {
530 [MonoNotSupported ("")]
531 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
532 [MonitoringDescription ("The session ID for this process.")]
533 public int SessionId {
534 get { throw new NotImplementedException (); }
538 /* the meaning of type is as follows: 0: user, 1: system, 2: total */
539 [MethodImplAttribute(MethodImplOptions.InternalCall)]
540 private extern static long Times (IntPtr handle, int type);
542 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
543 [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
544 public TimeSpan PrivilegedProcessorTime {
546 return new TimeSpan (Times (process_handle, 1));
550 [MethodImplAttribute(MethodImplOptions.InternalCall)]
551 private extern static string ProcessName_internal(IntPtr handle);
553 private string process_name=null;
555 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
556 [MonitoringDescription ("The name of this process.")]
557 public string ProcessName {
559 if(process_name==null) {
560 process_name=ProcessName_internal(process_handle);
561 /* If process_name is _still_
562 * null, assume the process
565 if (process_name == null)
566 throw new SystemException("The process has exited");
568 /* Strip the suffix (if it
569 * exists) simplistically
570 * instead of removing any
571 * trailing \.???, so we dont
572 * get stupid results on sane
575 if(process_name.EndsWith(".exe") ||
576 process_name.EndsWith(".bat") ||
577 process_name.EndsWith(".com")) {
578 process_name=process_name.Substring(0, process_name.Length-4);
581 return(process_name);
586 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
587 [MonitoringDescription ("Allowed processor that can be used by this process.")]
588 public IntPtr ProcessorAffinity {
597 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
598 [MonitoringDescription ("Is this process responsive.")]
599 public bool Responding {
605 private StreamReader error_stream=null;
607 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
608 [MonitoringDescription ("The standard error stream of this process.")]
609 public StreamReader StandardError {
611 if (error_stream == null)
612 throw new InvalidOperationException("Standard error has not been redirected");
615 if ((async_mode & AsyncModes.AsyncError) != 0)
616 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
618 async_mode |= AsyncModes.SyncError;
621 return(error_stream);
625 private StreamWriter input_stream=null;
627 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
628 [MonitoringDescription ("The standard input stream of this process.")]
629 public StreamWriter StandardInput {
631 if (input_stream == null)
632 throw new InvalidOperationException("Standard input has not been redirected");
634 return(input_stream);
638 private StreamReader output_stream=null;
640 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
641 [MonitoringDescription ("The standard output stream of this process.")]
642 public StreamReader StandardOutput {
644 if (output_stream == null)
645 throw new InvalidOperationException("Standard output has not been redirected");
648 if ((async_mode & AsyncModes.AsyncOutput) != 0)
649 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
651 async_mode |= AsyncModes.SyncOutput;
654 return(output_stream);
658 private ProcessStartInfo start_info=null;
660 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
661 [MonitoringDescription ("Information for the start of this process.")]
662 public ProcessStartInfo StartInfo {
664 if (start_info == null)
665 start_info = new ProcessStartInfo();
670 throw new ArgumentNullException("value");
675 /* Returns the process start time in Windows file
676 * times (ticks from DateTime(1/1/1601 00:00 GMT))
678 [MethodImplAttribute(MethodImplOptions.InternalCall)]
679 private extern static long StartTime_internal(IntPtr handle);
681 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
682 [MonitoringDescription ("The time this process started.")]
683 public DateTime StartTime {
685 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
689 [DefaultValue (null), Browsable (false)]
690 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
691 public ISynchronizeInvoke SynchronizingObject {
692 get { return synchronizingObject; }
693 set { synchronizingObject = value; }
697 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
698 [MonitoringDescription ("The number of threads of this process.")]
699 public ProcessThreadCollection Threads {
701 return ProcessThreadCollection.GetEmpty ();
705 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
706 [MonitoringDescription ("The total CPU time spent for this process.")]
707 public TimeSpan TotalProcessorTime {
709 return new TimeSpan (Times (process_handle, 2));
713 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
714 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
715 public TimeSpan UserProcessorTime {
717 return new TimeSpan (Times (process_handle, 0));
723 [Obsolete ("Use VirtualMemorySize64")]
725 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
726 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
727 public int VirtualMemorySize {
735 [Obsolete ("Use WorkingSet64")]
737 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
738 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
739 public int WorkingSet {
747 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
748 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
750 public long PrivateMemorySize64 {
757 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
758 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
760 public long VirtualMemorySize64 {
767 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
768 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
770 public long WorkingSet64 {
782 [MethodImplAttribute(MethodImplOptions.InternalCall)]
783 extern static bool Kill_internal (IntPtr handle, int signo);
785 /* int kill -> 1 KILL, 2 CloseMainWindow */
786 bool Close (int signo)
788 if (process_handle == IntPtr.Zero)
789 throw new SystemException ("No process to kill.");
791 int exitcode = ExitCode_internal (process_handle);
793 throw new InvalidOperationException ("The process already finished.");
795 return Kill_internal (process_handle, signo);
798 public bool CloseMainWindow ()
804 public static void EnterDebugMode() {
807 [MethodImplAttribute(MethodImplOptions.InternalCall)]
808 private extern static IntPtr GetProcess_internal(int pid);
810 [MethodImplAttribute(MethodImplOptions.InternalCall)]
811 private extern static int GetPid_internal();
813 public static Process GetCurrentProcess()
815 int pid = GetPid_internal();
816 IntPtr proc = GetProcess_internal(pid);
818 if (proc == IntPtr.Zero)
819 throw new SystemException("Can't find current process");
821 return (new Process (proc, pid));
824 public static Process GetProcessById(int processId)
826 IntPtr proc = GetProcess_internal(processId);
828 if (proc == IntPtr.Zero)
829 throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
831 return (new Process (proc, processId));
834 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
835 public static Process GetProcessById(int processId, string machineName) {
836 if (machineName == null)
837 throw new ArgumentNullException ("machineName");
839 if (!IsLocalMachine (machineName))
840 throw new NotImplementedException ();
842 return GetProcessById (processId);
845 [MethodImplAttribute(MethodImplOptions.InternalCall)]
846 private extern static int[] GetProcesses_internal();
848 public static Process[] GetProcesses()
850 int [] pids = GetProcesses_internal ();
851 ArrayList proclist = new ArrayList ();
853 for (int i = 0; i < pids.Length; i++) {
855 proclist.Add (GetProcessById (pids [i]));
856 } catch (SystemException) {
857 /* The process might exit
859 * GetProcesses_internal and
865 return ((Process []) proclist.ToArray (typeof (Process)));
868 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
869 public static Process[] GetProcesses(string machineName) {
870 if (machineName == null)
871 throw new ArgumentNullException ("machineName");
873 if (!IsLocalMachine (machineName))
874 throw new NotImplementedException ();
876 return GetProcesses ();
879 public static Process[] GetProcessesByName(string processName)
881 Process [] procs = GetProcesses();
882 ArrayList proclist = new ArrayList();
884 for (int i = 0; i < procs.Length; i++) {
886 if (String.Compare (processName,
887 procs [i].ProcessName,
889 proclist.Add (procs [i]);
893 return ((Process[]) proclist.ToArray (typeof(Process)));
897 public static Process[] GetProcessesByName(string processName, string machineName) {
898 throw new NotImplementedException();
907 public static void LeaveDebugMode() {
910 public void Refresh ()
912 // FIXME: should refresh any cached data we might have about
913 // the process (currently we have none).
916 [MethodImplAttribute(MethodImplOptions.InternalCall)]
917 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
918 ref ProcInfo proc_info);
920 [MethodImplAttribute(MethodImplOptions.InternalCall)]
921 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
925 ref ProcInfo proc_info);
927 private static bool Start_shell (ProcessStartInfo startInfo,
930 ProcInfo proc_info=new ProcInfo();
933 if (startInfo.RedirectStandardInput ||
934 startInfo.RedirectStandardOutput ||
935 startInfo.RedirectStandardError) {
936 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
939 if (startInfo.HaveEnvVars)
940 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
942 FillUserInfo (startInfo, ref proc_info);
944 ret = ShellExecuteEx_internal (startInfo,
947 if (proc_info.Password != IntPtr.Zero)
948 Marshal.FreeBSTR (proc_info.Password);
949 proc_info.Password = IntPtr.Zero;
952 throw new Win32Exception (-proc_info.pid);
955 process.process_handle = proc_info.process_handle;
956 process.pid = proc_info.pid;
958 process.StartExitCallbackIfNeeded ();
963 private static bool Start_noshell (ProcessStartInfo startInfo,
966 ProcInfo proc_info=new ProcInfo();
967 IntPtr stdin_rd, stdin_wr;
973 if (startInfo.HaveEnvVars) {
974 string [] strs = new string [startInfo.EnvironmentVariables.Count];
975 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
976 proc_info.envKeys = strs;
978 strs = new string [startInfo.EnvironmentVariables.Count];
979 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
980 proc_info.envValues = strs;
983 if (startInfo.RedirectStandardInput == true) {
984 ret = MonoIO.CreatePipe (out stdin_rd,
987 throw new IOException ("Error creating standard input pipe");
990 stdin_rd = MonoIO.ConsoleInput;
991 /* This is required to stop the
992 * &$*£ing stupid compiler moaning
993 * that stdin_wr is unassigned, below.
995 stdin_wr = (IntPtr)0;
998 if (startInfo.RedirectStandardOutput == true) {
1000 ret = MonoIO.CreatePipe (out out_rd,
1003 process.stdout_rd = out_rd;
1005 if (startInfo.RedirectStandardInput == true) {
1006 MonoIO.Close (stdin_rd, out error);
1007 MonoIO.Close (stdin_wr, out error);
1010 throw new IOException ("Error creating standard output pipe");
1013 process.stdout_rd = (IntPtr)0;
1014 stdout_wr = MonoIO.ConsoleOutput;
1017 if (startInfo.RedirectStandardError == true) {
1019 ret = MonoIO.CreatePipe (out err_rd,
1022 process.stderr_rd = err_rd;
1024 if (startInfo.RedirectStandardInput == true) {
1025 MonoIO.Close (stdin_rd, out error);
1026 MonoIO.Close (stdin_wr, out error);
1028 if (startInfo.RedirectStandardOutput == true) {
1029 MonoIO.Close (process.stdout_rd, out error);
1030 MonoIO.Close (stdout_wr, out error);
1033 throw new IOException ("Error creating standard error pipe");
1036 process.stderr_rd = (IntPtr)0;
1037 stderr_wr = MonoIO.ConsoleError;
1040 FillUserInfo (startInfo, ref proc_info);
1042 ret = CreateProcess_internal (startInfo,
1043 stdin_rd, stdout_wr, stderr_wr,
1046 if (proc_info.Password != IntPtr.Zero)
1047 Marshal.FreeBSTR (proc_info.Password);
1048 proc_info.Password = IntPtr.Zero;
1051 if (startInfo.RedirectStandardInput == true) {
1052 MonoIO.Close (stdin_rd, out error);
1053 MonoIO.Close (stdin_wr, out error);
1056 if (startInfo.RedirectStandardOutput == true) {
1057 MonoIO.Close (process.stdout_rd, out error);
1058 MonoIO.Close (stdout_wr, out error);
1061 if (startInfo.RedirectStandardError == true) {
1062 MonoIO.Close (process.stderr_rd, out error);
1063 MonoIO.Close (stderr_wr, out error);
1066 throw new Win32Exception (-proc_info.pid,
1067 "ApplicationName='" + startInfo.FileName +
1068 "', CommandLine='" + startInfo.Arguments +
1069 "', CurrentDirectory='" + startInfo.WorkingDirectory + "'");
1072 process.process_handle = proc_info.process_handle;
1073 process.pid = proc_info.pid;
1075 if (startInfo.RedirectStandardInput == true) {
1076 MonoIO.Close (stdin_rd, out error);
1077 process.input_stream = new StreamWriter (new MonoSyncFileStream (stdin_wr, FileAccess.Write, true, 8192), Console.Out.Encoding);
1078 process.input_stream.AutoFlush = true;
1082 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1083 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1085 Encoding stdoutEncoding = Console.Out.Encoding;
1086 Encoding stderrEncoding = stdoutEncoding;
1089 if (startInfo.RedirectStandardOutput == true) {
1090 MonoIO.Close (stdout_wr, out error);
1091 process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding);
1094 if (startInfo.RedirectStandardError == true) {
1095 MonoIO.Close (stderr_wr, out error);
1096 process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding);
1099 process.StartExitCallbackIfNeeded ();
1104 // Note that ProcInfo.Password must be freed.
1105 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1108 if (startInfo.UserName != null) {
1109 proc_info.UserName = startInfo.UserName;
1110 proc_info.Domain = startInfo.Domain;
1111 if (startInfo.Password != null)
1112 proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1114 proc_info.Password = IntPtr.Zero;
1115 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1120 private static bool Start_common (ProcessStartInfo startInfo,
1123 if (startInfo.FileName == null || startInfo.FileName.Length == 0)
1124 throw new InvalidOperationException("File name has not been set");
1127 if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1128 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1129 if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1130 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1133 if (startInfo.UseShellExecute) {
1135 if (startInfo.UserName != null)
1136 throw new InvalidOperationException ("UserShellExecute must be false if an explicit UserName is specified when starting a process");
1138 return (Start_shell (startInfo, process));
1140 return (Start_noshell (startInfo, process));
1144 public bool Start ()
1146 if (process_handle != IntPtr.Zero) {
1147 Process_free_internal (process_handle);
1148 process_handle = IntPtr.Zero;
1150 return Start_common(start_info, this);
1153 public static Process Start (ProcessStartInfo startInfo)
1155 if (startInfo == null)
1156 throw new ArgumentNullException ("startInfo");
1158 Process process=new Process();
1159 process.StartInfo = startInfo;
1160 if (Start_common(startInfo, process))
1165 public static Process Start (string fileName)
1167 return Start (new ProcessStartInfo (fileName));
1170 public static Process Start(string fileName, string arguments)
1172 return Start (new ProcessStartInfo (fileName, arguments));
1176 public static Process Start(string fileName, string username, SecureString password, string domain) {
1177 return Start(fileName, null, username, password, domain);
1180 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1181 ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1182 psi.UserName = username;
1183 psi.Password = password;
1184 psi.Domain = domain;
1185 psi.UseShellExecute = false;
1190 public override string ToString()
1192 return(base.ToString() + " (" + this.ProcessName + ")");
1195 /* Waits up to ms milliseconds for process 'handle' to
1196 * exit. ms can be <0 to mean wait forever.
1198 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1199 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1201 public void WaitForExit ()
1206 public bool WaitForExit(int milliseconds) {
1207 int ms = milliseconds;
1208 if (ms == int.MaxValue)
1212 DateTime start = DateTime.UtcNow;
1213 if (async_output != null && !async_output.IsCompleted) {
1214 if (false == async_output.WaitHandle.WaitOne (ms, false))
1215 return false; // Timed out
1218 DateTime now = DateTime.UtcNow;
1219 ms -= (int) (now - start).TotalMilliseconds;
1226 if (async_error != null && !async_error.IsCompleted) {
1227 if (false == async_error.WaitHandle.WaitOne (ms, false))
1228 return false; // Timed out
1231 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1237 return WaitForExit_internal (process_handle, ms);
1241 public bool WaitForInputIdle() {
1246 public bool WaitForInputIdle(int milliseconds) {
1250 private static bool IsLocalMachine (string machineName)
1252 if (machineName == "." || machineName.Length == 0)
1255 return (string.Compare (machineName, Environment.MachineName, true) == 0);
1260 [MonitoringDescription ("Raised when it receives output data")]
1261 public event DataReceivedEventHandler OutputDataReceived;
1263 [MonitoringDescription ("Raised when it receives error data")]
1264 public event DataReceivedEventHandler ErrorDataReceived;
1266 void OnOutputDataReceived (string str)
1268 if (OutputDataReceived != null)
1269 OutputDataReceived (this, new DataReceivedEventArgs (str));
1272 void OnErrorDataReceived (string str)
1274 if (ErrorDataReceived != null)
1275 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1283 AsyncOutput = 1 << 2,
1287 [StructLayout (LayoutKind.Sequential)]
1288 sealed class ProcessAsyncReader
1291 The following fields match those of SocketAsyncResult.
1292 This is so that changes needed in the runtime to handle
1293 asynchronous reads are trivial
1295 /* DON'T shuffle fields around. DON'T remove fields */
1297 public IntPtr handle;
1298 public object state;
1299 public AsyncCallback callback;
1300 public ManualResetEvent wait_handle;
1302 public Exception delayedException;
1304 public object EndPoint;
1305 byte [] buffer = new byte [4196];
1308 public int SockFlags;
1310 public object acc_socket;
1312 public bool completed_sync;
1314 bool err_out; // true -> stdout, false -> stderr
1316 public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1320 // These fields are not in SocketAsyncResult
1323 StringBuilder sb = new StringBuilder ();
1324 public AsyncReadHandler ReadHandler;
1326 public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1328 this.process = process;
1329 this.handle = handle;
1330 stream = new FileStream (handle, FileAccess.Read, false);
1331 this.ReadHandler = new AsyncReadHandler (AddInput);
1332 this.err_out = err_out;
1335 public void AddInput ()
1338 int nread = stream.Read (buffer, 0, buffer.Length);
1341 if (wait_handle != null)
1348 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1350 // Just in case the encoding fails...
1351 for (int i = 0; i < nread; i++) {
1352 sb.Append ((char) buffer [i]);
1357 ReadHandler.BeginInvoke (null, this);
1361 void Flush (bool last)
1363 if (sb.Length == 0 ||
1364 (err_out && process.output_canceled) ||
1365 (!err_out && process.error_canceled))
1368 string total = sb.ToString ();
1370 string [] strs = total.Split ('\n');
1371 int len = strs.Length;
1375 for (int i = 0; i < len - 1; i++) {
1377 process.OnOutputDataReceived (strs [i]);
1379 process.OnErrorDataReceived (strs [i]);
1382 string end = strs [len - 1];
1383 if (last || (len == 1 && end == "")) {
1385 process.OnOutputDataReceived (end);
1387 process.OnErrorDataReceived (end);
1394 public bool IsCompleted {
1395 get { return completed; }
1398 public WaitHandle WaitHandle {
1401 if (wait_handle == null)
1402 wait_handle = new ManualResetEvent (completed);
1409 AsyncModes async_mode;
1410 bool output_canceled;
1411 bool error_canceled;
1412 ProcessAsyncReader async_output;
1413 ProcessAsyncReader async_error;
1414 delegate void AsyncReadHandler ();
1416 [ComVisibleAttribute(false)]
1417 public void BeginOutputReadLine ()
1419 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1420 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1422 if ((async_mode & AsyncModes.SyncOutput) != 0)
1423 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1425 async_mode |= AsyncModes.AsyncOutput;
1426 output_canceled = false;
1427 if (async_output == null) {
1428 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1429 async_output.ReadHandler.BeginInvoke (null, async_output);
1433 [ComVisibleAttribute(false)]
1434 public void CancelOutputRead ()
1436 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1437 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1439 if ((async_mode & AsyncModes.SyncOutput) != 0)
1440 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1442 if (async_output == null)
1443 throw new InvalidOperationException ("No async operation in progress.");
1445 output_canceled = true;
1448 [ComVisibleAttribute(false)]
1449 public void BeginErrorReadLine ()
1451 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1452 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1454 if ((async_mode & AsyncModes.SyncError) != 0)
1455 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1457 async_mode |= AsyncModes.AsyncError;
1458 error_canceled = false;
1459 if (async_error == null) {
1460 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1461 async_error.ReadHandler.BeginInvoke (null, async_error);
1465 [ComVisibleAttribute(false)]
1466 public void CancelErrorRead ()
1468 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1469 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1471 if ((async_mode & AsyncModes.SyncOutput) != 0)
1472 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1474 if (async_error == null)
1475 throw new InvalidOperationException ("No async operation in progress.");
1477 error_canceled = true;
1481 [Category ("Behavior")]
1482 [MonitoringDescription ("Raised when this process exits.")]
1483 public event EventHandler Exited {
1485 if (process_handle != IntPtr.Zero && HasExited) {
1486 value.BeginInvoke (null, null, null, null);
1488 exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1489 if (exited_event != null)
1490 StartExitCallbackIfNeeded ();
1494 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1498 // Closes the system process handle
1499 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1500 private extern void Process_free_internal(IntPtr handle);
1502 private bool disposed = false;
1504 protected override void Dispose(bool disposing) {
1505 // Check to see if Dispose has already been called.
1506 if(this.disposed == false) {
1508 // If this is a call to Dispose,
1509 // dispose all managed resources.
1514 // Release unmanaged resources
1517 if(process_handle!=IntPtr.Zero) {
1519 Process_free_internal(process_handle);
1520 process_handle=IntPtr.Zero;
1523 if (input_stream != null) {
1524 input_stream.Close();
1525 input_stream = null;
1528 if (output_stream != null) {
1529 output_stream.Close();
1530 output_stream = null;
1533 if (error_stream != null) {
1534 error_stream.Close();
1535 error_stream = null;
1539 base.Dispose (disposing);
1547 static void CBOnExit (object state, bool unused)
1549 Process p = (Process) state;
1553 protected void OnExited()
1555 if (exited_event == null)
1558 if (synchronizingObject == null) {
1559 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1561 d (this, EventArgs.Empty);
1567 object [] args = new object [] {this, EventArgs.Empty};
1568 synchronizingObject.BeginInvoke (exited_event, args);
1571 class ProcessWaitHandle : WaitHandle
1573 public ProcessWaitHandle (IntPtr handle)
1578 protected override void Dispose (bool explicitDisposing)
1580 // Do nothing, we don't own the handle and we won't close it.