2010-04-06 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System / System.Diagnostics / Process.cs
blob9fe5d909b6f3dfefc1e14a6a309c7ece22084398
1 //
2 // System.Diagnostics.Process.cs
3 //
4 // Authors:
5 // Dick Porter (dick@ximian.com)
6 // Andreas Nahr (ClassDevelopment@A-SoftTech.com)
7 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 //
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:
22 //
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 //
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.
35 using System.IO;
36 using System.Text;
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 #if NET_2_0
53 [MonitoringDescription ("Represents a system process")]
54 #endif
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.
68 public int tid;
69 public string [] envKeys;
70 public string [] envValues;
71 public string UserName;
72 public string Domain;
73 public IntPtr Password;
74 public bool LoadUserProfile;
77 IntPtr process_handle;
78 int pid;
79 bool enableRaisingEvents;
80 bool already_waiting;
81 ISynchronizeInvoke synchronizingObject;
82 EventHandler exited_event;
83 IntPtr stdout_rd;
84 IntPtr stderr_rd;
86 /* Private constructor called from other methods */
87 private Process(IntPtr handle, int id) {
88 process_handle=handle;
89 pid=id;
92 public Process ()
96 [MonoTODO]
97 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
98 [MonitoringDescription ("Base process priority.")]
99 public int BasePriority {
100 get {
101 return(0);
105 void StartExitCallbackIfNeeded ()
107 #if !NET_2_1
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;
115 #endif
118 [DefaultValue (false), Browsable (false)]
119 [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
120 public bool EnableRaisingEvents {
121 get {
122 return enableRaisingEvents;
124 set {
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 {
139 get {
140 if (process_handle == IntPtr.Zero)
141 throw new InvalidOperationException ("Process has not been started.");
143 int code = ExitCode_internal (process_handle);
144 if (code == 259)
145 throw new InvalidOperationException ("The process must exit before " +
146 "getting the requested information.");
148 return code;
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 {
161 get {
162 if (process_handle == IntPtr.Zero)
163 throw new InvalidOperationException ("Process has not been started.");
165 if (!HasExited)
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 {
176 get {
177 return(process_handle);
181 [MonoTODO]
182 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
183 [MonitoringDescription ("Handles for this process.")]
184 public int HandleCount {
185 get {
186 return(0);
190 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
191 [MonitoringDescription ("Determines if the process is still running.")]
192 public bool HasExited {
193 get {
194 if (process_handle == IntPtr.Zero)
195 throw new InvalidOperationException ("Process has not been started.");
197 int exitcode = ExitCode_internal (process_handle);
199 if(exitcode==259) {
200 /* STILL_ACTIVE */
201 return(false);
202 } else {
203 return(true);
208 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
209 [MonitoringDescription ("Process identifier.")]
210 public int Id {
211 get {
212 if (pid == 0)
213 throw new InvalidOperationException ("Process ID has not been set.");
215 return(pid);
219 [MonoTODO]
220 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
221 [MonitoringDescription ("The name of the computer running the process.")]
222 public string MachineName {
223 get {
224 return("localhost");
228 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
229 [MonitoringDescription ("The main module of the process.")]
230 public ProcessModule MainModule {
231 get {
232 return(this.Modules[0]);
236 [MonoTODO]
237 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
238 [MonitoringDescription ("The handle of the main window of the process.")]
239 public IntPtr MainWindowHandle {
240 get {
241 return((IntPtr)0);
245 [MonoTODO]
246 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
247 [MonitoringDescription ("The title of the main window of the process.")]
248 public string MainWindowTitle {
249 get {
250 return("null");
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 {
263 get {
264 if(HasExited)
265 throw new InvalidOperationException(
266 "The process " + ProcessName +
267 " (ID " + Id + ") has exited");
269 int min;
270 int max;
271 bool ok=GetWorkingSet_internal(process_handle, out min, out max);
272 if(ok==false) {
273 throw new Win32Exception();
276 return((IntPtr)max);
278 set {
279 if(HasExited) {
280 throw new InvalidOperationException("The process " + ProcessName + " (ID " + Id + ") has exited");
283 bool ok=SetWorkingSet_internal(process_handle, 0, value.ToInt32(), false);
284 if(ok==false) {
285 throw new Win32Exception();
290 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
291 [MonitoringDescription ("The minimum working set for this process.")]
292 public IntPtr MinWorkingSet {
293 get {
294 if(HasExited)
295 throw new InvalidOperationException(
296 "The process " + ProcessName +
297 " (ID " + Id + ") has exited");
299 int min;
300 int max;
301 bool ok= GetWorkingSet_internal (process_handle, out min, out max);
302 if(!ok)
303 throw new Win32Exception();
304 return ((IntPtr) min);
306 set {
307 if(HasExited)
308 throw new InvalidOperationException(
309 "The process " + ProcessName +
310 " (ID " + Id + ") has exited");
312 bool ok = SetWorkingSet_internal (process_handle, value.ToInt32(), 0, true);
313 if (!ok)
314 throw new Win32Exception();
318 /* Returns the list of process modules. The main module is
319 * element 0.
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 {
329 get {
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);
341 [MonoTODO]
342 #if NET_2_0
343 [Obsolete ("Use NonpagedSystemMemorySize64")]
344 #endif
345 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
346 [MonitoringDescription ("The number of bytes that are not pageable.")]
347 public int NonpagedSystemMemorySize {
348 get {
349 return(0);
353 [MonoTODO]
354 #if NET_2_0
355 [Obsolete ("Use PagedMemorySize64")]
356 #endif
357 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
358 [MonitoringDescription ("The number of bytes that are paged.")]
359 public int PagedMemorySize {
360 get {
361 return(0);
365 [MonoTODO]
366 #if NET_2_0
367 [Obsolete ("Use PagedSystemMemorySize64")]
368 #endif
369 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
370 [MonitoringDescription ("The amount of paged system memory in bytes.")]
371 public int PagedSystemMemorySize {
372 get {
373 return(0);
377 [MonoTODO]
378 #if NET_2_0
379 [Obsolete ("Use PeakPagedMemorySize64")]
380 #endif
381 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
382 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
383 public int PeakPagedMemorySize {
384 get {
385 return(0);
389 #if NET_2_0
390 [Obsolete ("Use PeakVirtualMemorySize64")]
391 #endif
392 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
393 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
394 public int PeakVirtualMemorySize {
395 get {
396 int error;
397 return (int)GetProcessData (pid, 8, out error);
401 #if NET_2_0
402 [Obsolete ("Use PeakWorkingSet64")]
403 #endif
404 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
405 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
406 public int PeakWorkingSet {
407 get {
408 int error;
409 return (int)GetProcessData (pid, 5, out error);
413 #if NET_2_0
414 [MonoTODO]
415 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
416 [MonitoringDescription ("The number of bytes that are not pageable.")]
417 [ComVisible (false)]
418 public long NonpagedSystemMemorySize64 {
419 get {
420 return(0);
424 [MonoTODO]
425 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
426 [MonitoringDescription ("The number of bytes that are paged.")]
427 [ComVisible (false)]
428 public long PagedMemorySize64 {
429 get {
430 return(0);
434 [MonoTODO]
435 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
436 [MonitoringDescription ("The amount of paged system memory in bytes.")]
437 [ComVisible (false)]
438 public long PagedSystemMemorySize64 {
439 get {
440 return(0);
444 [MonoTODO]
445 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
446 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
447 [ComVisible (false)]
448 public long PeakPagedMemorySize64 {
449 get {
450 return(0);
454 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
455 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
456 [ComVisible (false)]
457 public long PeakVirtualMemorySize64 {
458 get {
459 int error;
460 return GetProcessData (pid, 8, out error);
464 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
465 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
466 [ComVisible (false)]
467 public long PeakWorkingSet64 {
468 get {
469 int error;
470 return GetProcessData (pid, 5, out error);
473 #endif
475 [MonoTODO]
476 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
477 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
478 public bool PriorityBoostEnabled {
479 get {
480 return(false);
482 set {
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 {
490 get {
491 if (process_handle == IntPtr.Zero)
492 throw new InvalidOperationException ("Process has not been started.");
494 int error;
495 int prio = GetPriorityClass (process_handle, out error);
496 if (prio == 0)
497 throw new Win32Exception (error);
498 return (ProcessPriorityClass) prio;
500 set {
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.");
509 int error;
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.")]
523 #if NET_2_0
524 [Obsolete ("Use PrivateMemorySize64")]
525 #endif
526 public int PrivateMemorySize {
527 get {
528 int error;
529 return (int)GetProcessData (pid, 6, out error);
533 #if NET_2_0
534 [MonoNotSupported ("")]
535 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
536 [MonitoringDescription ("The session ID for this process.")]
537 public int SessionId {
538 get { throw new NotImplementedException (); }
540 #endif
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 {
549 get {
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 {
562 get {
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
571 * has exited
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
581 * systems
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);
593 [MonoTODO]
594 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
595 [MonitoringDescription ("Allowed processor that can be used by this process.")]
596 public IntPtr ProcessorAffinity {
597 get {
598 return((IntPtr)0);
600 set {
604 [MonoTODO]
605 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
606 [MonitoringDescription ("Is this process responsive.")]
607 public bool Responding {
608 get {
609 return(false);
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 {
618 get {
619 if (error_stream == null)
620 throw new InvalidOperationException("Standard error has not been redirected");
622 #if NET_2_0
623 if ((async_mode & AsyncModes.AsyncError) != 0)
624 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
626 async_mode |= AsyncModes.SyncError;
627 #endif
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 {
638 get {
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 {
651 get {
652 if (output_stream == null)
653 throw new InvalidOperationException("Standard output has not been redirected");
655 #if NET_2_0
656 if ((async_mode & AsyncModes.AsyncOutput) != 0)
657 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
659 async_mode |= AsyncModes.SyncOutput;
660 #endif
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 {
671 get {
672 if (start_info == null)
673 start_info = new ProcessStartInfo();
674 return start_info;
676 set {
677 if (value == null)
678 throw new ArgumentNullException("value");
679 start_info = 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 {
692 get {
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; }
704 [MonoTODO]
705 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden), Browsable (false)]
706 [MonitoringDescription ("The number of threads of this process.")]
707 public ProcessThreadCollection Threads {
708 get {
709 return ProcessThreadCollection.GetEmpty ();
713 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
714 [MonitoringDescription ("The total CPU time spent for this process.")]
715 public TimeSpan TotalProcessorTime {
716 get {
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 {
724 get {
725 return new TimeSpan (Times (process_handle, 0));
729 #if NET_2_0
730 [Obsolete ("Use VirtualMemorySize64")]
731 #endif
732 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
733 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
734 public int VirtualMemorySize {
735 get {
736 int error;
737 return (int)GetProcessData (pid, 7, out error);
741 #if NET_2_0
742 [Obsolete ("Use WorkingSet64")]
743 #endif
744 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
745 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
746 public int WorkingSet {
747 get {
748 int error;
749 return (int)GetProcessData (pid, 4, out error);
753 #if NET_2_0
754 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
755 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
756 [ComVisible (false)]
757 public long PrivateMemorySize64 {
758 get {
759 int error;
760 return GetProcessData (pid, 6, out error);
764 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
765 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
766 [ComVisible (false)]
767 public long VirtualMemorySize64 {
768 get {
769 int error;
770 return GetProcessData (pid, 7, out error);
774 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
775 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
776 [ComVisible (false)]
777 public long WorkingSet64 {
778 get {
779 int error;
780 return GetProcessData (pid, 4, out error);
783 #endif
785 public void Close()
787 Dispose (true);
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);
800 if (exitcode != 259)
801 throw new InvalidOperationException ("The process already finished.");
803 return Kill_internal (process_handle, signo);
806 public bool CloseMainWindow ()
808 return Close (2);
811 [MonoTODO]
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 ();
861 if (pids == null)
862 return new Process [0];
864 for (int i = 0; i < pids.Length; i++) {
865 try {
866 proclist.Add (GetProcessById (pids [i]));
867 } catch (SystemException) {
868 /* The process might exit
869 * between
870 * GetProcesses_internal and
871 * GetProcessById
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++) {
896 /* Ignore case */
897 if (String.Compare (processName,
898 procs [i].ProcessName,
899 true) == 0) {
900 proclist.Add (procs [i]);
904 return ((Process[]) proclist.ToArray (typeof(Process)));
907 [MonoTODO]
908 public static Process[] GetProcessesByName(string processName, string machineName) {
909 throw new NotImplementedException();
912 public void Kill ()
914 Close (1);
917 [MonoTODO]
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,
933 IntPtr stdin,
934 IntPtr stdout,
935 IntPtr stderr,
936 ref ProcInfo proc_info);
938 private static bool Start_shell (ProcessStartInfo startInfo,
939 Process process)
941 ProcInfo proc_info=new ProcInfo();
942 bool ret;
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);
954 try {
955 ret = ShellExecuteEx_internal (startInfo,
956 ref proc_info);
957 } finally {
958 if (proc_info.Password != IntPtr.Zero)
959 Marshal.FreeBSTR (proc_info.Password);
960 proc_info.Password = IntPtr.Zero;
962 if (!ret) {
963 throw new Win32Exception (-proc_info.pid);
966 process.process_handle = proc_info.process_handle;
967 process.pid = proc_info.pid;
969 process.StartExitCallbackIfNeeded ();
971 return(ret);
974 private static bool Start_noshell (ProcessStartInfo startInfo,
975 Process process)
977 ProcInfo proc_info=new ProcInfo();
978 IntPtr stdin_rd = IntPtr.Zero, stdin_wr = IntPtr.Zero;
979 IntPtr stdout_wr;
980 IntPtr stderr_wr;
981 bool ret;
982 MonoIOError error;
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) {
995 if (IsWindows) {
996 int DUPLICATE_SAME_ACCESS = 0x00000002;
997 IntPtr stdin_wr_tmp;
999 ret = MonoIO.CreatePipe (out stdin_rd,
1000 out stdin_wr_tmp);
1001 if (ret) {
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);
1007 else
1009 ret = MonoIO.CreatePipe (out stdin_rd,
1010 out stdin_wr);
1012 if (ret == false) {
1013 throw new IOException ("Error creating standard input pipe");
1015 } else {
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;
1026 if (IsWindows) {
1027 IntPtr out_rd_tmp;
1028 int DUPLICATE_SAME_ACCESS = 0x00000002;
1030 ret = MonoIO.CreatePipe (out out_rd_tmp,
1031 out stdout_wr);
1032 if (ret) {
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);
1038 else {
1039 ret = MonoIO.CreatePipe (out out_rd,
1040 out stdout_wr);
1043 process.stdout_rd = out_rd;
1044 if (ret == false) {
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");
1052 } else {
1053 process.stdout_rd = (IntPtr)0;
1054 stdout_wr = MonoIO.ConsoleOutput;
1057 if (startInfo.RedirectStandardError == true) {
1058 IntPtr err_rd = IntPtr.Zero;
1059 if (IsWindows) {
1060 IntPtr err_rd_tmp;
1061 int DUPLICATE_SAME_ACCESS = 0x00000002;
1063 ret = MonoIO.CreatePipe (out err_rd_tmp,
1064 out stderr_wr);
1065 if (ret) {
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);
1071 else {
1072 ret = MonoIO.CreatePipe (out err_rd,
1073 out stderr_wr);
1076 process.stderr_rd = err_rd;
1077 if (ret == false) {
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");
1089 } else {
1090 process.stderr_rd = (IntPtr)0;
1091 stderr_wr = MonoIO.ConsoleError;
1094 FillUserInfo (startInfo, ref proc_info);
1095 try {
1096 ret = CreateProcess_internal (startInfo,
1097 stdin_rd, stdout_wr, stderr_wr,
1098 ref proc_info);
1099 } finally {
1100 if (proc_info.Password != IntPtr.Zero)
1101 Marshal.FreeBSTR (proc_info.Password);
1102 proc_info.Password = IntPtr.Zero;
1104 if (!ret) {
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;
1135 #if NET_2_0
1136 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1137 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1138 #else
1139 Encoding stdoutEncoding = Console.Out.Encoding;
1140 Encoding stderrEncoding = stdoutEncoding;
1141 #endif
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 ();
1155 return(ret);
1158 // Note that ProcInfo.Password must be freed.
1159 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1161 #if NET_2_0
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);
1167 else
1168 proc_info.Password = IntPtr.Zero;
1169 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1171 #endif
1174 private static bool Start_common (ProcessStartInfo startInfo,
1175 Process process)
1177 if (startInfo.FileName == null || startInfo.FileName.Length == 0)
1178 throw new InvalidOperationException("File name has not been set");
1180 #if NET_2_0
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");
1185 #endif
1187 if (startInfo.UseShellExecute) {
1188 #if NET_2_0
1189 if (!String.IsNullOrEmpty (startInfo.UserName))
1190 throw new InvalidOperationException ("UserShellExecute must be false if an explicit UserName is specified when starting a process");
1191 #endif
1192 return (Start_shell (startInfo, process));
1193 } else {
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))
1215 return process;
1216 return null;
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));
1229 #if NET_2_0
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;
1240 return Start(psi);
1242 #endif
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 ()
1257 WaitForExit (-1);
1260 public bool WaitForExit(int milliseconds) {
1261 int ms = milliseconds;
1262 if (ms == int.MaxValue)
1263 ms = -1;
1265 #if NET_2_0
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
1271 if (ms >= 0) {
1272 DateTime now = DateTime.UtcNow;
1273 ms -= (int) (now - start).TotalMilliseconds;
1274 if (ms <= 0)
1275 return false;
1276 start = now;
1280 if (async_error != null && !async_error.IsCompleted) {
1281 if (false == async_error.WaitHandle.WaitOne (ms, false))
1282 return false; // Timed out
1284 if (ms >= 0) {
1285 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1286 if (ms <= 0)
1287 return false;
1290 #endif
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.
1301 [MonoTODO]
1302 public bool WaitForInputIdle() {
1303 return WaitForInputIdle (-1);
1306 // The internal call is only implemented properly on Windows.
1307 [MonoTODO]
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)
1315 return true;
1317 return (string.Compare (machineName, Environment.MachineName, true) == 0);
1320 #if NET_2_0
1321 [Browsable (true)]
1322 [MonitoringDescription ("Raised when it receives output data")]
1323 public event DataReceivedEventHandler OutputDataReceived;
1324 [Browsable (true)]
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));
1340 [Flags]
1341 enum AsyncModes {
1342 NoneYet = 0,
1343 SyncOutput = 1,
1344 SyncError = 1 << 1,
1345 AsyncOutput = 1 << 2,
1346 AsyncError = 1 << 3
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 */
1361 public object Sock;
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];
1371 public int Offset;
1372 public int Size;
1373 public int SockFlags;
1375 public object AcceptSocket;
1376 public object[] Addresses;
1377 public int port;
1378 public object Buffers; // Reserve this slot in older profiles
1379 public bool ReuseSocket; // Disconnect
1380 public object acc_socket;
1381 public int total;
1382 public bool completed_sync;
1383 bool completed;
1384 bool err_out; // true -> stdout, false -> stderr
1385 internal int error;
1386 public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1387 public object ares;
1388 public int EndCalled;
1390 // These fields are not in SocketAsyncResult
1391 Process process;
1392 Stream stream;
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 ()
1407 lock (this) {
1408 int nread = stream.Read (buffer, 0, buffer.Length);
1409 if (nread == 0) {
1410 completed = true;
1411 if (wait_handle != null)
1412 wait_handle.Set ();
1413 FlushLast ();
1414 return;
1417 try {
1418 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1419 } catch {
1420 // Just in case the encoding fails...
1421 for (int i = 0; i < nread; i++) {
1422 sb.Append ((char) buffer [i]);
1426 Flush (false);
1427 ReadHandler.BeginInvoke (null, this);
1431 void FlushLast ()
1433 Flush (true);
1434 if (err_out) {
1435 process.OnOutputDataReceived (null);
1436 } else {
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))
1446 return;
1448 string total = sb.ToString ();
1449 sb.Length = 0;
1450 string [] strs = total.Split ('\n');
1451 int len = strs.Length;
1452 if (len == 0)
1453 return;
1455 for (int i = 0; i < len - 1; i++) {
1456 if (err_out)
1457 process.OnOutputDataReceived (strs [i]);
1458 else
1459 process.OnErrorDataReceived (strs [i]);
1462 string end = strs [len - 1];
1463 if (last || (len == 1 && end == "")) {
1464 if (err_out) {
1465 process.OnOutputDataReceived (end);
1466 } else {
1467 process.OnErrorDataReceived (end);
1469 } else {
1470 sb.Append (end);
1474 public bool IsCompleted {
1475 get { return completed; }
1478 public WaitHandle WaitHandle {
1479 get {
1480 lock (this) {
1481 if (wait_handle == null)
1482 wait_handle = new ManualResetEvent (completed);
1483 return wait_handle;
1488 public void Close () {
1489 stream.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;
1563 #endif
1565 [Category ("Behavior")]
1566 [MonitoringDescription ("Raised when this process exits.")]
1567 public event EventHandler Exited {
1568 add {
1569 if (process_handle != IntPtr.Zero && HasExited) {
1570 value.BeginInvoke (null, null, null, null);
1571 } else {
1572 exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1573 if (exited_event != null)
1574 StartExitCallbackIfNeeded ();
1577 remove {
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) {
1591 this.disposed=true;
1592 // If this is a call to Dispose,
1593 // dispose all managed resources.
1594 if(disposing) {
1595 // Do stuff here
1596 lock (this) {
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
1607 lock(this) {
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);
1632 ~Process ()
1634 Dispose (false);
1637 static void CBOnExit (object state, bool unused)
1639 Process p = (Process) state;
1640 p.OnExited ();
1643 protected void OnExited()
1645 if (exited_event == null)
1646 return;
1648 if (synchronizingObject == null) {
1649 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1650 try {
1651 d (this, EventArgs.Empty);
1652 } catch {}
1654 return;
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) {
1670 return true;
1672 return false;
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).