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)]
689 [MonitoringDescription ("The number of threads of this process.")]
690 public ProcessThreadCollection Threads {
692 // This'll return a correctly-sized array of empty ProcessThreads for now.
694 return new ProcessThreadCollection(new ProcessThread[GetProcessData (pid, 0, out error)]);
698 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
699 [MonitoringDescription ("The total CPU time spent for this process.")]
700 public TimeSpan TotalProcessorTime {
702 return new TimeSpan (Times (process_handle, 2));
706 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
707 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
708 public TimeSpan UserProcessorTime {
710 return new TimeSpan (Times (process_handle, 0));
714 [Obsolete ("Use VirtualMemorySize64")]
715 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
716 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
717 public int VirtualMemorySize {
720 return (int)GetProcessData (pid, 7, out error);
724 [Obsolete ("Use WorkingSet64")]
725 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
726 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
727 public int WorkingSet {
730 return (int)GetProcessData (pid, 4, out error);
734 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
735 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
737 public long PrivateMemorySize64 {
740 return GetProcessData (pid, 6, out error);
744 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
745 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
747 public long VirtualMemorySize64 {
750 return GetProcessData (pid, 7, out error);
754 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
755 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
757 public long WorkingSet64 {
760 return GetProcessData (pid, 4, out error);
769 [MethodImplAttribute(MethodImplOptions.InternalCall)]
770 extern static bool Kill_internal (IntPtr handle, int signo);
772 /* int kill -> 1 KILL, 2 CloseMainWindow */
773 bool Close (int signo)
775 if (process_handle == IntPtr.Zero)
776 throw new SystemException ("No process to kill.");
778 int exitcode = ExitCode_internal (process_handle);
780 throw new InvalidOperationException ("The process already finished.");
782 return Kill_internal (process_handle, signo);
785 public bool CloseMainWindow ()
791 public static void EnterDebugMode() {
794 [MethodImplAttribute(MethodImplOptions.InternalCall)]
795 private extern static IntPtr GetProcess_internal(int pid);
797 [MethodImplAttribute(MethodImplOptions.InternalCall)]
798 private extern static int GetPid_internal();
800 public static Process GetCurrentProcess()
802 int pid = GetPid_internal();
803 IntPtr proc = GetProcess_internal(pid);
805 if (proc == IntPtr.Zero)
806 throw new SystemException("Can't find current process");
808 return (new Process (proc, pid));
811 public static Process GetProcessById(int processId)
813 IntPtr proc = GetProcess_internal(processId);
815 if (proc == IntPtr.Zero)
816 throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
818 return (new Process (proc, processId));
821 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
822 public static Process GetProcessById(int processId, string machineName) {
823 if (machineName == null)
824 throw new ArgumentNullException ("machineName");
826 if (!IsLocalMachine (machineName))
827 throw new NotImplementedException ();
829 return GetProcessById (processId);
832 [MethodImplAttribute(MethodImplOptions.InternalCall)]
833 private extern static int[] GetProcesses_internal();
835 public static Process[] GetProcesses()
837 int [] pids = GetProcesses_internal ();
839 return new Process [0];
841 ArrayList proclist = new ArrayList (pids.Length);
842 for (int i = 0; i < pids.Length; i++) {
844 proclist.Add (GetProcessById (pids [i]));
845 } catch (SystemException) {
846 /* The process might exit
848 * GetProcesses_internal and
854 return ((Process []) proclist.ToArray (typeof (Process)));
857 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
858 public static Process[] GetProcesses(string machineName) {
859 if (machineName == null)
860 throw new ArgumentNullException ("machineName");
862 if (!IsLocalMachine (machineName))
863 throw new NotImplementedException ();
865 return GetProcesses ();
868 public static Process[] GetProcessesByName(string processName)
870 int [] pids = GetProcesses_internal ();
872 return new Process [0];
874 ArrayList proclist = new ArrayList (pids.Length);
875 for (int i = 0; i < pids.Length; i++) {
877 Process p = GetProcessById (pids [i]);
878 if (String.Compare (processName, p.ProcessName, true) == 0)
880 } catch (SystemException) {
881 /* The process might exit
883 * GetProcesses_internal and
889 return ((Process []) proclist.ToArray (typeof (Process)));
893 public static Process[] GetProcessesByName(string processName, string machineName) {
894 throw new NotImplementedException();
903 public static void LeaveDebugMode() {
906 public void Refresh ()
908 // FIXME: should refresh any cached data we might have about
909 // the process (currently we have none).
912 [MethodImplAttribute(MethodImplOptions.InternalCall)]
913 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
914 ref ProcInfo proc_info);
916 [MethodImplAttribute(MethodImplOptions.InternalCall)]
917 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
921 ref ProcInfo proc_info);
923 private static bool Start_shell (ProcessStartInfo startInfo,
926 ProcInfo proc_info=new ProcInfo();
929 if (startInfo.RedirectStandardInput ||
930 startInfo.RedirectStandardOutput ||
931 startInfo.RedirectStandardError) {
932 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
935 if (startInfo.HaveEnvVars)
936 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
938 FillUserInfo (startInfo, ref proc_info);
940 ret = ShellExecuteEx_internal (startInfo,
943 if (proc_info.Password != IntPtr.Zero)
944 Marshal.FreeBSTR (proc_info.Password);
945 proc_info.Password = IntPtr.Zero;
948 throw new Win32Exception (-proc_info.pid);
951 process.process_handle = proc_info.process_handle;
952 process.pid = proc_info.pid;
954 process.StartExitCallbackIfNeeded ();
959 private static bool Start_noshell (ProcessStartInfo startInfo,
962 ProcInfo proc_info=new ProcInfo();
963 IntPtr stdin_rd = IntPtr.Zero, stdin_wr = IntPtr.Zero;
969 if (startInfo.HaveEnvVars) {
970 string [] strs = new string [startInfo.EnvironmentVariables.Count];
971 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
972 proc_info.envKeys = strs;
974 strs = new string [startInfo.EnvironmentVariables.Count];
975 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
976 proc_info.envValues = strs;
979 if (startInfo.RedirectStandardInput == true) {
981 int DUPLICATE_SAME_ACCESS = 0x00000002;
984 ret = MonoIO.CreatePipe (out stdin_rd,
987 ret = MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, stdin_wr_tmp,
988 Process.GetCurrentProcess ().Handle, out stdin_wr, 0, 0, DUPLICATE_SAME_ACCESS);
989 MonoIO.Close (stdin_wr_tmp, out error);
994 ret = MonoIO.CreatePipe (out stdin_rd,
998 throw new IOException ("Error creating standard input pipe");
1001 stdin_rd = MonoIO.ConsoleInput;
1002 /* This is required to stop the
1003 * &$*£ing stupid compiler moaning
1004 * that stdin_wr is unassigned, below.
1006 stdin_wr = (IntPtr)0;
1009 if (startInfo.RedirectStandardOutput == true) {
1010 IntPtr out_rd = IntPtr.Zero;
1013 int DUPLICATE_SAME_ACCESS = 0x00000002;
1015 ret = MonoIO.CreatePipe (out out_rd_tmp,
1018 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, out_rd_tmp,
1019 Process.GetCurrentProcess ().Handle, out out_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1020 MonoIO.Close (out_rd_tmp, out error);
1024 ret = MonoIO.CreatePipe (out out_rd,
1028 process.stdout_rd = out_rd;
1030 if (startInfo.RedirectStandardInput == true) {
1031 MonoIO.Close (stdin_rd, out error);
1032 MonoIO.Close (stdin_wr, out error);
1035 throw new IOException ("Error creating standard output pipe");
1038 process.stdout_rd = (IntPtr)0;
1039 stdout_wr = MonoIO.ConsoleOutput;
1042 if (startInfo.RedirectStandardError == true) {
1043 IntPtr err_rd = IntPtr.Zero;
1046 int DUPLICATE_SAME_ACCESS = 0x00000002;
1048 ret = MonoIO.CreatePipe (out err_rd_tmp,
1051 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, err_rd_tmp,
1052 Process.GetCurrentProcess ().Handle, out err_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1053 MonoIO.Close (err_rd_tmp, out error);
1057 ret = MonoIO.CreatePipe (out err_rd,
1061 process.stderr_rd = err_rd;
1063 if (startInfo.RedirectStandardInput == true) {
1064 MonoIO.Close (stdin_rd, out error);
1065 MonoIO.Close (stdin_wr, out error);
1067 if (startInfo.RedirectStandardOutput == true) {
1068 MonoIO.Close (process.stdout_rd, out error);
1069 MonoIO.Close (stdout_wr, out error);
1072 throw new IOException ("Error creating standard error pipe");
1075 process.stderr_rd = (IntPtr)0;
1076 stderr_wr = MonoIO.ConsoleError;
1079 FillUserInfo (startInfo, ref proc_info);
1081 ret = CreateProcess_internal (startInfo,
1082 stdin_rd, stdout_wr, stderr_wr,
1085 if (proc_info.Password != IntPtr.Zero)
1086 Marshal.FreeBSTR (proc_info.Password);
1087 proc_info.Password = IntPtr.Zero;
1090 if (startInfo.RedirectStandardInput == true) {
1091 MonoIO.Close (stdin_rd, out error);
1092 MonoIO.Close (stdin_wr, out error);
1095 if (startInfo.RedirectStandardOutput == true) {
1096 MonoIO.Close (process.stdout_rd, out error);
1097 MonoIO.Close (stdout_wr, out error);
1100 if (startInfo.RedirectStandardError == true) {
1101 MonoIO.Close (process.stderr_rd, out error);
1102 MonoIO.Close (stderr_wr, out error);
1105 throw new Win32Exception (-proc_info.pid,
1106 "ApplicationName='" + startInfo.FileName +
1107 "', CommandLine='" + startInfo.Arguments +
1108 "', CurrentDirectory='" + startInfo.WorkingDirectory +
1109 "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
1112 process.process_handle = proc_info.process_handle;
1113 process.pid = proc_info.pid;
1115 if (startInfo.RedirectStandardInput == true) {
1116 MonoIO.Close (stdin_rd, out error);
1117 process.input_stream = new StreamWriter (new MonoSyncFileStream (stdin_wr, FileAccess.Write, true, 8192), Console.Out.Encoding);
1118 process.input_stream.AutoFlush = true;
1121 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1122 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1124 if (startInfo.RedirectStandardOutput == true) {
1125 MonoIO.Close (stdout_wr, out error);
1126 process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding, true, 8192);
1129 if (startInfo.RedirectStandardError == true) {
1130 MonoIO.Close (stderr_wr, out error);
1131 process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding, true, 8192);
1134 process.StartExitCallbackIfNeeded ();
1139 // Note that ProcInfo.Password must be freed.
1140 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1142 if (startInfo.UserName != null) {
1143 proc_info.UserName = startInfo.UserName;
1144 proc_info.Domain = startInfo.Domain;
1145 if (startInfo.Password != null)
1146 proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1148 proc_info.Password = IntPtr.Zero;
1149 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1153 private static bool Start_common (ProcessStartInfo startInfo,
1156 if (startInfo.FileName == null || startInfo.FileName.Length == 0)
1157 throw new InvalidOperationException("File name has not been set");
1159 if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1160 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1161 if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1162 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1164 if (startInfo.UseShellExecute) {
1165 if (!String.IsNullOrEmpty (startInfo.UserName))
1166 throw new InvalidOperationException ("UserShellExecute must be false if an explicit UserName is specified when starting a process");
1167 return (Start_shell (startInfo, process));
1169 return (Start_noshell (startInfo, process));
1173 public bool Start ()
1175 if (process_handle != IntPtr.Zero) {
1176 Process_free_internal (process_handle);
1177 process_handle = IntPtr.Zero;
1179 return Start_common(start_info, this);
1182 public static Process Start (ProcessStartInfo startInfo)
1184 if (startInfo == null)
1185 throw new ArgumentNullException ("startInfo");
1187 Process process=new Process();
1188 process.StartInfo = startInfo;
1189 if (Start_common(startInfo, process))
1194 public static Process Start (string fileName)
1196 return Start (new ProcessStartInfo (fileName));
1199 public static Process Start(string fileName, string arguments)
1201 return Start (new ProcessStartInfo (fileName, arguments));
1204 public static Process Start(string fileName, string username, SecureString password, string domain) {
1205 return Start(fileName, null, username, password, domain);
1208 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1209 ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1210 psi.UserName = username;
1211 psi.Password = password;
1212 psi.Domain = domain;
1213 psi.UseShellExecute = false;
1217 public override string ToString()
1219 return(base.ToString() + " (" + this.ProcessName + ")");
1222 /* Waits up to ms milliseconds for process 'handle' to
1223 * exit. ms can be <0 to mean wait forever.
1225 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1226 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1228 public void WaitForExit ()
1233 public bool WaitForExit(int milliseconds) {
1234 int ms = milliseconds;
1235 if (ms == int.MaxValue)
1238 DateTime start = DateTime.UtcNow;
1239 if (async_output != null && !async_output.IsCompleted) {
1240 if (false == async_output.WaitHandle.WaitOne (ms, false))
1241 return false; // Timed out
1244 DateTime now = DateTime.UtcNow;
1245 ms -= (int) (now - start).TotalMilliseconds;
1252 if (async_error != null && !async_error.IsCompleted) {
1253 if (false == async_error.WaitHandle.WaitOne (ms, false))
1254 return false; // Timed out
1257 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1262 return WaitForExit_internal (process_handle, ms);
1265 /* Waits up to ms milliseconds for process 'handle' to
1266 * wait for input. ms can be <0 to mean wait forever.
1268 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1269 private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
1271 // The internal call is only implemented properly on Windows.
1273 public bool WaitForInputIdle() {
1274 return WaitForInputIdle (-1);
1277 // The internal call is only implemented properly on Windows.
1279 public bool WaitForInputIdle(int milliseconds) {
1280 return WaitForInputIdle_internal (process_handle, milliseconds);
1283 private static bool IsLocalMachine (string machineName)
1285 if (machineName == "." || machineName.Length == 0)
1288 return (string.Compare (machineName, Environment.MachineName, true) == 0);
1292 [MonitoringDescription ("Raised when it receives output data")]
1293 public event DataReceivedEventHandler OutputDataReceived;
1295 [MonitoringDescription ("Raised when it receives error data")]
1296 public event DataReceivedEventHandler ErrorDataReceived;
1298 void OnOutputDataReceived (string str)
1300 if (OutputDataReceived != null)
1301 OutputDataReceived (this, new DataReceivedEventArgs (str));
1304 void OnErrorDataReceived (string str)
1306 if (ErrorDataReceived != null)
1307 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1315 AsyncOutput = 1 << 2,
1319 [StructLayout (LayoutKind.Sequential)]
1320 sealed class ProcessAsyncReader
1323 The following fields match those of SocketAsyncResult.
1324 This is so that changes needed in the runtime to handle
1325 asynchronous reads are trivial
1326 Keep this in sync with SocketAsyncResult in
1327 ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
1328 in metadata/socket-io.h.
1330 /* DON'T shuffle fields around. DON'T remove fields */
1332 public IntPtr handle;
1333 public object state;
1334 public AsyncCallback callback;
1335 public ManualResetEvent wait_handle;
1337 public Exception delayedException;
1339 public object EndPoint;
1340 byte [] buffer = new byte [4196];
1343 public int SockFlags;
1345 public object AcceptSocket;
1346 public object[] Addresses;
1348 public object Buffers; // Reserve this slot in older profiles
1349 public bool ReuseSocket; // Disconnect
1350 public object acc_socket;
1352 public bool completed_sync;
1354 bool err_out; // true -> stdout, false -> stderr
1356 public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1358 public int EndCalled;
1360 // These fields are not in SocketAsyncResult
1363 StringBuilder sb = new StringBuilder ();
1364 public AsyncReadHandler ReadHandler;
1366 public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1368 this.process = process;
1369 this.handle = handle;
1370 stream = new FileStream (handle, FileAccess.Read, false);
1371 this.ReadHandler = new AsyncReadHandler (AddInput);
1372 this.err_out = err_out;
1375 public void AddInput ()
1378 int nread = stream.Read (buffer, 0, buffer.Length);
1381 if (wait_handle != null)
1388 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1390 // Just in case the encoding fails...
1391 for (int i = 0; i < nread; i++) {
1392 sb.Append ((char) buffer [i]);
1397 ReadHandler.BeginInvoke (null, this);
1405 process.OnOutputDataReceived (null);
1407 process.OnErrorDataReceived (null);
1411 void Flush (bool last)
1413 if (sb.Length == 0 ||
1414 (err_out && process.output_canceled) ||
1415 (!err_out && process.error_canceled))
1418 string total = sb.ToString ();
1420 string [] strs = total.Split ('\n');
1421 int len = strs.Length;
1425 for (int i = 0; i < len - 1; i++) {
1427 process.OnOutputDataReceived (strs [i]);
1429 process.OnErrorDataReceived (strs [i]);
1432 string end = strs [len - 1];
1433 if (last || (len == 1 && end == "")) {
1435 process.OnOutputDataReceived (end);
1437 process.OnErrorDataReceived (end);
1444 public bool IsCompleted {
1445 get { return completed; }
1448 public WaitHandle WaitHandle {
1451 if (wait_handle == null)
1452 wait_handle = new ManualResetEvent (completed);
1458 public void Close () {
1463 AsyncModes async_mode;
1464 bool output_canceled;
1465 bool error_canceled;
1466 ProcessAsyncReader async_output;
1467 ProcessAsyncReader async_error;
1468 delegate void AsyncReadHandler ();
1470 [ComVisibleAttribute(false)]
1471 public void BeginOutputReadLine ()
1473 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1474 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1476 if ((async_mode & AsyncModes.SyncOutput) != 0)
1477 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1479 async_mode |= AsyncModes.AsyncOutput;
1480 output_canceled = false;
1481 if (async_output == null) {
1482 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1483 async_output.ReadHandler.BeginInvoke (null, async_output);
1487 [ComVisibleAttribute(false)]
1488 public void CancelOutputRead ()
1490 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1491 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1493 if ((async_mode & AsyncModes.SyncOutput) != 0)
1494 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1496 if (async_output == null)
1497 throw new InvalidOperationException ("No async operation in progress.");
1499 output_canceled = true;
1502 [ComVisibleAttribute(false)]
1503 public void BeginErrorReadLine ()
1505 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1506 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1508 if ((async_mode & AsyncModes.SyncError) != 0)
1509 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1511 async_mode |= AsyncModes.AsyncError;
1512 error_canceled = false;
1513 if (async_error == null) {
1514 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1515 async_error.ReadHandler.BeginInvoke (null, async_error);
1519 [ComVisibleAttribute(false)]
1520 public void CancelErrorRead ()
1522 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1523 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1525 if ((async_mode & AsyncModes.SyncOutput) != 0)
1526 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1528 if (async_error == null)
1529 throw new InvalidOperationException ("No async operation in progress.");
1531 error_canceled = true;
1534 [Category ("Behavior")]
1535 [MonitoringDescription ("Raised when this process exits.")]
1536 public event EventHandler Exited {
1538 if (process_handle != IntPtr.Zero && HasExited) {
1539 value.BeginInvoke (null, null, null, null);
1541 exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1542 if (exited_event != null)
1543 StartExitCallbackIfNeeded ();
1547 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1551 // Closes the system process handle
1552 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1553 private extern void Process_free_internal(IntPtr handle);
1555 private bool disposed = false;
1557 protected override void Dispose(bool disposing) {
1558 // Check to see if Dispose has already been called.
1559 if(this.disposed == false) {
1561 // If this is a call to Dispose,
1562 // dispose all managed resources.
1566 /* These have open FileStreams on the pipes we are about to close */
1567 if (async_output != null)
1568 async_output.Close ();
1569 if (async_error != null)
1570 async_error.Close ();
1574 // Release unmanaged resources
1577 if(process_handle!=IntPtr.Zero) {
1578 Process_free_internal(process_handle);
1579 process_handle=IntPtr.Zero;
1582 if (input_stream != null) {
1583 input_stream.Close();
1584 input_stream = null;
1587 if (output_stream != null) {
1588 output_stream.Close();
1589 output_stream = null;
1592 if (error_stream != null) {
1593 error_stream.Close();
1594 error_stream = null;
1598 base.Dispose (disposing);
1606 static void CBOnExit (object state, bool unused)
1608 Process p = (Process) state;
1609 p.already_waiting = false;
1613 protected void OnExited()
1615 if (exited_event == null)
1618 if (synchronizingObject == null) {
1619 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1621 d (this, EventArgs.Empty);
1627 object [] args = new object [] {this, EventArgs.Empty};
1628 synchronizingObject.BeginInvoke (exited_event, args);
1631 static bool IsWindows
1635 PlatformID platform = Environment.OSVersion.Platform;
1636 if (platform == PlatformID.Win32S ||
1637 platform == PlatformID.Win32Windows ||
1638 platform == PlatformID.Win32NT ||
1639 platform == PlatformID.WinCE) {
1646 class ProcessWaitHandle : WaitHandle
1648 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1649 private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1651 public ProcessWaitHandle (IntPtr handle)
1653 // Need to keep a reference to this handle,
1654 // in case the Process object is collected
1655 Handle = ProcessHandle_duplicate (handle);
1657 // When the wait handle is disposed, the duplicated handle will be
1658 // closed, so no need to override dispose (bug #464628).