Revert
[mono-project.git] / mcs / class / System / System.Diagnostics / Process.cs
blob75787d07bc22daf2e5df78ae6648c7966eaf49b6
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 int [] pids = GetProcesses_internal ();
893 if (pids == null)
894 return new Process [0];
896 ArrayList proclist = new ArrayList ();
897 for (int i = 0; i < pids.Length; i++) {
898 try {
899 Process p = GetProcessById (pids [i]);
900 if (String.Compare (processName, p.ProcessName, true) == 0)
901 proclist.Add (p);
902 } catch (SystemException) {
903 /* The process might exit
904 * between
905 * GetProcesses_internal and
906 * GetProcessById
911 return ((Process []) proclist.ToArray (typeof (Process)));
914 [MonoTODO]
915 public static Process[] GetProcessesByName(string processName, string machineName) {
916 throw new NotImplementedException();
919 public void Kill ()
921 Close (1);
924 [MonoTODO]
925 public static void LeaveDebugMode() {
928 public void Refresh ()
930 // FIXME: should refresh any cached data we might have about
931 // the process (currently we have none).
934 [MethodImplAttribute(MethodImplOptions.InternalCall)]
935 private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
936 ref ProcInfo proc_info);
938 [MethodImplAttribute(MethodImplOptions.InternalCall)]
939 private extern static bool CreateProcess_internal(ProcessStartInfo startInfo,
940 IntPtr stdin,
941 IntPtr stdout,
942 IntPtr stderr,
943 ref ProcInfo proc_info);
945 private static bool Start_shell (ProcessStartInfo startInfo,
946 Process process)
948 ProcInfo proc_info=new ProcInfo();
949 bool ret;
951 if (startInfo.RedirectStandardInput ||
952 startInfo.RedirectStandardOutput ||
953 startInfo.RedirectStandardError) {
954 throw new InvalidOperationException ("UseShellExecute must be false when redirecting I/O.");
957 if (startInfo.HaveEnvVars)
958 throw new InvalidOperationException ("UseShellExecute must be false in order to use environment variables.");
960 FillUserInfo (startInfo, ref proc_info);
961 try {
962 ret = ShellExecuteEx_internal (startInfo,
963 ref proc_info);
964 } finally {
965 if (proc_info.Password != IntPtr.Zero)
966 Marshal.FreeBSTR (proc_info.Password);
967 proc_info.Password = IntPtr.Zero;
969 if (!ret) {
970 throw new Win32Exception (-proc_info.pid);
973 process.process_handle = proc_info.process_handle;
974 process.pid = proc_info.pid;
976 process.StartExitCallbackIfNeeded ();
978 return(ret);
981 private static bool Start_noshell (ProcessStartInfo startInfo,
982 Process process)
984 ProcInfo proc_info=new ProcInfo();
985 IntPtr stdin_rd = IntPtr.Zero, stdin_wr = IntPtr.Zero;
986 IntPtr stdout_wr;
987 IntPtr stderr_wr;
988 bool ret;
989 MonoIOError error;
991 if (startInfo.HaveEnvVars) {
992 string [] strs = new string [startInfo.EnvironmentVariables.Count];
993 startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
994 proc_info.envKeys = strs;
996 strs = new string [startInfo.EnvironmentVariables.Count];
997 startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
998 proc_info.envValues = strs;
1001 if (startInfo.RedirectStandardInput == true) {
1002 if (IsWindows) {
1003 int DUPLICATE_SAME_ACCESS = 0x00000002;
1004 IntPtr stdin_wr_tmp;
1006 ret = MonoIO.CreatePipe (out stdin_rd,
1007 out stdin_wr_tmp);
1008 if (ret) {
1009 ret = MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, stdin_wr_tmp,
1010 Process.GetCurrentProcess ().Handle, out stdin_wr, 0, 0, DUPLICATE_SAME_ACCESS);
1011 MonoIO.Close (stdin_wr_tmp, out error);
1014 else
1016 ret = MonoIO.CreatePipe (out stdin_rd,
1017 out stdin_wr);
1019 if (ret == false) {
1020 throw new IOException ("Error creating standard input pipe");
1022 } else {
1023 stdin_rd = MonoIO.ConsoleInput;
1024 /* This is required to stop the
1025 * &$*£ing stupid compiler moaning
1026 * that stdin_wr is unassigned, below.
1028 stdin_wr = (IntPtr)0;
1031 if (startInfo.RedirectStandardOutput == true) {
1032 IntPtr out_rd = IntPtr.Zero;
1033 if (IsWindows) {
1034 IntPtr out_rd_tmp;
1035 int DUPLICATE_SAME_ACCESS = 0x00000002;
1037 ret = MonoIO.CreatePipe (out out_rd_tmp,
1038 out stdout_wr);
1039 if (ret) {
1040 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, out_rd_tmp,
1041 Process.GetCurrentProcess ().Handle, out out_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1042 MonoIO.Close (out_rd_tmp, out error);
1045 else {
1046 ret = MonoIO.CreatePipe (out out_rd,
1047 out stdout_wr);
1050 process.stdout_rd = out_rd;
1051 if (ret == false) {
1052 if (startInfo.RedirectStandardInput == true) {
1053 MonoIO.Close (stdin_rd, out error);
1054 MonoIO.Close (stdin_wr, out error);
1057 throw new IOException ("Error creating standard output pipe");
1059 } else {
1060 process.stdout_rd = (IntPtr)0;
1061 stdout_wr = MonoIO.ConsoleOutput;
1064 if (startInfo.RedirectStandardError == true) {
1065 IntPtr err_rd = IntPtr.Zero;
1066 if (IsWindows) {
1067 IntPtr err_rd_tmp;
1068 int DUPLICATE_SAME_ACCESS = 0x00000002;
1070 ret = MonoIO.CreatePipe (out err_rd_tmp,
1071 out stderr_wr);
1072 if (ret) {
1073 MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, err_rd_tmp,
1074 Process.GetCurrentProcess ().Handle, out err_rd, 0, 0, DUPLICATE_SAME_ACCESS);
1075 MonoIO.Close (err_rd_tmp, out error);
1078 else {
1079 ret = MonoIO.CreatePipe (out err_rd,
1080 out stderr_wr);
1083 process.stderr_rd = err_rd;
1084 if (ret == false) {
1085 if (startInfo.RedirectStandardInput == true) {
1086 MonoIO.Close (stdin_rd, out error);
1087 MonoIO.Close (stdin_wr, out error);
1089 if (startInfo.RedirectStandardOutput == true) {
1090 MonoIO.Close (process.stdout_rd, out error);
1091 MonoIO.Close (stdout_wr, out error);
1094 throw new IOException ("Error creating standard error pipe");
1096 } else {
1097 process.stderr_rd = (IntPtr)0;
1098 stderr_wr = MonoIO.ConsoleError;
1101 FillUserInfo (startInfo, ref proc_info);
1102 try {
1103 ret = CreateProcess_internal (startInfo,
1104 stdin_rd, stdout_wr, stderr_wr,
1105 ref proc_info);
1106 } finally {
1107 if (proc_info.Password != IntPtr.Zero)
1108 Marshal.FreeBSTR (proc_info.Password);
1109 proc_info.Password = IntPtr.Zero;
1111 if (!ret) {
1112 if (startInfo.RedirectStandardInput == true) {
1113 MonoIO.Close (stdin_rd, out error);
1114 MonoIO.Close (stdin_wr, out error);
1117 if (startInfo.RedirectStandardOutput == true) {
1118 MonoIO.Close (process.stdout_rd, out error);
1119 MonoIO.Close (stdout_wr, out error);
1122 if (startInfo.RedirectStandardError == true) {
1123 MonoIO.Close (process.stderr_rd, out error);
1124 MonoIO.Close (stderr_wr, out error);
1127 throw new Win32Exception (-proc_info.pid,
1128 "ApplicationName='" + startInfo.FileName +
1129 "', CommandLine='" + startInfo.Arguments +
1130 "', CurrentDirectory='" + startInfo.WorkingDirectory + "'");
1133 process.process_handle = proc_info.process_handle;
1134 process.pid = proc_info.pid;
1136 if (startInfo.RedirectStandardInput == true) {
1137 MonoIO.Close (stdin_rd, out error);
1138 process.input_stream = new StreamWriter (new MonoSyncFileStream (stdin_wr, FileAccess.Write, true, 8192), Console.Out.Encoding);
1139 process.input_stream.AutoFlush = true;
1142 #if NET_2_0
1143 Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
1144 Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
1145 #else
1146 Encoding stdoutEncoding = Console.Out.Encoding;
1147 Encoding stderrEncoding = stdoutEncoding;
1148 #endif
1150 if (startInfo.RedirectStandardOutput == true) {
1151 MonoIO.Close (stdout_wr, out error);
1152 process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding, true, 8192);
1155 if (startInfo.RedirectStandardError == true) {
1156 MonoIO.Close (stderr_wr, out error);
1157 process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding, true, 8192);
1160 process.StartExitCallbackIfNeeded ();
1162 return(ret);
1165 // Note that ProcInfo.Password must be freed.
1166 private static void FillUserInfo (ProcessStartInfo startInfo, ref ProcInfo proc_info)
1168 #if NET_2_0
1169 if (startInfo.UserName != null) {
1170 proc_info.UserName = startInfo.UserName;
1171 proc_info.Domain = startInfo.Domain;
1172 if (startInfo.Password != null)
1173 proc_info.Password = Marshal.SecureStringToBSTR (startInfo.Password);
1174 else
1175 proc_info.Password = IntPtr.Zero;
1176 proc_info.LoadUserProfile = startInfo.LoadUserProfile;
1178 #endif
1181 private static bool Start_common (ProcessStartInfo startInfo,
1182 Process process)
1184 if (startInfo.FileName == null || startInfo.FileName.Length == 0)
1185 throw new InvalidOperationException("File name has not been set");
1187 #if NET_2_0
1188 if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError)
1189 throw new InvalidOperationException ("StandardErrorEncoding is only supported when standard error is redirected");
1190 if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput)
1191 throw new InvalidOperationException ("StandardOutputEncoding is only supported when standard output is redirected");
1192 #endif
1194 if (startInfo.UseShellExecute) {
1195 #if NET_2_0
1196 if (!String.IsNullOrEmpty (startInfo.UserName))
1197 throw new InvalidOperationException ("UserShellExecute must be false if an explicit UserName is specified when starting a process");
1198 #endif
1199 return (Start_shell (startInfo, process));
1200 } else {
1201 return (Start_noshell (startInfo, process));
1205 public bool Start ()
1207 if (process_handle != IntPtr.Zero) {
1208 Process_free_internal (process_handle);
1209 process_handle = IntPtr.Zero;
1211 return Start_common(start_info, this);
1214 public static Process Start (ProcessStartInfo startInfo)
1216 if (startInfo == null)
1217 throw new ArgumentNullException ("startInfo");
1219 Process process=new Process();
1220 process.StartInfo = startInfo;
1221 if (Start_common(startInfo, process))
1222 return process;
1223 return null;
1226 public static Process Start (string fileName)
1228 return Start (new ProcessStartInfo (fileName));
1231 public static Process Start(string fileName, string arguments)
1233 return Start (new ProcessStartInfo (fileName, arguments));
1236 #if NET_2_0
1237 public static Process Start(string fileName, string username, SecureString password, string domain) {
1238 return Start(fileName, null, username, password, domain);
1241 public static Process Start(string fileName, string arguments, string username, SecureString password, string domain) {
1242 ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
1243 psi.UserName = username;
1244 psi.Password = password;
1245 psi.Domain = domain;
1246 psi.UseShellExecute = false;
1247 return Start(psi);
1249 #endif
1251 public override string ToString()
1253 return(base.ToString() + " (" + this.ProcessName + ")");
1256 /* Waits up to ms milliseconds for process 'handle' to
1257 * exit. ms can be <0 to mean wait forever.
1259 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1260 private extern bool WaitForExit_internal(IntPtr handle, int ms);
1262 public void WaitForExit ()
1264 WaitForExit (-1);
1267 public bool WaitForExit(int milliseconds) {
1268 int ms = milliseconds;
1269 if (ms == int.MaxValue)
1270 ms = -1;
1272 #if NET_2_0
1273 DateTime start = DateTime.UtcNow;
1274 if (async_output != null && !async_output.IsCompleted) {
1275 if (false == async_output.WaitHandle.WaitOne (ms, false))
1276 return false; // Timed out
1278 if (ms >= 0) {
1279 DateTime now = DateTime.UtcNow;
1280 ms -= (int) (now - start).TotalMilliseconds;
1281 if (ms <= 0)
1282 return false;
1283 start = now;
1287 if (async_error != null && !async_error.IsCompleted) {
1288 if (false == async_error.WaitHandle.WaitOne (ms, false))
1289 return false; // Timed out
1291 if (ms >= 0) {
1292 ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
1293 if (ms <= 0)
1294 return false;
1297 #endif
1298 return WaitForExit_internal (process_handle, ms);
1301 /* Waits up to ms milliseconds for process 'handle' to
1302 * wait for input. ms can be <0 to mean wait forever.
1304 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1305 private extern bool WaitForInputIdle_internal(IntPtr handle, int ms);
1307 // The internal call is only implemented properly on Windows.
1308 [MonoTODO]
1309 public bool WaitForInputIdle() {
1310 return WaitForInputIdle (-1);
1313 // The internal call is only implemented properly on Windows.
1314 [MonoTODO]
1315 public bool WaitForInputIdle(int milliseconds) {
1316 return WaitForInputIdle_internal (process_handle, milliseconds);
1319 private static bool IsLocalMachine (string machineName)
1321 if (machineName == "." || machineName.Length == 0)
1322 return true;
1324 return (string.Compare (machineName, Environment.MachineName, true) == 0);
1327 #if NET_2_0
1328 [Browsable (true)]
1329 [MonitoringDescription ("Raised when it receives output data")]
1330 public event DataReceivedEventHandler OutputDataReceived;
1331 [Browsable (true)]
1332 [MonitoringDescription ("Raised when it receives error data")]
1333 public event DataReceivedEventHandler ErrorDataReceived;
1335 void OnOutputDataReceived (string str)
1337 if (OutputDataReceived != null)
1338 OutputDataReceived (this, new DataReceivedEventArgs (str));
1341 void OnErrorDataReceived (string str)
1343 if (ErrorDataReceived != null)
1344 ErrorDataReceived (this, new DataReceivedEventArgs (str));
1347 [Flags]
1348 enum AsyncModes {
1349 NoneYet = 0,
1350 SyncOutput = 1,
1351 SyncError = 1 << 1,
1352 AsyncOutput = 1 << 2,
1353 AsyncError = 1 << 3
1356 [StructLayout (LayoutKind.Sequential)]
1357 sealed class ProcessAsyncReader
1360 The following fields match those of SocketAsyncResult.
1361 This is so that changes needed in the runtime to handle
1362 asynchronous reads are trivial
1363 Keep this in sync with SocketAsyncResult in
1364 ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
1365 in metadata/socket-io.h.
1367 /* DON'T shuffle fields around. DON'T remove fields */
1368 public object Sock;
1369 public IntPtr handle;
1370 public object state;
1371 public AsyncCallback callback;
1372 public ManualResetEvent wait_handle;
1374 public Exception delayedException;
1376 public object EndPoint;
1377 byte [] buffer = new byte [4196];
1378 public int Offset;
1379 public int Size;
1380 public int SockFlags;
1382 public object AcceptSocket;
1383 public object[] Addresses;
1384 public int port;
1385 public object Buffers; // Reserve this slot in older profiles
1386 public bool ReuseSocket; // Disconnect
1387 public object acc_socket;
1388 public int total;
1389 public bool completed_sync;
1390 bool completed;
1391 bool err_out; // true -> stdout, false -> stderr
1392 internal int error;
1393 public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
1394 public object ares;
1395 public int EndCalled;
1397 // These fields are not in SocketAsyncResult
1398 Process process;
1399 Stream stream;
1400 StringBuilder sb = new StringBuilder ();
1401 public AsyncReadHandler ReadHandler;
1403 public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
1405 this.process = process;
1406 this.handle = handle;
1407 stream = new FileStream (handle, FileAccess.Read, false);
1408 this.ReadHandler = new AsyncReadHandler (AddInput);
1409 this.err_out = err_out;
1412 public void AddInput ()
1414 lock (this) {
1415 int nread = stream.Read (buffer, 0, buffer.Length);
1416 if (nread == 0) {
1417 completed = true;
1418 if (wait_handle != null)
1419 wait_handle.Set ();
1420 FlushLast ();
1421 return;
1424 try {
1425 sb.Append (Encoding.Default.GetString (buffer, 0, nread));
1426 } catch {
1427 // Just in case the encoding fails...
1428 for (int i = 0; i < nread; i++) {
1429 sb.Append ((char) buffer [i]);
1433 Flush (false);
1434 ReadHandler.BeginInvoke (null, this);
1438 void FlushLast ()
1440 Flush (true);
1441 if (err_out) {
1442 process.OnOutputDataReceived (null);
1443 } else {
1444 process.OnErrorDataReceived (null);
1448 void Flush (bool last)
1450 if (sb.Length == 0 ||
1451 (err_out && process.output_canceled) ||
1452 (!err_out && process.error_canceled))
1453 return;
1455 string total = sb.ToString ();
1456 sb.Length = 0;
1457 string [] strs = total.Split ('\n');
1458 int len = strs.Length;
1459 if (len == 0)
1460 return;
1462 for (int i = 0; i < len - 1; i++) {
1463 if (err_out)
1464 process.OnOutputDataReceived (strs [i]);
1465 else
1466 process.OnErrorDataReceived (strs [i]);
1469 string end = strs [len - 1];
1470 if (last || (len == 1 && end == "")) {
1471 if (err_out) {
1472 process.OnOutputDataReceived (end);
1473 } else {
1474 process.OnErrorDataReceived (end);
1476 } else {
1477 sb.Append (end);
1481 public bool IsCompleted {
1482 get { return completed; }
1485 public WaitHandle WaitHandle {
1486 get {
1487 lock (this) {
1488 if (wait_handle == null)
1489 wait_handle = new ManualResetEvent (completed);
1490 return wait_handle;
1495 public void Close () {
1496 stream.Close ();
1500 AsyncModes async_mode;
1501 bool output_canceled;
1502 bool error_canceled;
1503 ProcessAsyncReader async_output;
1504 ProcessAsyncReader async_error;
1505 delegate void AsyncReadHandler ();
1507 [ComVisibleAttribute(false)]
1508 public void BeginOutputReadLine ()
1510 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1511 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1513 if ((async_mode & AsyncModes.SyncOutput) != 0)
1514 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1516 async_mode |= AsyncModes.AsyncOutput;
1517 output_canceled = false;
1518 if (async_output == null) {
1519 async_output = new ProcessAsyncReader (this, stdout_rd, true);
1520 async_output.ReadHandler.BeginInvoke (null, async_output);
1524 [ComVisibleAttribute(false)]
1525 public void CancelOutputRead ()
1527 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1528 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1530 if ((async_mode & AsyncModes.SyncOutput) != 0)
1531 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1533 if (async_output == null)
1534 throw new InvalidOperationException ("No async operation in progress.");
1536 output_canceled = true;
1539 [ComVisibleAttribute(false)]
1540 public void BeginErrorReadLine ()
1542 if (process_handle == IntPtr.Zero || error_stream == null || StartInfo.RedirectStandardError == false)
1543 throw new InvalidOperationException ("Standard error has not been redirected or process has not been started.");
1545 if ((async_mode & AsyncModes.SyncError) != 0)
1546 throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
1548 async_mode |= AsyncModes.AsyncError;
1549 error_canceled = false;
1550 if (async_error == null) {
1551 async_error = new ProcessAsyncReader (this, stderr_rd, false);
1552 async_error.ReadHandler.BeginInvoke (null, async_error);
1556 [ComVisibleAttribute(false)]
1557 public void CancelErrorRead ()
1559 if (process_handle == IntPtr.Zero || output_stream == null || StartInfo.RedirectStandardOutput == false)
1560 throw new InvalidOperationException ("Standard output has not been redirected or process has not been started.");
1562 if ((async_mode & AsyncModes.SyncOutput) != 0)
1563 throw new InvalidOperationException ("OutputStream is not enabled for asynchronous read operations.");
1565 if (async_error == null)
1566 throw new InvalidOperationException ("No async operation in progress.");
1568 error_canceled = true;
1570 #endif
1572 [Category ("Behavior")]
1573 [MonitoringDescription ("Raised when this process exits.")]
1574 public event EventHandler Exited {
1575 add {
1576 if (process_handle != IntPtr.Zero && HasExited) {
1577 value.BeginInvoke (null, null, null, null);
1578 } else {
1579 exited_event = (EventHandler) Delegate.Combine (exited_event, value);
1580 if (exited_event != null)
1581 StartExitCallbackIfNeeded ();
1584 remove {
1585 exited_event = (EventHandler) Delegate.Remove (exited_event, value);
1589 // Closes the system process handle
1590 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1591 private extern void Process_free_internal(IntPtr handle);
1593 private bool disposed = false;
1595 protected override void Dispose(bool disposing) {
1596 // Check to see if Dispose has already been called.
1597 if(this.disposed == false) {
1598 this.disposed=true;
1599 // If this is a call to Dispose,
1600 // dispose all managed resources.
1601 if(disposing) {
1602 // Do stuff here
1603 lock (this) {
1604 /* These have open FileStreams on the pipes we are about to close */
1605 if (async_output != null)
1606 async_output.Close ();
1607 if (async_error != null)
1608 async_error.Close ();
1612 // Release unmanaged resources
1614 lock(this) {
1615 if(process_handle!=IntPtr.Zero) {
1616 Process_free_internal(process_handle);
1617 process_handle=IntPtr.Zero;
1620 if (input_stream != null) {
1621 input_stream.Close();
1622 input_stream = null;
1625 if (output_stream != null) {
1626 output_stream.Close();
1627 output_stream = null;
1630 if (error_stream != null) {
1631 error_stream.Close();
1632 error_stream = null;
1636 base.Dispose (disposing);
1639 ~Process ()
1641 Dispose (false);
1644 static void CBOnExit (object state, bool unused)
1646 Process p = (Process) state;
1647 p.already_waiting = false;
1648 p.OnExited ();
1651 protected void OnExited()
1653 if (exited_event == null)
1654 return;
1656 if (synchronizingObject == null) {
1657 foreach (EventHandler d in exited_event.GetInvocationList ()) {
1658 try {
1659 d (this, EventArgs.Empty);
1660 } catch {}
1662 return;
1665 object [] args = new object [] {this, EventArgs.Empty};
1666 synchronizingObject.BeginInvoke (exited_event, args);
1669 static bool IsWindows
1673 PlatformID platform = Environment.OSVersion.Platform;
1674 if (platform == PlatformID.Win32S ||
1675 platform == PlatformID.Win32Windows ||
1676 platform == PlatformID.Win32NT ||
1677 platform == PlatformID.WinCE) {
1678 return true;
1680 return false;
1684 class ProcessWaitHandle : WaitHandle
1686 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1687 private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
1689 public ProcessWaitHandle (IntPtr handle)
1691 // Need to keep a reference to this handle,
1692 // in case the Process object is collected
1693 Handle = ProcessHandle_duplicate (handle);
1695 // When the wait handle is disposed, the duplicated handle will be
1696 // closed, so no need to override dispose (bug #464628).