2 // System.Diagnostics.Process.cs
5 // Dick Porter (dick@ximian.com)
6 // Andreas Nahr (ClassDevelopment@A-SoftTech.com)
7 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 // (C) 2002 Ximian, Inc.
10 // (C) 2003 Andreas Nahr
11 // (c) 2004,2005,2006 Novell, Inc. (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 using System
.ComponentModel
;
38 using System
.ComponentModel
.Design
;
39 using System
.Runtime
.CompilerServices
;
40 using System
.Runtime
.InteropServices
;
41 using System
.Security
.Permissions
;
42 using System
.Collections
;
43 using System
.Security
;
44 using System
.Threading
;
46 namespace System
.Diagnostics
{
48 [DefaultEvent ("Exited"), DefaultProperty ("StartInfo")]
49 [Designer ("System.Diagnostics.Design.ProcessDesigner, " + Consts
.AssemblySystem_Design
)]
50 [PermissionSet (SecurityAction
.LinkDemand
, Unrestricted
= true)]
51 [PermissionSet (SecurityAction
.InheritanceDemand
, Unrestricted
= true)]
53 [MonitoringDescription ("Represents a system process")]
55 public class Process
: Component
57 [StructLayout(LayoutKind
.Sequential
)]
58 private struct ProcInfo
60 public IntPtr process_handle
;
61 /* If thread_handle is ever needed for
62 * something, take out the CloseHandle() in
63 * the Start_internal icall in
64 * mono/metadata/process.c
66 public IntPtr thread_handle
;
67 public int pid
; // Contains -GetLastError () on failure.
69 public string [] envKeys
;
70 public string [] envValues
;
71 public string UserName
;
73 public IntPtr Password
;
74 public bool LoadUserProfile
;
77 IntPtr process_handle
;
79 bool enableRaisingEvents
;
81 ISynchronizeInvoke synchronizingObject
;
82 EventHandler exited_event
;
86 /* Private constructor called from other methods */
87 private Process(IntPtr handle
, int id
) {
88 process_handle
=handle
;
97 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
98 [MonitoringDescription ("Base process priority.")]
99 public int BasePriority
{
105 void StartExitCallbackIfNeeded ()
108 bool start
= (!already_waiting
&& enableRaisingEvents
&& exited_event
!= null);
109 if (start
&& process_handle
!= IntPtr
.Zero
) {
110 WaitOrTimerCallback cb
= new WaitOrTimerCallback (CBOnExit
);
111 ProcessWaitHandle h
= new ProcessWaitHandle (process_handle
);
112 ThreadPool
.RegisterWaitForSingleObject (h
, cb
, this, -1, true);
113 already_waiting
= true;
118 [DefaultValue (false), Browsable (false)]
119 [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
120 public bool EnableRaisingEvents
{
122 return enableRaisingEvents
;
125 bool prev
= enableRaisingEvents
;
126 enableRaisingEvents
= value;
127 if (enableRaisingEvents
&& !prev
)
128 StartExitCallbackIfNeeded ();
133 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
134 private extern static int ExitCode_internal(IntPtr handle
);
136 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
137 [MonitoringDescription ("The exit code of the process.")]
138 public int ExitCode
{
140 if (process_handle
== IntPtr
.Zero
)
141 throw new InvalidOperationException ("Process has not been started.");
143 int code
= ExitCode_internal (process_handle
);
145 throw new InvalidOperationException ("The process must exit before " +
146 "getting the requested information.");
152 /* Returns the process start time in Windows file
153 * times (ticks from DateTime(1/1/1601 00:00 GMT))
155 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
156 private extern static long ExitTime_internal(IntPtr handle
);
158 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
159 [MonitoringDescription ("The exit time of the process.")]
160 public DateTime ExitTime
{
162 if (process_handle
== IntPtr
.Zero
)
163 throw new InvalidOperationException ("Process has not been started.");
166 throw new InvalidOperationException ("The process must exit before " +
167 "getting the requested information.");
169 return(DateTime
.FromFileTime(ExitTime_internal(process_handle
)));
173 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
174 [MonitoringDescription ("Handle for this process.")]
175 public IntPtr Handle
{
177 return(process_handle
);
182 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
183 [MonitoringDescription ("Handles for this process.")]
184 public int HandleCount
{
190 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
191 [MonitoringDescription ("Determines if the process is still running.")]
192 public bool HasExited
{
194 if (process_handle
== IntPtr
.Zero
)
195 throw new InvalidOperationException ("Process has not been started.");
197 int exitcode
= ExitCode_internal (process_handle
);
208 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
209 [MonitoringDescription ("Process identifier.")]
213 throw new InvalidOperationException ("Process ID has not been set.");
220 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
221 [MonitoringDescription ("The name of the computer running the process.")]
222 public string MachineName
{
228 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
229 [MonitoringDescription ("The main module of the process.")]
230 public ProcessModule MainModule
{
232 return(this.Modules
[0]);
237 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
238 [MonitoringDescription ("The handle of the main window of the process.")]
239 public IntPtr MainWindowHandle
{
246 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
247 [MonitoringDescription ("The title of the main window of the process.")]
248 public string MainWindowTitle
{
254 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
255 private extern static bool GetWorkingSet_internal(IntPtr handle
, out int min
, out int max
);
256 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
257 private extern static bool SetWorkingSet_internal(IntPtr handle
, int min
, int max
, bool use_min
);
259 /* LAMESPEC: why is this an IntPtr not a plain int? */
260 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
261 [MonitoringDescription ("The maximum working set for this process.")]
262 public IntPtr MaxWorkingSet
{
265 throw new InvalidOperationException(
266 "The process " + ProcessName
+
267 " (ID " + Id
+ ") has exited");
271 bool ok
=GetWorkingSet_internal(process_handle
, out min
, out max
);
273 throw new Win32Exception();
280 throw new InvalidOperationException("The process " + ProcessName
+ " (ID " + Id
+ ") has exited");
283 bool ok
=SetWorkingSet_internal(process_handle
, 0, value.ToInt32(), false);
285 throw new Win32Exception();
290 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
291 [MonitoringDescription ("The minimum working set for this process.")]
292 public IntPtr MinWorkingSet
{
295 throw new InvalidOperationException(
296 "The process " + ProcessName
+
297 " (ID " + Id
+ ") has exited");
301 bool ok
= GetWorkingSet_internal (process_handle
, out min
, out max
);
303 throw new Win32Exception();
304 return ((IntPtr
) min
);
308 throw new InvalidOperationException(
309 "The process " + ProcessName
+
310 " (ID " + Id
+ ") has exited");
312 bool ok
= SetWorkingSet_internal (process_handle
, value.ToInt32(), 0, true);
314 throw new Win32Exception();
318 /* Returns the list of process modules. The main module is
321 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
322 private extern ProcessModule
[] GetModules_internal(IntPtr handle
);
324 private ProcessModuleCollection module_collection
;
326 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
327 [MonitoringDescription ("The modules that are loaded as part of this process.")]
328 public ProcessModuleCollection Modules
{
330 if (module_collection
== null)
331 module_collection
= new ProcessModuleCollection(
332 GetModules_internal (process_handle
));
333 return(module_collection
);
337 /* data type is from the MonoProcessData enum in mono-proclib.h in the runtime */
338 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
339 private extern static long GetProcessData (int pid
, int data_type
, out int error
);
343 [Obsolete ("Use NonpagedSystemMemorySize64")]
345 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
346 [MonitoringDescription ("The number of bytes that are not pageable.")]
347 public int NonpagedSystemMemorySize
{
355 [Obsolete ("Use PagedMemorySize64")]
357 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
358 [MonitoringDescription ("The number of bytes that are paged.")]
359 public int PagedMemorySize
{
367 [Obsolete ("Use PagedSystemMemorySize64")]
369 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
370 [MonitoringDescription ("The amount of paged system memory in bytes.")]
371 public int PagedSystemMemorySize
{
379 [Obsolete ("Use PeakPagedMemorySize64")]
381 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
382 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
383 public int PeakPagedMemorySize
{
390 [Obsolete ("Use PeakVirtualMemorySize64")]
392 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
393 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
394 public int PeakVirtualMemorySize
{
397 return (int)GetProcessData (pid
, 8, out error
);
402 [Obsolete ("Use PeakWorkingSet64")]
404 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
405 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
406 public int PeakWorkingSet
{
409 return (int)GetProcessData (pid
, 5, out error
);
415 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
416 [MonitoringDescription ("The number of bytes that are not pageable.")]
418 public long NonpagedSystemMemorySize64
{
425 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
426 [MonitoringDescription ("The number of bytes that are paged.")]
428 public long PagedMemorySize64
{
435 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
436 [MonitoringDescription ("The amount of paged system memory in bytes.")]
438 public long PagedSystemMemorySize64
{
445 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
446 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
448 public long PeakPagedMemorySize64
{
454 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
455 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
457 public long PeakVirtualMemorySize64
{
460 return GetProcessData (pid
, 8, out error
);
464 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
465 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
467 public long PeakWorkingSet64
{
470 return GetProcessData (pid
, 5, out error
);
476 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
477 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
478 public bool PriorityBoostEnabled
{
486 [MonoLimitation ("Under Unix, only root is allowed to raise the priority.")]
487 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
488 [MonitoringDescription ("The relative process priority.")]
489 public ProcessPriorityClass PriorityClass
{
491 if (process_handle
== IntPtr
.Zero
)
492 throw new InvalidOperationException ("Process has not been started.");
495 int prio
= GetPriorityClass (process_handle
, out error
);
497 throw new Win32Exception (error
);
498 return (ProcessPriorityClass
) prio
;
501 if (!Enum
.IsDefined (typeof (ProcessPriorityClass
), value))
502 throw new InvalidEnumArgumentException (
503 "value", (int) value,
504 typeof (ProcessPriorityClass
));
506 if (process_handle
== IntPtr
.Zero
)
507 throw new InvalidOperationException ("Process has not been started.");
510 if (!SetPriorityClass (process_handle
, (int) value, out error
))
511 throw new Win32Exception (error
);
515 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
516 static extern int GetPriorityClass (IntPtr handle
, out int error
);
518 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
519 static extern bool SetPriorityClass (IntPtr handle
, int priority
, out int error
);
521 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
522 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
524 [Obsolete ("Use PrivateMemorySize64")]
526 public int PrivateMemorySize
{
529 return (int)GetProcessData (pid
, 6, out error
);
534 [MonoNotSupported ("")]
535 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
536 [MonitoringDescription ("The session ID for this process.")]
537 public int SessionId
{
538 get { throw new NotImplementedException (); }
542 /* the meaning of type is as follows: 0: user, 1: system, 2: total */
543 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
544 private extern static long Times (IntPtr handle
, int type
);
546 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
547 [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
548 public TimeSpan PrivilegedProcessorTime
{
550 return new TimeSpan (Times (process_handle
, 1));
554 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
555 private extern static string ProcessName_internal(IntPtr handle
);
557 private string process_name
=null;
559 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
560 [MonitoringDescription ("The name of this process.")]
561 public string ProcessName
{
563 if(process_name
==null) {
565 if (process_handle
== IntPtr
.Zero
)
566 throw new InvalidOperationException ("No process is associated with this object.");
568 process_name
=ProcessName_internal(process_handle
);
569 /* If process_name is _still_
570 * null, assume the process
573 if (process_name
== null)
574 throw new InvalidOperationException ("Process has exited, so the requested information is not available.");
576 /* Strip the suffix (if it
577 * exists) simplistically
578 * instead of removing any
579 * trailing \.???, so we dont
580 * get stupid results on sane
583 if(process_name
.EndsWith(".exe") ||
584 process_name
.EndsWith(".bat") ||
585 process_name
.EndsWith(".com")) {
586 process_name
=process_name
.Substring(0, process_name
.Length
-4);
589 return(process_name
);
594 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
595 [MonitoringDescription ("Allowed processor that can be used by this process.")]
596 public IntPtr ProcessorAffinity
{
605 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
606 [MonitoringDescription ("Is this process responsive.")]
607 public bool Responding
{
613 private StreamReader error_stream
=null;
615 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
616 [MonitoringDescription ("The standard error stream of this process.")]
617 public StreamReader StandardError
{
619 if (error_stream
== null)
620 throw new InvalidOperationException("Standard error has not been redirected");
623 if ((async_mode
& AsyncModes
.AsyncError
) != 0)
624 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
626 async_mode
|= AsyncModes
.SyncError
;
629 return(error_stream
);
633 private StreamWriter input_stream
=null;
635 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
636 [MonitoringDescription ("The standard input stream of this process.")]
637 public StreamWriter StandardInput
{
639 if (input_stream
== null)
640 throw new InvalidOperationException("Standard input has not been redirected");
642 return(input_stream
);
646 private StreamReader output_stream
=null;
648 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
649 [MonitoringDescription ("The standard output stream of this process.")]
650 public StreamReader StandardOutput
{
652 if (output_stream
== null)
653 throw new InvalidOperationException("Standard output has not been redirected");
656 if ((async_mode
& AsyncModes
.AsyncOutput
) != 0)
657 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
659 async_mode
|= AsyncModes
.SyncOutput
;
662 return(output_stream
);
666 private ProcessStartInfo start_info
=null;
668 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Content
), Browsable (false)]
669 [MonitoringDescription ("Information for the start of this process.")]
670 public ProcessStartInfo StartInfo
{
672 if (start_info
== null)
673 start_info
= new ProcessStartInfo();
678 throw new ArgumentNullException("value");
683 /* Returns the process start time in Windows file
684 * times (ticks from DateTime(1/1/1601 00:00 GMT))
686 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
687 private extern static long StartTime_internal(IntPtr handle
);
689 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
690 [MonitoringDescription ("The time this process started.")]
691 public DateTime StartTime
{
693 return(DateTime
.FromFileTime(StartTime_internal(process_handle
)));
697 [DefaultValue (null), Browsable (false)]
698 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
699 public ISynchronizeInvoke SynchronizingObject
{
700 get { return synchronizingObject; }
701 set { synchronizingObject = value; }
705 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
706 [MonitoringDescription ("The number of threads of this process.")]
707 public ProcessThreadCollection Threads
{
709 return ProcessThreadCollection
.GetEmpty ();
713 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
714 [MonitoringDescription ("The total CPU time spent for this process.")]
715 public TimeSpan TotalProcessorTime
{
717 return new TimeSpan (Times (process_handle
, 2));
721 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
722 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
723 public TimeSpan UserProcessorTime
{
725 return new TimeSpan (Times (process_handle
, 0));
730 [Obsolete ("Use VirtualMemorySize64")]
732 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
733 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
734 public int VirtualMemorySize
{
737 return (int)GetProcessData (pid
, 7, out error
);
742 [Obsolete ("Use WorkingSet64")]
744 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
745 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
746 public int WorkingSet
{
749 return (int)GetProcessData (pid
, 4, out error
);
754 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
755 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
757 public long PrivateMemorySize64
{
760 return GetProcessData (pid
, 6, out error
);
764 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
765 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
767 public long VirtualMemorySize64
{
770 return GetProcessData (pid
, 7, out error
);
774 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
775 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
777 public long WorkingSet64
{
780 return GetProcessData (pid
, 4, out error
);
790 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
791 extern static bool Kill_internal (IntPtr handle
, int signo
);
793 /* int kill -> 1 KILL, 2 CloseMainWindow */
794 bool Close (int signo
)
796 if (process_handle
== IntPtr
.Zero
)
797 throw new SystemException ("No process to kill.");
799 int exitcode
= ExitCode_internal (process_handle
);
801 throw new InvalidOperationException ("The process already finished.");
803 return Kill_internal (process_handle
, signo
);
806 public bool CloseMainWindow ()
812 public static void EnterDebugMode() {
815 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
816 private extern static IntPtr
GetProcess_internal(int pid
);
818 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
819 private extern static int GetPid_internal();
821 public static Process
GetCurrentProcess()
823 int pid
= GetPid_internal();
824 IntPtr proc
= GetProcess_internal(pid
);
826 if (proc
== IntPtr
.Zero
)
827 throw new SystemException("Can't find current process");
829 return (new Process (proc
, pid
));
832 public static Process
GetProcessById(int processId
)
834 IntPtr proc
= GetProcess_internal(processId
);
836 if (proc
== IntPtr
.Zero
)
837 throw new ArgumentException ("Can't find process with ID " + processId
.ToString ());
839 return (new Process (proc
, processId
));
842 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
843 public static Process
GetProcessById(int processId
, string machineName
) {
844 if (machineName
== null)
845 throw new ArgumentNullException ("machineName");
847 if (!IsLocalMachine (machineName
))
848 throw new NotImplementedException ();
850 return GetProcessById (processId
);
853 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
854 private extern static int[] GetProcesses_internal();
856 public static Process
[] GetProcesses()
858 int [] pids
= GetProcesses_internal ();
859 ArrayList proclist
= new ArrayList ();
862 return new Process
[0];
864 for (int i
= 0; i
< pids
.Length
; i
++) {
866 proclist
.Add (GetProcessById (pids
[i
]));
867 } catch (SystemException
) {
868 /* The process might exit
870 * GetProcesses_internal and
876 return ((Process
[]) proclist
.ToArray (typeof (Process
)));
879 [MonoTODO ("There is no support for retrieving process information from a remote machine")]
880 public static Process
[] GetProcesses(string machineName
) {
881 if (machineName
== null)
882 throw new ArgumentNullException ("machineName");
884 if (!IsLocalMachine (machineName
))
885 throw new NotImplementedException ();
887 return GetProcesses ();
890 public static Process
[] GetProcessesByName(string processName
)
892 Process
[] procs
= GetProcesses();
893 ArrayList proclist
= new ArrayList();
895 for (int i
= 0; i
< procs
.Length
; i
++) {
897 if (String
.Compare (processName
,
898 procs
[i
].ProcessName
,
900 proclist
.Add (procs
[i
]);
904 return ((Process
[]) proclist
.ToArray (typeof(Process
)));
908 public static Process
[] GetProcessesByName(string processName
, string machineName
) {
909 throw new NotImplementedException();
918 public static void LeaveDebugMode() {
921 public void Refresh ()
923 // FIXME: should refresh any cached data we might have about
924 // the process (currently we have none).
927 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
928 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo
,
929 ref ProcInfo proc_info
);
931 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
932 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo
,
936 ref ProcInfo proc_info
);
938 private static bool Start_shell (ProcessStartInfo startInfo
,
941 ProcInfo proc_info
=new ProcInfo();
944 if (startInfo
.RedirectStandardInput
||
945 startInfo
.RedirectStandardOutput
||
946 startInfo
.RedirectStandardError
) {
947 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
950 if (startInfo
.HaveEnvVars
)
951 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
953 FillUserInfo (startInfo
, ref proc_info
);
955 ret
= ShellExecuteEx_internal (startInfo
,
958 if (proc_info
.Password
!= IntPtr
.Zero
)
959 Marshal
.FreeBSTR (proc_info
.Password
);
960 proc_info
.Password
= IntPtr
.Zero
;
963 throw new Win32Exception (-proc_info
.pid
);
966 process
.process_handle
= proc_info
.process_handle
;
967 process
.pid
= proc_info
.pid
;
969 process
.StartExitCallbackIfNeeded ();
974 private static bool Start_noshell (ProcessStartInfo startInfo
,
977 ProcInfo proc_info
=new ProcInfo();
978 IntPtr stdin_rd
= IntPtr
.Zero
, stdin_wr
= IntPtr
.Zero
;
984 if (startInfo
.HaveEnvVars
) {
985 string [] strs
= new string [startInfo
.EnvironmentVariables
.Count
];
986 startInfo
.EnvironmentVariables
.Keys
.CopyTo (strs
, 0);
987 proc_info
.envKeys
= strs
;
989 strs
= new string [startInfo
.EnvironmentVariables
.Count
];
990 startInfo
.EnvironmentVariables
.Values
.CopyTo (strs
, 0);
991 proc_info
.envValues
= strs
;
994 if (startInfo
.RedirectStandardInput
== true) {
996 int DUPLICATE_SAME_ACCESS
= 0x00000002;
999 ret
= MonoIO
.CreatePipe (out stdin_rd
,
1002 ret
= MonoIO
.DuplicateHandle (Process
.GetCurrentProcess ().Handle
, stdin_wr_tmp
,
1003 Process
.GetCurrentProcess ().Handle
, out stdin_wr
, 0, 0, DUPLICATE_SAME_ACCESS
);
1004 MonoIO
.Close (stdin_wr_tmp
, out error
);
1009 ret
= MonoIO
.CreatePipe (out stdin_rd
,
1013 throw new IOException ("Error creating standard input pipe");
1016 stdin_rd
= MonoIO
.ConsoleInput
;
1017 /* This is required to stop the
1018 * &$*£ing stupid compiler moaning
1019 * that stdin_wr is unassigned, below.
1021 stdin_wr
= (IntPtr
)0;
1024 if (startInfo
.RedirectStandardOutput
== true) {
1025 IntPtr out_rd
= IntPtr
.Zero
;
1028 int DUPLICATE_SAME_ACCESS
= 0x00000002;
1030 ret
= MonoIO
.CreatePipe (out out_rd_tmp
,
1033 MonoIO
.DuplicateHandle (Process
.GetCurrentProcess ().Handle
, out_rd_tmp
,
1034 Process
.GetCurrentProcess ().Handle
, out out_rd
, 0, 0, DUPLICATE_SAME_ACCESS
);
1035 MonoIO
.Close (out_rd_tmp
, out error
);
1039 ret
= MonoIO
.CreatePipe (out out_rd
,
1043 process
.stdout_rd
= out_rd
;
1045 if (startInfo
.RedirectStandardInput
== true) {
1046 MonoIO
.Close (stdin_rd
, out error
);
1047 MonoIO
.Close (stdin_wr
, out error
);
1050 throw new IOException ("Error creating standard output pipe");
1053 process
.stdout_rd
= (IntPtr
)0;
1054 stdout_wr
= MonoIO
.ConsoleOutput
;
1057 if (startInfo
.RedirectStandardError
== true) {
1058 IntPtr err_rd
= IntPtr
.Zero
;
1061 int DUPLICATE_SAME_ACCESS
= 0x00000002;
1063 ret
= MonoIO
.CreatePipe (out err_rd_tmp
,
1066 MonoIO
.DuplicateHandle (Process
.GetCurrentProcess ().Handle
, err_rd_tmp
,
1067 Process
.GetCurrentProcess ().Handle
, out err_rd
, 0, 0, DUPLICATE_SAME_ACCESS
);
1068 MonoIO
.Close (err_rd_tmp
, out error
);
1072 ret
= MonoIO
.CreatePipe (out err_rd
,
1076 process
.stderr_rd
= err_rd
;
1078 if (startInfo
.RedirectStandardInput
== true) {
1079 MonoIO
.Close (stdin_rd
, out error
);
1080 MonoIO
.Close (stdin_wr
, out error
);
1082 if (startInfo
.RedirectStandardOutput
== true) {
1083 MonoIO
.Close (process
.stdout_rd
, out error
);
1084 MonoIO
.Close (stdout_wr
, out error
);
1087 throw new IOException ("Error creating standard error pipe");
1090 process
.stderr_rd
= (IntPtr
)0;
1091 stderr_wr
= MonoIO
.ConsoleError
;
1094 FillUserInfo (startInfo
, ref proc_info
);
1096 ret
= CreateProcess_internal (startInfo
,
1097 stdin_rd
, stdout_wr
, stderr_wr
,
1100 if (proc_info
.Password
!= IntPtr
.Zero
)
1101 Marshal
.FreeBSTR (proc_info
.Password
);
1102 proc_info
.Password
= IntPtr
.Zero
;
1105 if (startInfo
.RedirectStandardInput
== true) {
1106 MonoIO
.Close (stdin_rd
, out error
);
1107 MonoIO
.Close (stdin_wr
, out error
);
1110 if (startInfo
.RedirectStandardOutput
== true) {
1111 MonoIO
.Close (process
.stdout_rd
, out error
);
1112 MonoIO
.Close (stdout_wr
, out error
);
1115 if (startInfo
.RedirectStandardError
== true) {
1116 MonoIO
.Close (process
.stderr_rd
, out error
);
1117 MonoIO
.Close (stderr_wr
, out error
);
1120 throw new Win32Exception (-proc_info
.pid
,
1121 "ApplicationName='" + startInfo
.FileName
+
1122 "', CommandLine='" + startInfo
.Arguments
+
1123 "', CurrentDirectory='" + startInfo
.WorkingDirectory
+ "'");
1126 process
.process_handle
= proc_info
.process_handle
;
1127 process
.pid
= proc_info
.pid
;
1129 if (startInfo
.RedirectStandardInput
== true) {
1130 MonoIO
.Close (stdin_rd
, out error
);
1131 process
.input_stream
= new StreamWriter (new MonoSyncFileStream (stdin_wr
, FileAccess
.Write
, true, 8192), Console
.Out
.Encoding
);
1132 process
.input_stream
.AutoFlush
= true;
1136 Encoding stdoutEncoding
= startInfo
.StandardOutputEncoding
?? Console
.Out
.Encoding
;
1137 Encoding stderrEncoding
= startInfo
.StandardErrorEncoding
?? Console
.Out
.Encoding
;
1139 Encoding stdoutEncoding
= Console
.Out
.Encoding
;
1140 Encoding stderrEncoding
= stdoutEncoding
;
1143 if (startInfo
.RedirectStandardOutput
== true) {
1144 MonoIO
.Close (stdout_wr
, out error
);
1145 process
.output_stream
= new StreamReader (new MonoSyncFileStream (process
.stdout_rd
, FileAccess
.Read
, true, 8192), stdoutEncoding
, true, 8192);
1148 if (startInfo
.RedirectStandardError
== true) {
1149 MonoIO
.Close (stderr_wr
, out error
);
1150 process
.error_stream
= new StreamReader (new MonoSyncFileStream (process
.stderr_rd
, FileAccess
.Read
, true, 8192), stderrEncoding
, true, 8192);
1153 process
.StartExitCallbackIfNeeded ();
1158 // Note that ProcInfo.Password must be freed.
1159 private static void FillUserInfo (ProcessStartInfo startInfo
, ref ProcInfo proc_info
)
1162 if (startInfo
.UserName
!= null) {
1163 proc_info
.UserName
= startInfo
.UserName
;
1164 proc_info
.Domain
= startInfo
.Domain
;
1165 if (startInfo
.Password
!= null)
1166 proc_info
.Password
= Marshal
.SecureStringToBSTR (startInfo
.Password
);
1168 proc_info
.Password
= IntPtr
.Zero
;
1169 proc_info
.LoadUserProfile
= startInfo
.LoadUserProfile
;
1174 private static bool Start_common (ProcessStartInfo startInfo
,
1177 if (startInfo
.FileName
== null || startInfo
.FileName
.Length
== 0)
1178 throw new InvalidOperationException("File name has not been set");
1181 if (startInfo
.StandardErrorEncoding
!= null && !startInfo
.RedirectStandardError
)
1182 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1183 if (startInfo
.StandardOutputEncoding
!= null && !startInfo
.RedirectStandardOutput
)
1184 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1187 if (startInfo
.UseShellExecute
) {
1189 if (!String
.IsNullOrEmpty (startInfo
.UserName
))
1190 throw new InvalidOperationException ("UserShellExecute must be false if an explicit UserName is specified when starting a process");
1192 return (Start_shell (startInfo
, process
));
1194 return (Start_noshell (startInfo
, process
));
1198 public bool Start ()
1200 if (process_handle
!= IntPtr
.Zero
) {
1201 Process_free_internal (process_handle
);
1202 process_handle
= IntPtr
.Zero
;
1204 return Start_common(start_info
, this);
1207 public static Process
Start (ProcessStartInfo startInfo
)
1209 if (startInfo
== null)
1210 throw new ArgumentNullException ("startInfo");
1212 Process process
=new Process();
1213 process
.StartInfo
= startInfo
;
1214 if (Start_common(startInfo
, process
))
1219 public static Process
Start (string fileName
)
1221 return Start (new ProcessStartInfo (fileName
));
1224 public static Process
Start(string fileName
, string arguments
)
1226 return Start (new ProcessStartInfo (fileName
, arguments
));
1230 public static Process
Start(string fileName
, string username
, SecureString password
, string domain
) {
1231 return Start(fileName
, null, username
, password
, domain
);
1234 public static Process
Start(string fileName
, string arguments
, string username
, SecureString password
, string domain
) {
1235 ProcessStartInfo psi
= new ProcessStartInfo(fileName
, arguments
);
1236 psi
.UserName
= username
;
1237 psi
.Password
= password
;
1238 psi
.Domain
= domain
;
1239 psi
.UseShellExecute
= false;
1244 public override string ToString()
1246 return(base.ToString() + " (" + this.ProcessName
+ ")");
1249 /* Waits up to ms milliseconds for process 'handle' to
1250 * exit. ms can be <0 to mean wait forever.
1252 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1253 private extern bool WaitForExit_internal(IntPtr handle
, int ms
);
1255 public void WaitForExit ()
1260 public bool WaitForExit(int milliseconds
) {
1261 int ms
= milliseconds
;
1262 if (ms
== int.MaxValue
)
1266 DateTime start
= DateTime
.UtcNow
;
1267 if (async_output
!= null && !async_output
.IsCompleted
) {
1268 if (false == async_output
.WaitHandle
.WaitOne (ms
, false))
1269 return false; // Timed out
1272 DateTime now
= DateTime
.UtcNow
;
1273 ms
-= (int) (now
- start
).TotalMilliseconds
;
1280 if (async_error
!= null && !async_error
.IsCompleted
) {
1281 if (false == async_error
.WaitHandle
.WaitOne (ms
, false))
1282 return false; // Timed out
1285 ms
-= (int) (DateTime
.UtcNow
- start
).TotalMilliseconds
;
1291 return WaitForExit_internal (process_handle
, ms
);
1294 /* Waits up to ms milliseconds for process 'handle' to
1295 * wait for input. ms can be <0 to mean wait forever.
1297 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1298 private extern bool WaitForInputIdle_internal(IntPtr handle
, int ms
);
1300 // The internal call is only implemented properly on Windows.
1302 public bool WaitForInputIdle() {
1303 return WaitForInputIdle (-1);
1306 // The internal call is only implemented properly on Windows.
1308 public bool WaitForInputIdle(int milliseconds
) {
1309 return WaitForInputIdle_internal (process_handle
, milliseconds
);
1312 private static bool IsLocalMachine (string machineName
)
1314 if (machineName
== "." || machineName
.Length
== 0)
1317 return (string.Compare (machineName
, Environment
.MachineName
, true) == 0);
1322 [MonitoringDescription ("Raised when it receives output data")]
1323 public event DataReceivedEventHandler OutputDataReceived
;
1325 [MonitoringDescription ("Raised when it receives error data")]
1326 public event DataReceivedEventHandler ErrorDataReceived
;
1328 void OnOutputDataReceived (string str
)
1330 if (OutputDataReceived
!= null)
1331 OutputDataReceived (this, new DataReceivedEventArgs (str
));
1334 void OnErrorDataReceived (string str
)
1336 if (ErrorDataReceived
!= null)
1337 ErrorDataReceived (this, new DataReceivedEventArgs (str
));
1345 AsyncOutput
= 1 << 2,
1349 [StructLayout (LayoutKind
.Sequential
)]
1350 sealed class ProcessAsyncReader
1353 The following fields match those of SocketAsyncResult.
1354 This is so that changes needed in the runtime to handle
1355 asynchronous reads are trivial
1356 Keep this in sync with SocketAsyncResult in
1357 ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
1358 in metadata/socket-io.h.
1360 /* DON'T shuffle fields around. DON'T remove fields */
1362 public IntPtr handle
;
1363 public object state
;
1364 public AsyncCallback callback
;
1365 public ManualResetEvent wait_handle
;
1367 public Exception delayedException
;
1369 public object EndPoint
;
1370 byte [] buffer
= new byte [4196];
1373 public int SockFlags
;
1375 public object AcceptSocket
;
1376 public object[] Addresses
;
1378 public object Buffers
; // Reserve this slot in older profiles
1379 public bool ReuseSocket
; // Disconnect
1380 public object acc_socket
;
1382 public bool completed_sync
;
1384 bool err_out
; // true -> stdout, false -> stderr
1386 public int operation
= 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1388 public int EndCalled
;
1390 // These fields are not in SocketAsyncResult
1393 StringBuilder sb
= new StringBuilder ();
1394 public AsyncReadHandler ReadHandler
;
1396 public ProcessAsyncReader (Process process
, IntPtr handle
, bool err_out
)
1398 this.process
= process
;
1399 this.handle
= handle
;
1400 stream
= new FileStream (handle
, FileAccess
.Read
, false);
1401 this.ReadHandler
= new AsyncReadHandler (AddInput
);
1402 this.err_out
= err_out
;
1405 public void AddInput ()
1408 int nread
= stream
.Read (buffer
, 0, buffer
.Length
);
1411 if (wait_handle
!= null)
1418 sb
.Append (Encoding
.Default
.GetString (buffer
, 0, nread
));
1420 // Just in case the encoding fails...
1421 for (int i
= 0; i
< nread
; i
++) {
1422 sb
.Append ((char) buffer
[i
]);
1427 ReadHandler
.BeginInvoke (null, this);
1435 process
.OnOutputDataReceived (null);
1437 process
.OnErrorDataReceived (null);
1441 void Flush (bool last
)
1443 if (sb
.Length
== 0 ||
1444 (err_out
&& process
.output_canceled
) ||
1445 (!err_out
&& process
.error_canceled
))
1448 string total
= sb
.ToString ();
1450 string [] strs
= total
.Split ('\n');
1451 int len
= strs
.Length
;
1455 for (int i
= 0; i
< len
- 1; i
++) {
1457 process
.OnOutputDataReceived (strs
[i
]);
1459 process
.OnErrorDataReceived (strs
[i
]);
1462 string end
= strs
[len
- 1];
1463 if (last
|| (len
== 1 && end
== "")) {
1465 process
.OnOutputDataReceived (end
);
1467 process
.OnErrorDataReceived (end
);
1474 public bool IsCompleted
{
1475 get { return completed; }
1478 public WaitHandle WaitHandle
{
1481 if (wait_handle
== null)
1482 wait_handle
= new ManualResetEvent (completed
);
1488 public void Close () {
1493 AsyncModes async_mode
;
1494 bool output_canceled
;
1495 bool error_canceled
;
1496 ProcessAsyncReader async_output
;
1497 ProcessAsyncReader async_error
;
1498 delegate void AsyncReadHandler ();
1500 [ComVisibleAttribute(false)]
1501 public void BeginOutputReadLine ()
1503 if (process_handle
== IntPtr
.Zero
|| output_stream
== null || StartInfo
.RedirectStandardOutput
== false)
1504 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1506 if ((async_mode
& AsyncModes
.SyncOutput
) != 0)
1507 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1509 async_mode
|= AsyncModes
.AsyncOutput
;
1510 output_canceled
= false;
1511 if (async_output
== null) {
1512 async_output
= new ProcessAsyncReader (this, stdout_rd
, true);
1513 async_output
.ReadHandler
.BeginInvoke (null, async_output
);
1517 [ComVisibleAttribute(false)]
1518 public void CancelOutputRead ()
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_output
== null)
1527 throw new InvalidOperationException ("No async operation in progress.");
1529 output_canceled
= true;
1532 [ComVisibleAttribute(false)]
1533 public void BeginErrorReadLine ()
1535 if (process_handle
== IntPtr
.Zero
|| error_stream
== null || StartInfo
.RedirectStandardError
== false)
1536 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1538 if ((async_mode
& AsyncModes
.SyncError
) != 0)
1539 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1541 async_mode
|= AsyncModes
.AsyncError
;
1542 error_canceled
= false;
1543 if (async_error
== null) {
1544 async_error
= new ProcessAsyncReader (this, stderr_rd
, false);
1545 async_error
.ReadHandler
.BeginInvoke (null, async_error
);
1549 [ComVisibleAttribute(false)]
1550 public void CancelErrorRead ()
1552 if (process_handle
== IntPtr
.Zero
|| output_stream
== null || StartInfo
.RedirectStandardOutput
== false)
1553 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1555 if ((async_mode
& AsyncModes
.SyncOutput
) != 0)
1556 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1558 if (async_error
== null)
1559 throw new InvalidOperationException ("No async operation in progress.");
1561 error_canceled
= true;
1565 [Category ("Behavior")]
1566 [MonitoringDescription ("Raised when this process exits.")]
1567 public event EventHandler Exited
{
1569 if (process_handle
!= IntPtr
.Zero
&& HasExited
) {
1570 value.BeginInvoke (null, null, null, null);
1572 exited_event
= (EventHandler
) Delegate
.Combine (exited_event
, value);
1573 if (exited_event
!= null)
1574 StartExitCallbackIfNeeded ();
1578 exited_event
= (EventHandler
) Delegate
.Remove (exited_event
, value);
1582 // Closes the system process handle
1583 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1584 private extern void Process_free_internal(IntPtr handle
);
1586 private bool disposed
= false;
1588 protected override void Dispose(bool disposing
) {
1589 // Check to see if Dispose has already been called.
1590 if(this.disposed
== false) {
1592 // If this is a call to Dispose,
1593 // dispose all managed resources.
1597 /* These have open FileStreams on the pipes we are about to close */
1598 if (async_output
!= null)
1599 async_output
.Close ();
1600 if (async_error
!= null)
1601 async_error
.Close ();
1605 // Release unmanaged resources
1608 if(process_handle
!=IntPtr
.Zero
) {
1609 Process_free_internal(process_handle
);
1610 process_handle
=IntPtr
.Zero
;
1613 if (input_stream
!= null) {
1614 input_stream
.Close();
1615 input_stream
= null;
1618 if (output_stream
!= null) {
1619 output_stream
.Close();
1620 output_stream
= null;
1623 if (error_stream
!= null) {
1624 error_stream
.Close();
1625 error_stream
= null;
1629 base.Dispose (disposing
);
1637 static void CBOnExit (object state
, bool unused
)
1639 Process p
= (Process
) state
;
1643 protected void OnExited()
1645 if (exited_event
== null)
1648 if (synchronizingObject
== null) {
1649 foreach (EventHandler d
in exited_event
.GetInvocationList ()) {
1651 d (this, EventArgs
.Empty
);
1657 object [] args
= new object [] {this, EventArgs.Empty}
;
1658 synchronizingObject
.BeginInvoke (exited_event
, args
);
1661 static bool IsWindows
1665 PlatformID platform
= Environment
.OSVersion
.Platform
;
1666 if (platform
== PlatformID
.Win32S
||
1667 platform
== PlatformID
.Win32Windows
||
1668 platform
== PlatformID
.Win32NT
||
1669 platform
== PlatformID
.WinCE
) {
1676 class ProcessWaitHandle
: WaitHandle
1678 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
1679 private extern static IntPtr
ProcessHandle_duplicate (IntPtr handle
);
1681 public ProcessWaitHandle (IntPtr handle
)
1683 // Need to keep a reference to this handle,
1684 // in case the Process object is collected
1685 Handle
= ProcessHandle_duplicate (handle
);
1687 // When the wait handle is disposed, the duplicated handle will be
1688 // closed, so no need to override dispose (bug #464628).