2 // System.Diagnostics.Process.cs
5 // Dick Porter (dick@ximian.com)
6 // Andreas Nahr (ClassDevelopment@A-SoftTech.com)
8 // (C) 2002 Ximian, Inc.
9 // (C) 2003 Andreas Nahr
14 using System.ComponentModel;
15 using System.ComponentModel.Design;
16 using System.Runtime.CompilerServices;
17 using System.Runtime.InteropServices;
18 using System.Collections;
19 using System.Threading;
21 namespace System.Diagnostics {
22 [DefaultEvent ("Exited"), DefaultProperty ("StartInfo")]
23 [Designer ("System.Diagnostics.Design.ProcessDesigner, " + Consts.AssemblySystem_Design, typeof (IDesigner))]
24 public class Process : Component
26 [StructLayout(LayoutKind.Sequential)]
27 private struct ProcInfo
29 public IntPtr process_handle;
30 public IntPtr thread_handle;
31 public int pid; // Contains -GetLastError () on failure.
33 public string [] envKeys;
34 public string [] envValues;
35 public bool useShellExecute;
38 IntPtr process_handle;
40 bool enableRaisingEvents;
42 /* Private constructor called from other methods */
43 private Process(IntPtr handle, int id) {
44 process_handle=handle;
53 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
54 [MonitoringDescription ("Base process priority.")]
55 public int BasePriority {
62 [DefaultValue (false), Browsable (false)]
63 [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
64 public bool EnableRaisingEvents {
66 return enableRaisingEvents;
69 if (process_handle != IntPtr.Zero)
70 throw new InvalidOperationException ("The process is already started.");
72 enableRaisingEvents = value;
77 [MethodImplAttribute(MethodImplOptions.InternalCall)]
78 private extern static int ExitCode_internal(IntPtr handle);
80 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
81 [MonitoringDescription ("The exit code of the process.")]
84 if (process_handle == IntPtr.Zero)
85 throw new InvalidOperationException ("Process has not been started.");
87 int code = ExitCode_internal (process_handle);
89 throw new InvalidOperationException ("The process must exit before " +
90 "getting the requested information.");
96 /* Returns the process start time in Windows file
97 * times (ticks from DateTime(1/1/1601 00:00 GMT))
99 [MethodImplAttribute(MethodImplOptions.InternalCall)]
100 private extern static long ExitTime_internal(IntPtr handle);
102 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
103 [MonitoringDescription ("The exit time of the process.")]
104 public DateTime ExitTime {
106 if (process_handle == IntPtr.Zero)
107 throw new InvalidOperationException ("Process has not been started.");
110 throw new InvalidOperationException ("The process must exit before " +
111 "getting the requested information.");
113 return(DateTime.FromFileTime(ExitTime_internal(process_handle)));
117 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
118 [MonitoringDescription ("Handle for this process.")]
119 public IntPtr Handle {
121 return(process_handle);
126 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
127 [MonitoringDescription ("Handles for this process.")]
128 public int HandleCount {
134 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
135 [MonitoringDescription ("Determines if the process is still running.")]
136 public bool HasExited {
138 int exitcode = ExitCode_internal (process_handle);
149 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
150 [MonitoringDescription ("Process identifier.")]
158 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
159 [MonitoringDescription ("The name of the computer running the process.")]
160 public string MachineName {
166 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
167 [MonitoringDescription ("The main module of the process.")]
168 public ProcessModule MainModule {
170 return(this.Modules[0]);
175 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
176 [MonitoringDescription ("The handle of the main window of the process.")]
177 public IntPtr MainWindowHandle {
184 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
185 [MonitoringDescription ("The title of the main window of the process.")]
186 public string MainWindowTitle {
192 [MethodImplAttribute(MethodImplOptions.InternalCall)]
193 private extern static bool GetWorkingSet_internal(IntPtr handle, out int min, out int max);
194 [MethodImplAttribute(MethodImplOptions.InternalCall)]
195 private extern static bool SetWorkingSet_internal(IntPtr handle, int min, int max, bool use_min);
197 /* LAMESPEC: why is this an IntPtr not a plain int? */
198 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
199 [MonitoringDescription ("The maximum working set for this process.")]
200 public IntPtr MaxWorkingSet {
203 throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
208 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
210 throw new Win32Exception();
217 throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
220 bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
222 throw new Win32Exception();
227 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
228 [MonitoringDescription ("The minimum working set for this process.")]
229 public IntPtr MinWorkingSet {
232 throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
237 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
239 throw new Win32Exception();
246 throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
249 bool ok=SetWorkingSet_internal(process_handle, value.ToInt32(), 0, true);
251 throw new Win32Exception();
256 /* Returns the list of process modules. The main module is
259 [MethodImplAttribute(MethodImplOptions.InternalCall)]
260 private extern ProcessModule[] GetModules_internal();
262 private ProcessModuleCollection module_collection;
264 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
265 [MonitoringDescription ("The modules that are loaded as part of this process.")]
266 public ProcessModuleCollection Modules {
268 if(module_collection==null) {
269 module_collection=new ProcessModuleCollection(GetModules_internal());
272 return(module_collection);
277 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
278 [MonitoringDescription ("The number of bytes that are not pageable.")]
279 public int NonpagedSystemMemorySize {
286 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
287 [MonitoringDescription ("The number of bytes that are paged.")]
288 public int PagedMemorySize {
295 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
296 [MonitoringDescription ("The amount of paged system memory in bytes.")]
297 public int PagedSystemMemorySize {
304 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
305 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
306 public int PeakPagedMemorySize {
313 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
314 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
315 public int PeakVirtualMemorySize {
322 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
323 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
324 public int PeakWorkingSet {
331 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
332 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
333 public bool PriorityBoostEnabled {
342 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
343 [MonitoringDescription ("The relative process priority.")]
344 public ProcessPriorityClass PriorityClass {
346 return(ProcessPriorityClass.Normal);
353 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
354 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
355 public int PrivateMemorySize {
362 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
363 [MonitoringDescription ("The amount of processing time spent is the OS core for this process.")]
364 public TimeSpan PrivilegedProcessorTime {
366 return(new TimeSpan(0));
370 [MethodImplAttribute(MethodImplOptions.InternalCall)]
371 private extern static string ProcessName_internal(IntPtr handle);
373 private string process_name=null;
375 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
376 [MonitoringDescription ("The name of this process.")]
377 public string ProcessName {
379 if(process_name==null) {
380 process_name=ProcessName_internal(process_handle);
381 /* If process_name is _still_
382 * null, assume the process
385 if(process_name==null) {
386 throw new SystemException("The process has exited");
389 /* Strip the suffix (if it
390 * exists) simplistically
391 * instead of removing any
392 * trailing \.???, so we dont
393 * get stupid results on sane
396 if(process_name.EndsWith(".exe") ||
397 process_name.EndsWith(".bat") ||
398 process_name.EndsWith(".com")) {
399 process_name=process_name.Substring(0, process_name.Length-4);
402 return(process_name);
407 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
408 [MonitoringDescription ("Allowed processor that can be used by this process.")]
409 public IntPtr ProcessorAffinity {
418 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
419 [MonitoringDescription ("Is this process responsive.")]
420 public bool Responding {
426 private StreamReader error_stream=null;
428 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
429 [MonitoringDescription ("The standard error stream of this process.")]
430 public StreamReader StandardError {
432 return(error_stream);
436 private StreamWriter input_stream=null;
438 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
439 [MonitoringDescription ("The standard input stream of this process.")]
440 public StreamWriter StandardInput {
442 return(input_stream);
446 private StreamReader output_stream=null;
448 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
449 [MonitoringDescription ("The standard output stream of this process.")]
450 public StreamReader StandardOutput {
452 return(output_stream);
456 private ProcessStartInfo start_info=null;
458 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
459 [MonitoringDescription ("Information for the start of this process.")]
460 public ProcessStartInfo StartInfo {
462 if(start_info==null) {
463 start_info=new ProcessStartInfo();
470 throw new ArgumentException("value is null");
477 /* Returns the process start time in Windows file
478 * times (ticks from DateTime(1/1/1601 00:00 GMT))
480 [MethodImplAttribute(MethodImplOptions.InternalCall)]
481 private extern static long StartTime_internal(IntPtr handle);
483 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
484 [MonitoringDescription ("The time this process started.")]
485 public DateTime StartTime {
487 return(DateTime.FromFileTime(StartTime_internal(process_handle)));
492 [DefaultValue (null), Browsable (false)]
493 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
494 public ISynchronizeInvoke SynchronizingObject {
503 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
504 [MonitoringDescription ("The number of threads of this process.")]
505 public ProcessThreadCollection Threads {
512 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
513 [MonitoringDescription ("The total CPU time spent for this process.")]
514 public TimeSpan TotalProcessorTime {
516 return(new TimeSpan(0));
521 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
522 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
523 public TimeSpan UserProcessorTime {
525 return(new TimeSpan(0));
530 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
531 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
532 public int VirtualMemorySize {
539 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
540 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
541 public int WorkingSet {
548 public void Close() {
552 public bool CloseMainWindow() {
557 public static void EnterDebugMode() {
560 [MethodImplAttribute(MethodImplOptions.InternalCall)]
561 private extern static IntPtr GetProcess_internal(int pid);
563 [MethodImplAttribute(MethodImplOptions.InternalCall)]
564 private extern static int GetPid_internal();
566 public static Process GetCurrentProcess() {
567 int pid=GetPid_internal();
568 IntPtr proc=GetProcess_internal(pid);
570 if(proc==IntPtr.Zero) {
571 throw new SystemException("Can't find current process");
574 return(new Process(proc, pid));
577 public static Process GetProcessById(int processId) {
578 IntPtr proc=GetProcess_internal(processId);
580 if(proc==IntPtr.Zero) {
581 throw new ArgumentException("Can't find process with ID " + processId.ToString());
584 return(new Process(proc, processId));
588 public static Process GetProcessById(int processId, string machineName) {
589 throw new NotImplementedException();
592 [MethodImplAttribute(MethodImplOptions.InternalCall)]
593 private extern static int[] GetProcesses_internal();
595 public static Process[] GetProcesses() {
596 int[] pids=GetProcesses_internal();
597 ArrayList proclist=new ArrayList();
599 for(int i=0; i<pids.Length; i++) {
601 proclist.Add(GetProcessById(pids[i]));
602 } catch (SystemException) {
603 /* The process might exit
605 * GetProcesses_internal and
611 return((Process[])proclist.ToArray(typeof(Process)));
615 public static Process[] GetProcesses(string machineName) {
616 throw new NotImplementedException();
619 public static Process[] GetProcessesByName(string processName) {
620 Process[] procs=GetProcesses();
621 ArrayList proclist=new ArrayList();
623 for(int i=0; i<procs.Length; i++) {
625 if(String.Compare(processName,
626 procs[i].ProcessName,
628 proclist.Add(procs[i]);
632 return((Process[])proclist.ToArray(typeof(Process)));
636 public static Process[] GetProcessesByName(string processName, string machineName) {
637 throw new NotImplementedException();
645 public static void LeaveDebugMode() {
649 public void Refresh() {
652 [MethodImplAttribute(MethodImplOptions.InternalCall)]
653 private extern static bool Start_internal(string cmd,
658 ref ProcInfo proc_info);
660 private static bool Start_common(ProcessStartInfo startInfo,
662 ProcInfo proc_info=new ProcInfo();
663 IntPtr stdin_rd, stdin_wr;
664 IntPtr stdout_rd, stdout_wr;
665 IntPtr stderr_rd, stderr_wr;
668 if(startInfo.FileName == "") {
669 throw new InvalidOperationException("File name has not been set");
672 proc_info.useShellExecute = startInfo.UseShellExecute;
673 if (startInfo.HaveEnvVars) {
674 if (startInfo.UseShellExecute)
675 throw new InvalidOperationException ("UseShellExecute must be false in order " +
676 "to use environment variables.");
678 string [] strs = new string [startInfo.EnvironmentVariables.Count];
679 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
680 proc_info.envKeys = strs;
682 strs = new string [startInfo.EnvironmentVariables.Count];
683 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
684 proc_info.envValues = strs;
687 if(startInfo.RedirectStandardInput==true) {
688 ret=MonoIO.CreatePipe(out stdin_rd,
691 stdin_rd=MonoIO.ConsoleInput;
692 /* This is required to stop the
693 * &$*£ing stupid compiler moaning
694 * that stdin_wr is unassigned, below.
699 if(startInfo.RedirectStandardOutput==true) {
700 ret=MonoIO.CreatePipe(out stdout_rd,
704 stdout_wr=MonoIO.ConsoleOutput;
707 if(startInfo.RedirectStandardError==true) {
708 ret=MonoIO.CreatePipe(out stderr_rd,
712 stderr_wr=MonoIO.ConsoleError;
715 ret=Start_internal(startInfo.FileName + " " +
717 startInfo.WorkingDirectory,
718 stdin_rd, stdout_wr, stderr_wr,
724 if (startInfo.RedirectStandardInput == true)
725 MonoIO.Close (stdin_rd, out error);
727 if (startInfo.RedirectStandardOutput == true)
728 MonoIO.Close (stdout_wr, out error);
730 if (startInfo.RedirectStandardError == true)
731 MonoIO.Close (stderr_wr, out error);
733 throw new Win32Exception (-proc_info.pid);
736 if (process.enableRaisingEvents && process.Exited != null) {
737 WaitOrTimerCallback cb = new WaitOrTimerCallback (CBOnExit);
738 ProcessWaitHandle h = new ProcessWaitHandle (proc_info.process_handle);
739 ThreadPool.RegisterWaitForSingleObject (h, cb, process, -1, true);
742 process.process_handle=proc_info.process_handle;
743 process.pid=proc_info.pid;
745 if(startInfo.RedirectStandardInput==true) {
746 MonoIO.Close(stdin_rd, out error);
747 process.input_stream=new StreamWriter(new FileStream(stdin_wr, FileAccess.Write, true));
748 process.input_stream.AutoFlush=true;
751 if(startInfo.RedirectStandardOutput==true) {
752 MonoIO.Close(stdout_wr, out error);
753 process.output_stream=new StreamReader(new FileStream(stdout_rd, FileAccess.Read, true));
756 if(startInfo.RedirectStandardError==true) {
757 MonoIO.Close(stderr_wr, out error);
758 process.error_stream=new StreamReader(new FileStream(stderr_rd, FileAccess.Read, true));
764 public bool Start() {
767 ret=Start_common(start_info, this);
772 public static Process Start(ProcessStartInfo startInfo) {
773 Process process=new Process();
776 ret=Start_common(startInfo, process);
785 public static Process Start(string fileName) {
786 return Start(new ProcessStartInfo(fileName));
789 public static Process Start(string fileName,
791 return Start(new ProcessStartInfo(fileName, arguments));
794 public override string ToString() {
795 return(base.ToString() +
796 " (" + this.ProcessName + ")");
799 /* Waits up to ms milliseconds for process 'handle' to
800 * exit. ms can be <0 to mean wait forever.
802 [MethodImplAttribute(MethodImplOptions.InternalCall)]
803 private extern bool WaitForExit_internal(IntPtr handle,
806 public void WaitForExit() {
807 WaitForExit_internal(process_handle, -1);
810 public bool WaitForExit(int milliseconds) {
811 if (milliseconds == int.MaxValue)
814 return WaitForExit_internal (process_handle, milliseconds);
818 public bool WaitForInputIdle() {
823 public bool WaitForInputIdle(int milliseconds) {
828 [MonitoringDescription ("Raised when this process exits.")]
829 public event EventHandler Exited;
831 // Closes the system process handle
832 [MethodImplAttribute(MethodImplOptions.InternalCall)]
833 private extern void Process_free_internal(IntPtr handle);
835 private bool disposed = false;
837 protected override void Dispose(bool disposing) {
838 // Check to see if Dispose has already been called.
841 // If this is a call to Dispose,
842 // dispose all managed resources.
847 // Release unmanaged resources
850 if(process_handle!=IntPtr.Zero) {
852 Process_free_internal(process_handle);
853 process_handle=IntPtr.Zero;
857 base.Dispose (disposing);
860 static void CBOnExit (object state, bool unused)
862 Process p = (Process) state;
866 protected void OnExited()
869 Exited (this, EventArgs.Empty);
872 class ProcessWaitHandle : WaitHandle
874 public ProcessWaitHandle (IntPtr handle)