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 ()
105 bool start = (!already_waiting && enableRaisingEvents && exited_event != null);
106 if (start && process_handle != IntPtr.Zero) {
107 WaitOrTimerCallback cb = new WaitOrTimerCallback (CBOnExit);
108 ProcessWaitHandle h = new ProcessWaitHandle (process_handle);
109 ThreadPool.RegisterWaitForSingleObject (h, cb, this, -1, true);
110 already_waiting = true;
114 [DefaultValue (false), Browsable (false)]
115 [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
116 public bool EnableRaisingEvents {
118 return enableRaisingEvents;
121 bool prev = enableRaisingEvents;
122 enableRaisingEvents = value;
123 if (enableRaisingEvents && !prev)
124 StartExitCallbackIfNeeded ();
129 [MethodImplAttribute(MethodImplOptions.InternalCall)]
130 private extern static int ExitCode_internal(IntPtr handle);
132 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
133 [MonitoringDescription ("The exit code of the process.")]
134 public int ExitCode {
136 if (process_handle == IntPtr.Zero)
137 throw new InvalidOperationException ("Process has not been started.");
139 int code = ExitCode_internal (process_handle);
141 throw new InvalidOperationException ("The process must exit before " +
142 "getting the requested information.");
148 /* Returns the process start time in Windows file
149 * times (ticks from DateTime(1/1/1601 00:00 GMT))
151 [MethodImplAttribute(MethodImplOptions.InternalCall)]
152 private extern static long ExitTime_internal(IntPtr handle);
154 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
155 [MonitoringDescription ("The exit time of the process.")]
156 public DateTime ExitTime {
158 if (process_handle == IntPtr.Zero)
159 throw new InvalidOperationException ("Process has not been started.");
162 throw new InvalidOperationException ("The process must exit before " +
163 "getting the requested information.");
165 return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
169 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
170 [MonitoringDescription ("Handle for this process.")]
171 public IntPtr Handle {
173 return(process_handle);
178 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
179 [MonitoringDescription ("Handles for this process.")]
180 public int HandleCount {
186 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
187 [MonitoringDescription ("Determines if the process is still running.")]
188 public bool HasExited {
190 if (process_handle == IntPtr.Zero)
191 throw new InvalidOperationException ("Process has not been started.");
193 int exitcode = ExitCode_internal (process_handle);
204 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
205 [MonitoringDescription ("Process identifier.")]
209 throw new InvalidOperationException ("Process ID has not been set.");
216 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
217 [MonitoringDescription ("The name of the computer running the process.")]
218 public string MachineName {
224 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
225 [MonitoringDescription ("The main module of the process.")]
226 public ProcessModule MainModule {
228 return(this.Modules[0]);
233 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
234 [MonitoringDescription ("The handle of the main window of the process.")]
235 public IntPtr MainWindowHandle {
242 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
243 [MonitoringDescription ("The title of the main window of the process.")]
244 public string MainWindowTitle {
250 [MethodImplAttribute(MethodImplOptions.InternalCall)]
251 private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
252 [MethodImplAttribute(MethodImplOptions.InternalCall)]
253 private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);
255 /* LAMESPEC: why is this an IntPtr not a plain int? */
256 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
257 [MonitoringDescription ("The maximum working set for this process.")]
258 public IntPtr MaxWorkingSet {
261 throw new InvalidOperationException(
262 "The process " + ProcessName +
263 " (ID " + Id + ") has exited");
267 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
269 throw new Win32Exception();
276 throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
279 bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
281 throw new Win32Exception();
286 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
287 [MonitoringDescription ("The minimum working set for this process.")]
288 public IntPtr MinWorkingSet {
291 throw new InvalidOperationException(
292 "The process " + ProcessName +
293 " (ID " + Id + ") has exited");
297 bool ok= GetWorkingSet_internal (process_handle, out min, out max);
299 throw new Win32Exception();
300 return ((IntPtr) min);
304 throw new InvalidOperationException(
305 "The process " + ProcessName +
306 " (ID " + Id + ") has exited");
308 bool ok = SetWorkingSet_internal (process_handle, value.ToInt32(), 0, true);
310 throw new Win32Exception();
314 /* Returns the list of process modules. The main module is
317 [MethodImplAttribute(MethodImplOptions.InternalCall)]
318 private extern ProcessModule[] GetModules_internal(IntPtr handle);
320 private ProcessModuleCollection module_collection;
322 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
323 [MonitoringDescription ("The modules that are loaded as part of this process.")]
324 public ProcessModuleCollection Modules {
326 if (module_collection == null)
327 module_collection = new ProcessModuleCollection(
328 GetModules_internal (process_handle));
329 return(module_collection);
333 /* data type is from the MonoProcessData enum in mono-proclib.h in the runtime */
334 [MethodImplAttribute(MethodImplOptions.InternalCall)]
335 private extern static long GetProcessData (int pid, int data_type, out int error);
338 [Obsolete ("Use NonpagedSystemMemorySize64")]
339 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
340 [MonitoringDescription ("The number of bytes that are not pageable.")]
341 public int NonpagedSystemMemorySize {
348 [Obsolete ("Use PagedMemorySize64")]
349 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
350 [MonitoringDescription ("The number of bytes that are paged.")]
351 public int PagedMemorySize {
358 [Obsolete ("Use PagedSystemMemorySize64")]
359 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
360 [MonitoringDescription ("The amount of paged system memory in bytes.")]
361 public int PagedSystemMemorySize {
368 [Obsolete ("Use PeakPagedMemorySize64")]
369 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
370 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
371 public int PeakPagedMemorySize {
377 [Obsolete ("Use PeakVirtualMemorySize64")]
378 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
379 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
380 public int PeakVirtualMemorySize {
383 return (int)GetProcessData (pid, 8, out error);
387 [Obsolete ("Use PeakWorkingSet64")]
388 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
389 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
390 public int PeakWorkingSet {
393 return (int)GetProcessData (pid, 5, out error);
398 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
399 [MonitoringDescription ("The number of bytes that are not pageable.")]
401 public long NonpagedSystemMemorySize64 {
408 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
409 [MonitoringDescription ("The number of bytes that are paged.")]
411 public long PagedMemorySize64 {
418 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
419 [MonitoringDescription ("The amount of paged system memory in bytes.")]
421 public long PagedSystemMemorySize64 {
428 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
429 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
431 public long PeakPagedMemorySize64 {
437 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
438 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
440 public long PeakVirtualMemorySize64 {
443 return GetProcessData (pid, 8, out error);
447 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
448 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
450 public long PeakWorkingSet64 {
453 return GetProcessData (pid, 5, out error);
458 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
459 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
460 public bool PriorityBoostEnabled {
468 [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
469 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
470 [MonitoringDescription ("The relative process priority.")]
471 public ProcessPriorityClass PriorityClass {
473 if (process_handle == IntPtr.Zero)
474 throw new InvalidOperationException ("Process has not been started.");
477 int prio = GetPriorityClass (process_handle, out error);
479 throw new Win32Exception (error);
480 return (ProcessPriorityClass) prio;
483 if (!Enum.IsDefined (typeof (ProcessPriorityClass), value))
484 throw new InvalidEnumArgumentException (
485 "value", (int) value,
486 typeof (ProcessPriorityClass));
488 if (process_handle == IntPtr.Zero)
489 throw new InvalidOperationException ("Process has not been started.");
492 if (!SetPriorityClass (process_handle, (int) value, out error)) {
494 throw new Win32Exception (error);
499 void CheckExited () {
501 throw new InvalidOperationException (String.Format ("Cannot process request because the process ({0}) has exited.", Id));
504 [MethodImplAttribute(MethodImplOptions.InternalCall)]
505 static extern int GetPriorityClass (IntPtr handle, out int error);
507 [MethodImplAttribute(MethodImplOptions.InternalCall)]
508 static extern bool SetPriorityClass (IntPtr handle, int priority, out int error);
510 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
511 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
512 [Obsolete ("Use PrivateMemorySize64")]
513 public int PrivateMemorySize {
516 return (int)GetProcessData (pid, 6, out error);
520 [MonoNotSupported ("")]
521 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
522 [MonitoringDescription ("The session ID for this process.")]
523 public int SessionId {
524 get { throw new NotImplementedException (); }
527 /* the meaning of type is as follows: 0: user, 1: system, 2: total */
528 [MethodImplAttribute(MethodImplOptions.InternalCall)]
529 private extern static long Times (IntPtr handle, int type);
531 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
532 [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
533 public TimeSpan PrivilegedProcessorTime {
535 return new TimeSpan (Times (process_handle, 1));
539 [MethodImplAttribute(MethodImplOptions.InternalCall)]
540 private extern static string ProcessName_internal(IntPtr handle);
542 private string process_name=null;
544 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
545 [MonitoringDescription ("The name of this process.")]
546 public string ProcessName {
548 if(process_name==null) {
550 if (process_handle == IntPtr.Zero)
551 throw new InvalidOperationException ("No process is associated with this object.");
553 process_name=ProcessName_internal(process_handle);
554 /* If process_name is _still_
555 * null, assume the process
558 if (process_name == null)
559 throw new InvalidOperationException ("Process has exited, so the requested information is not available.");
561 /* Strip the suffix (if it
562 * exists) simplistically
563 * instead of removing any
564 * trailing \.???, so we dont
565 * get stupid results on sane
568 if(process_name.EndsWith(".exe") ||
569 process_name.EndsWith(".bat") ||
570 process_name.EndsWith(".com")) {
571 process_name=process_name.Substring(0, process_name.Length-4);
574 return(process_name);
579 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
580 [MonitoringDescription ("Allowed processor that can be used by this process.")]
581 public IntPtr ProcessorAffinity {
590 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
591 [MonitoringDescription ("Is this process responsive.")]
592 public bool Responding {
598 private StreamReader error_stream=null;
600 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
601 [MonitoringDescription ("The standard error stream of this process.")]
602 public StreamReader StandardError {
604 if (error_stream == null)
605 throw new InvalidOperationException("Standard error has not been redirected");
607 if ((async_mode & AsyncModes.AsyncError) != 0)
608 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
610 async_mode |= AsyncModes.SyncError;
612 return(error_stream);
616 private StreamWriter input_stream=null;
618 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
619 [MonitoringDescription ("The standard input stream of this process.")]
620 public StreamWriter StandardInput {
622 if (input_stream == null)
623 throw new InvalidOperationException("Standard input has not been redirected");
625 return(input_stream);
629 private StreamReader output_stream=null;
631 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
632 [MonitoringDescription ("The standard output stream of this process.")]
633 public StreamReader StandardOutput {
635 if (output_stream == null)
636 throw new InvalidOperationException("Standard output has not been redirected");
638 if ((async_mode & AsyncModes.AsyncOutput) != 0)
639 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
641 async_mode |= AsyncModes.SyncOutput;
643 return(output_stream);
647 private ProcessStartInfo start_info=null;
649 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content), Browsable (false)]
650 [MonitoringDescription ("Information for the start of this process.")]
651 public ProcessStartInfo StartInfo {
653 if (start_info == null)
654 start_info = new ProcessStartInfo();
659 throw new ArgumentNullException("value");
664 /* Returns the process start time in Windows file
665 * times (ticks from DateTime(1/1/1601 00:00 GMT))
667 [MethodImplAttribute(MethodImplOptions.InternalCall)]
668 private extern static long StartTime_internal(IntPtr handle);
670 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
671 [MonitoringDescription ("The time this process started.")]
672 public DateTime StartTime {
674 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
678 [DefaultValue (null), Browsable (false)]
679 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
680 public ISynchronizeInvoke SynchronizingObject {
681 get { return synchronizingObject; }
682 set { synchronizingObject = value; }
686 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
687 [MonitoringDescription ("The number of threads of this process.")]
688 public ProcessThreadCollection Threads {
690 // This'll return a correctly-sized array of empty ProcessThreads for now.
692 return new ProcessThreadCollection(new ProcessThread[GetProcessData (pid, 0, out error)]);
696 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
697 [MonitoringDescription ("The total CPU time spent for this process.")]
698 public TimeSpan TotalProcessorTime {
700 return new TimeSpan (Times (process_handle, 2));
704 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
705 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
706 public TimeSpan UserProcessorTime {
708 return new TimeSpan (Times (process_handle, 0));
712 [Obsolete ("Use VirtualMemorySize64")]
713 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
714 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
715 public int VirtualMemorySize {
718 return (int)GetProcessData (pid, 7, out error);
722 [Obsolete ("Use WorkingSet64")]
723 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
724 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
725 public int WorkingSet {
728 return (int)GetProcessData (pid, 4, out error);
732 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
733 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
735 public long PrivateMemorySize64 {
738 return GetProcessData (pid, 6, out error);
742 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
743 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
745 public long VirtualMemorySize64 {
748 return GetProcessData (pid, 7, out error);
752 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
753 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
755 public long WorkingSet64 {
758 return GetProcessData (pid, 4, out error);
767 [MethodImplAttribute(MethodImplOptions.InternalCall)]
768 extern static bool Kill_internal (IntPtr handle, int signo);
770 /* int kill -> 1 KILL, 2 CloseMainWindow */
771 bool Close (int signo)
773 if (process_handle == IntPtr.Zero)
774 throw new SystemException ("No process to kill.");
776 int exitcode = ExitCode_internal (process_handle);
778 throw new InvalidOperationException ("The process already finished.");
780 return Kill_internal (process_handle, signo);
783 public bool CloseMainWindow ()
789 public static void EnterDebugMode() {
792 [MethodImplAttribute(MethodImplOptions.InternalCall)]
793 private extern static IntPtr GetProcess_internal(int pid);
795 [MethodImplAttribute(MethodImplOptions.InternalCall)]
796 private extern static int GetPid_internal();
798 public static Process GetCurrentProcess()
800 int pid = GetPid_internal();
801 IntPtr proc = GetProcess_internal(pid);
803 if (proc == IntPtr.Zero)
804 throw new SystemException("Can't find current process");
806 return (new Process (proc, pid));
809 public static Process GetProcessById(int processId)
811 IntPtr proc = GetProcess_internal(processId);
813 if (proc == IntPtr.Zero)
814 throw new ArgumentException ("Can't find process with ID " + processId.ToString ());
816 return (new Process (proc, processId));
819 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
820 public static Process GetProcessById(int processId, string machineName) {
821 if (machineName == null)
822 throw new ArgumentNullException ("machineName");
824 if (!IsLocalMachine (machineName))
825 throw new NotImplementedException ();
827 return GetProcessById (processId);
830 [MethodImplAttribute(MethodImplOptions.InternalCall)]
831 private extern static int[] GetProcesses_internal();
833 public static Process[] GetProcesses()
835 int [] pids = GetProcesses_internal ();
837 return new Process [0];
839 ArrayList proclist = new ArrayList (pids.Length);
840 for (int i = 0; i < pids.Length; i++) {
842 proclist.Add (GetProcessById (pids [i]));
843 } catch (SystemException) {
844 /* The process might exit
846 * GetProcesses_internal and
852 return ((Process []) proclist.ToArray (typeof (Process)));
855 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
856 public static Process[] GetProcesses(string machineName) {
857 if (machineName == null)
858 throw new ArgumentNullException ("machineName");
860 if (!IsLocalMachine (machineName))
861 throw new NotImplementedException ();
863 return GetProcesses ();
866 public static Process[] GetProcessesByName(string processName)
868 int [] pids = GetProcesses_internal ();
870 return new Process [0];
872 ArrayList proclist = new ArrayList (pids.Length);
873 for (int i = 0; i < pids.Length; i++) {
875 Process p = GetProcessById (pids [i]);
876 if (String.Compare (processName, p.ProcessName, true) == 0)
878 } catch (SystemException) {
879 /* The process might exit
881 * GetProcesses_internal and
887 return ((Process []) proclist.ToArray (typeof (Process)));
891 public static Process[] GetProcessesByName(string processName, string machineName) {
892 throw new NotImplementedException();
901 public static void LeaveDebugMode() {
904 public void Refresh ()
906 // FIXME: should refresh any cached data we might have about
907 // the process (currently we have none).
910 [MethodImplAttribute(MethodImplOptions.InternalCall)]
911 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
912 ref ProcInfo proc_info);
914 [MethodImplAttribute(MethodImplOptions.InternalCall)]
915 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
919 ref ProcInfo proc_info);
921 private static bool Start_shell (ProcessStartInfo startInfo,
924 ProcInfo proc_info=new ProcInfo();
927 if (startInfo.RedirectStandardInput ||
928 startInfo.RedirectStandardOutput ||
929 startInfo.RedirectStandardError) {
930 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
933 if (startInfo.HaveEnvVars)
934 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
936 FillUserInfo (startInfo, ref proc_info);
938 ret = ShellExecuteEx_internal (startInfo,
941 if (proc_info.Password != IntPtr.Zero)
942 Marshal.FreeBSTR (proc_info.Password);
943 proc_info.Password = IntPtr.Zero;
946 throw new Win32Exception (-proc_info.pid);
949 process.process_handle = proc_info.process_handle;
950 process.pid = proc_info.pid;
952 process.StartExitCallbackIfNeeded ();
957 private static bool Start_noshell (ProcessStartInfo startInfo,
960 ProcInfo proc_info=new ProcInfo();
961 IntPtr stdin_rd = IntPtr.Zero, stdin_wr = IntPtr.Zero;
967 if (startInfo.HaveEnvVars) {
968 string [] strs = new string [startInfo.EnvironmentVariables.Count];
969 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
970 proc_info.envKeys = strs;
972 strs = new string [startInfo.EnvironmentVariables.Count];
973 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
974 proc_info.envValues = strs;
977 if (startInfo.RedirectStandardInput == true) {
979 int DUPLICATE_SAME_ACCESS = 0x00000002;
982 ret = MonoIO.CreatePipe (out stdin_rd,
985 ret = MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, stdin_wr_tmp,
986 Process.GetCurrentProcess ().Handle, out stdin_wr, 0, 0, DUPLICATE_SAME_ACCESS);
987 MonoIO.Close (stdin_wr_tmp, out error);
992 ret = MonoIO.CreatePipe (out stdin_rd,
996 throw new IOException ("Error creating standard input pipe");
999 stdin_rd = MonoIO.ConsoleInput;
1000 /* This is required to stop the
1001 * &$*£ing stupid compiler moaning
1002 * that stdin_wr is unassigned, below.
1004 stdin_wr = (IntPtr)0;
1007 if (startInfo.RedirectStandardOutput == true) {
1008 IntPtr out_rd = IntPtr.Zero;
1011 int DUPLICATE_SAME_ACCESS = 0x00000002;
1013 ret = MonoIO.CreatePipe (out out_rd_tmp,
1016 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, out_rd_tmp,
1017 Process.GetCurrentProcess ().Handle, out out_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1018 MonoIO.Close (out_rd_tmp, out error);
1022 ret = MonoIO.CreatePipe (out out_rd,
1026 process.stdout_rd = out_rd;
1028 if (startInfo.RedirectStandardInput == true) {
1029 MonoIO.Close (stdin_rd, out error);
1030 MonoIO.Close (stdin_wr, out error);
1033 throw new IOException ("Error creating standard output pipe");
1036 process.stdout_rd = (IntPtr)0;
1037 stdout_wr = MonoIO.ConsoleOutput;
1040 if (startInfo.RedirectStandardError == true) {
1041 IntPtr err_rd = IntPtr.Zero;
1044 int DUPLICATE_SAME_ACCESS = 0x00000002;
1046 ret = MonoIO.CreatePipe (out err_rd_tmp,
1049 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, err_rd_tmp,
1050 Process.GetCurrentProcess ().Handle, out err_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1051 MonoIO.Close (err_rd_tmp, out error);
1055 ret = MonoIO.CreatePipe (out err_rd,
1059 process.stderr_rd = err_rd;
1061 if (startInfo.RedirectStandardInput == true) {
1062 MonoIO.Close (stdin_rd, out error);
1063 MonoIO.Close (stdin_wr, out error);
1065 if (startInfo.RedirectStandardOutput == true) {
1066 MonoIO.Close (process.stdout_rd, out error);
1067 MonoIO.Close (stdout_wr, out error);
1070 throw new IOException ("Error creating standard error pipe");
1073 process.stderr_rd = (IntPtr)0;
1074 stderr_wr = MonoIO.ConsoleError;
1077 FillUserInfo (startInfo, ref proc_info);
1079 ret = CreateProcess_internal (startInfo,
1080 stdin_rd, stdout_wr, stderr_wr,
1083 if (proc_info.Password != IntPtr.Zero)
1084 Marshal.FreeBSTR (proc_info.Password);
1085 proc_info.Password = IntPtr.Zero;
1088 if (startInfo.RedirectStandardInput == true) {
1089 MonoIO.Close (stdin_rd, out error);
1090 MonoIO.Close (stdin_wr, out error);
1093 if (startInfo.RedirectStandardOutput == true) {
1094 MonoIO.Close (process.stdout_rd, out error);
1095 MonoIO.Close (stdout_wr, out error);
1098 if (startInfo.RedirectStandardError == true) {
1099 MonoIO.Close (process.stderr_rd, out error);
1100 MonoIO.Close (stderr_wr, out error);
1103 throw new Win32Exception (-proc_info.pid,
1104 "ApplicationName='" + startInfo.FileName +
1105 "', CommandLine='" + startInfo.Arguments +
1106 "', CurrentDirectory='" + startInfo.WorkingDirectory +
1107 "', Native error= " + Win32Exception.W32ErrorMessage (-proc_info.pid));
1110 process.process_handle = proc_info.process_handle;
1111 process.pid = proc_info.pid;
1113 if (startInfo.RedirectStandardInput == true) {
1114 MonoIO.Close (stdin_rd, out error);
1115 process.input_stream = new StreamWriter (new MonoSyncFileStream (stdin_wr, FileAccess.Write, true, 8192), Console.Out.Encoding);
1116 process.input_stream.AutoFlush = true;
1119 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1120 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1122 if (startInfo.RedirectStandardOutput == true) {
1123 MonoIO.Close (stdout_wr, out error);
1124 process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding, true, 8192);
1127 if (startInfo.RedirectStandardError == true) {
1128 MonoIO.Close (stderr_wr, out error);
1129 process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding, true, 8192);
1132 process.StartExitCallbackIfNeeded ();
1137 // Note that ProcInfo.Password must be freed.
1138 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1140 if (startInfo.UserName != null) {
1141 proc_info.UserName = startInfo.UserName;
1142 proc_info.Domain = startInfo.Domain;
1143 if (startInfo.Password != null)
1144 proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1146 proc_info.Password = IntPtr.Zero;
1147 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1151 private static bool Start_common (ProcessStartInfo startInfo,
1154 if (startInfo.FileName == null || startInfo.FileName.Length == 0)
1155 throw new InvalidOperationException("File name has not been set");
1157 if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1158 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1159 if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1160 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1162 if (startInfo.UseShellExecute) {
1163 if (!String.IsNullOrEmpty (startInfo.UserName))
1164 throw new InvalidOperationException ("UserShellExecute must be false if an explicit UserName is specified when starting a process");
1165 return (Start_shell (startInfo, process));
1167 return (Start_noshell (startInfo, process));
1171 public bool Start ()
1173 if (process_handle != IntPtr.Zero) {
1174 Process_free_internal (process_handle);
1175 process_handle = IntPtr.Zero;
1177 return Start_common(start_info, this);
1180 public static Process Start (ProcessStartInfo startInfo)
1182 if (startInfo == null)
1183 throw new ArgumentNullException ("startInfo");
1185 Process process=new Process();
1186 process.StartInfo = startInfo;
1187 if (Start_common(startInfo, process))
1192 public static Process Start (string fileName)
1194 return Start (new ProcessStartInfo (fileName));
1197 public static Process Start(string fileName, string arguments)
1199 return Start (new ProcessStartInfo (fileName, arguments));
1202 public static Process Start(string fileName, string username, SecureString password, string domain) {
1203 return Start(fileName, null, username, password, domain);
1206 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1207 ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1208 psi.UserName = username;
1209 psi.Password = password;
1210 psi.Domain = domain;
1211 psi.UseShellExecute = false;
1215 public override string ToString()
1217 return(base.ToString() + " (" + this.ProcessName + ")");
1220 /* Waits up to ms milliseconds for process 'handle' to
1221 * exit. ms can be <0 to mean wait forever.
1223 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1224 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1226 public void WaitForExit ()
1231 public bool WaitForExit(int milliseconds) {
1232 int ms = milliseconds;
1233 if (ms == int.MaxValue)
1236 DateTime start = DateTime.UtcNow;
1237 if (async_output != null && !async_output.IsCompleted) {
1238 if (false == async_output.WaitHandle.WaitOne (ms, false))
1239 return false; // Timed out
1242 DateTime now = DateTime.UtcNow;
1243 ms -= (int) (now - start).TotalMilliseconds;
1250 if (async_error != null && !async_error.IsCompleted) {
1251 if (false == async_error.WaitHandle.WaitOne (ms, false))
1252 return false; // Timed out
1255 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1260 return WaitForExit_internal (process_handle, ms);
1263 /* Waits up to ms milliseconds for process 'handle' to
1264 * wait for input. ms can be <0 to mean wait forever.
1266 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1267 private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
1269 // The internal call is only implemented properly on Windows.
1271 public bool WaitForInputIdle() {
1272 return WaitForInputIdle (-1);
1275 // The internal call is only implemented properly on Windows.
1277 public bool WaitForInputIdle(int milliseconds) {
1278 return WaitForInputIdle_internal (process_handle, milliseconds);
1281 private static bool IsLocalMachine (string machineName)
1283 if (machineName == "." || machineName.Length == 0)
1286 return (string.Compare (machineName, Environment.MachineName, true) == 0);
1290 [MonitoringDescription ("Raised when it receives output data")]
1291 public event DataReceivedEventHandler OutputDataReceived;
1293 [MonitoringDescription ("Raised when it receives error data")]
1294 public event DataReceivedEventHandler ErrorDataReceived;
1296 void OnOutputDataReceived (string str)
1298 if (OutputDataReceived != null)
1299 OutputDataReceived (this, new DataReceivedEventArgs (str));
1302 void OnErrorDataReceived (string str)
1304 if (ErrorDataReceived != null)
1305 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1313 AsyncOutput = 1 << 2,
1317 [StructLayout (LayoutKind.Sequential)]
1318 sealed class ProcessAsyncReader
1321 The following fields match those of SocketAsyncResult.
1322 This is so that changes needed in the runtime to handle
1323 asynchronous reads are trivial
1324 Keep this in sync with SocketAsyncResult in
1325 ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
1326 in metadata/socket-io.h.
1328 /* DON'T shuffle fields around. DON'T remove fields */
1330 public IntPtr handle;
1331 public object state;
1332 public AsyncCallback callback;
1333 public ManualResetEvent wait_handle;
1335 public Exception delayedException;
1337 public object EndPoint;
1338 byte [] buffer = new byte [4196];
1341 public int SockFlags;
1343 public object AcceptSocket;
1344 public object[] Addresses;
1346 public object Buffers; // Reserve this slot in older profiles
1347 public bool ReuseSocket; // Disconnect
1348 public object acc_socket;
1350 public bool completed_sync;
1352 bool err_out; // true -> stdout, false -> stderr
1354 public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1356 public int EndCalled;
1358 // These fields are not in SocketAsyncResult
1361 StringBuilder sb = new StringBuilder ();
1362 public AsyncReadHandler ReadHandler;
1364 public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1366 this.process = process;
1367 this.handle = handle;
1368 stream = new FileStream (handle, FileAccess.Read, false);
1369 this.ReadHandler = new AsyncReadHandler (AddInput);
1370 this.err_out = err_out;
1373 public void AddInput ()
1376 int nread = stream.Read (buffer, 0, buffer.Length);
1379 if (wait_handle != null)
1386 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1388 // Just in case the encoding fails...
1389 for (int i = 0; i < nread; i++) {
1390 sb.Append ((char) buffer [i]);
1395 ReadHandler.BeginInvoke (null, this);
1403 process.OnOutputDataReceived (null);
1405 process.OnErrorDataReceived (null);
1409 void Flush (bool last)
1411 if (sb.Length == 0 ||
1412 (err_out && process.output_canceled) ||
1413 (!err_out && process.error_canceled))
1416 string total = sb.ToString ();
1418 string [] strs = total.Split ('\n');
1419 int len = strs.Length;
1423 for (int i = 0; i < len - 1; i++) {
1425 process.OnOutputDataReceived (strs [i]);
1427 process.OnErrorDataReceived (strs [i]);
1430 string end = strs [len - 1];
1431 if (last || (len == 1 && end == "")) {
1433 process.OnOutputDataReceived (end);
1435 process.OnErrorDataReceived (end);
1442 public bool IsCompleted {
1443 get { return completed; }
1446 public WaitHandle WaitHandle {
1449 if (wait_handle == null)
1450 wait_handle = new ManualResetEvent (completed);
1456 public void Close () {
1461 AsyncModes async_mode;
1462 bool output_canceled;
1463 bool error_canceled;
1464 ProcessAsyncReader async_output;
1465 ProcessAsyncReader async_error;
1466 delegate void AsyncReadHandler ();
1468 [ComVisibleAttribute(false)]
1469 public void BeginOutputReadLine ()
1471 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1472 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1474 if ((async_mode & AsyncModes.SyncOutput) != 0)
1475 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1477 async_mode |= AsyncModes.AsyncOutput;
1478 output_canceled = false;
1479 if (async_output == null) {
1480 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1481 async_output.ReadHandler.BeginInvoke (null, async_output);
1485 [ComVisibleAttribute(false)]
1486 public void CancelOutputRead ()
1488 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1489 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1491 if ((async_mode & AsyncModes.SyncOutput) != 0)
1492 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1494 if (async_output == null)
1495 throw new InvalidOperationException ("No async operation in progress.");
1497 output_canceled = true;
1500 [ComVisibleAttribute(false)]
1501 public void BeginErrorReadLine ()
1503 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1504 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1506 if ((async_mode & AsyncModes.SyncError) != 0)
1507 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1509 async_mode |= AsyncModes.AsyncError;
1510 error_canceled = false;
1511 if (async_error == null) {
1512 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1513 async_error.ReadHandler.BeginInvoke (null, async_error);
1517 [ComVisibleAttribute(false)]
1518 public void CancelErrorRead ()
1520 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1521 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1523 if ((async_mode & AsyncModes.SyncOutput) != 0)
1524 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1526 if (async_error == null)
1527 throw new InvalidOperationException ("No async operation in progress.");
1529 error_canceled = true;
1532 [Category ("Behavior")]
1533 [MonitoringDescription ("Raised when this process exits.")]
1534 public event EventHandler Exited {
1536 if (process_handle != IntPtr.Zero && HasExited) {
1537 value.BeginInvoke (null, null, null, null);
1539 exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1540 if (exited_event != null)
1541 StartExitCallbackIfNeeded ();
1545 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1549 // Closes the system process handle
1550 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1551 private extern void Process_free_internal(IntPtr handle);
1553 private bool disposed = false;
1555 protected override void Dispose(bool disposing) {
1556 // Check to see if Dispose has already been called.
1557 if(this.disposed == false) {
1559 // If this is a call to Dispose,
1560 // dispose all managed resources.
1564 /* These have open FileStreams on the pipes we are about to close */
1565 if (async_output != null)
1566 async_output.Close ();
1567 if (async_error != null)
1568 async_error.Close ();
1570 if (input_stream != null) {
1571 input_stream.Close();
1572 input_stream = null;
1575 if (output_stream != null) {
1576 output_stream.Close();
1577 output_stream = null;
1580 if (error_stream != null) {
1581 error_stream.Close();
1582 error_stream = null;
1587 // Release unmanaged resources
1590 if(process_handle!=IntPtr.Zero) {
1591 Process_free_internal(process_handle);
1592 process_handle=IntPtr.Zero;
1596 base.Dispose (disposing);
1604 static void CBOnExit (object state, bool unused)
1606 Process p = (Process) state;
1607 p.already_waiting = false;
1611 protected void OnExited()
1613 if (exited_event == null)
1616 if (synchronizingObject == null) {
1617 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1619 d (this, EventArgs.Empty);
1625 object [] args = new object [] {this, EventArgs.Empty};
1626 synchronizingObject.BeginInvoke (exited_event, args);
1629 static bool IsWindows
1633 PlatformID platform = Environment.OSVersion.Platform;
1634 if (platform == PlatformID.Win32S ||
1635 platform == PlatformID.Win32Windows ||
1636 platform == PlatformID.Win32NT ||
1637 platform == PlatformID.WinCE) {
1644 class ProcessWaitHandle : WaitHandle
1646 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1647 private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1649 public ProcessWaitHandle (IntPtr handle)
1651 // Need to keep a reference to this handle,
1652 // in case the Process object is collected
1653 Handle = ProcessHandle_duplicate (handle);
1655 // When the wait handle is disposed, the duplicated handle will be
1656 // closed, so no need to override dispose (bug #464628).