2 // System.Diagnostics.Process.cs
5 // Dick Porter (dick@ximian.com)
6 // Andreas Nahr (ClassDevelopment@A-SoftTech.com)
7 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 // (C) 2002 Ximian, Inc.
10 // (C) 2003 Andreas Nahr
11 // (c) 2004 Novell, Inc. (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 using System
.ComponentModel
;
38 using System
.ComponentModel
.Design
;
39 using System
.Runtime
.CompilerServices
;
40 using System
.Runtime
.InteropServices
;
41 using System
.Collections
;
42 using System
.Threading
;
44 namespace System
.Diagnostics
{
45 [DefaultEvent ("Exited"), DefaultProperty ("StartInfo")]
46 [Designer ("System.Diagnostics.Design.ProcessDesigner, " + Consts
.AssemblySystem_Design
, typeof (IDesigner
))]
47 public class Process
: Component
49 [StructLayout(LayoutKind
.Sequential
)]
50 private struct ProcInfo
52 public IntPtr process_handle
;
53 /* If thread_handle is ever needed for
54 * something, take out the CloseHandle() in
55 * the Start_internal icall in
56 * mono/metadata/process.c
58 public IntPtr thread_handle
;
59 public int pid
; // Contains -GetLastError () on failure.
61 public string [] envKeys
;
62 public string [] envValues
;
63 public bool useShellExecute
;
66 IntPtr process_handle
;
68 bool enableRaisingEvents
;
69 ISynchronizeInvoke synchronizingObject
;
71 /* Private constructor called from other methods */
72 private Process(IntPtr handle
, int id
) {
73 process_handle
=handle
;
82 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
83 [MonitoringDescription ("Base process priority.")]
84 public int BasePriority
{
90 [DefaultValue (false), Browsable (false)]
91 [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
92 public bool EnableRaisingEvents
{
94 return enableRaisingEvents
;
97 if (process_handle
!= IntPtr
.Zero
)
98 throw new InvalidOperationException ("The process is already started.");
100 enableRaisingEvents
= value;
105 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
106 private extern static int ExitCode_internal(IntPtr handle
);
108 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
109 [MonitoringDescription ("The exit code of the process.")]
110 public int ExitCode
{
112 if (process_handle
== IntPtr
.Zero
)
113 throw new InvalidOperationException ("Process has not been started.");
115 int code
= ExitCode_internal (process_handle
);
117 throw new InvalidOperationException ("The process must exit before " +
118 "getting the requested information.");
124 /* Returns the process start time in Windows file
125 * times (ticks from DateTime(1/1/1601 00:00 GMT))
127 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
128 private extern static long ExitTime_internal(IntPtr handle
);
130 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
131 [MonitoringDescription ("The exit time of the process.")]
132 public DateTime ExitTime
{
134 if (process_handle
== IntPtr
.Zero
)
135 throw new InvalidOperationException ("Process has not been started.");
138 throw new InvalidOperationException ("The process must exit before " +
139 "getting the requested information.");
141 return(DateTime
.FromFileTime(ExitTime_internal(process_handle
)));
145 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
146 [MonitoringDescription ("Handle for this process.")]
147 public IntPtr Handle
{
149 return(process_handle
);
154 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
155 [MonitoringDescription ("Handles for this process.")]
156 public int HandleCount
{
162 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
163 [MonitoringDescription ("Determines if the process is still running.")]
164 public bool HasExited
{
166 if (process_handle
== IntPtr
.Zero
)
167 throw new InvalidOperationException ("Process has not been started.");
169 int exitcode
= ExitCode_internal (process_handle
);
180 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
181 [MonitoringDescription ("Process identifier.")]
189 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
190 [MonitoringDescription ("The name of the computer running the process.")]
191 public string MachineName
{
197 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
198 [MonitoringDescription ("The main module of the process.")]
199 public ProcessModule MainModule
{
201 return(this.Modules
[0]);
206 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
207 [MonitoringDescription ("The handle of the main window of the process.")]
208 public IntPtr MainWindowHandle
{
215 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
216 [MonitoringDescription ("The title of the main window of the process.")]
217 public string MainWindowTitle
{
223 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
224 private extern static bool GetWorkingSet_internal(IntPtr handle
, out int min
, out int max
);
225 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
226 private extern static bool SetWorkingSet_internal(IntPtr handle
, int min
, int max
, bool use_min
);
228 /* LAMESPEC: why is this an IntPtr not a plain int? */
229 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
230 [MonitoringDescription ("The maximum working set for this process.")]
231 public IntPtr MaxWorkingSet
{
234 throw new InvalidOperationException("The process " + ProcessName
+ " (ID " + Id
+ ") has exited");
239 bool ok
=GetWorkingSet_internal(process_handle
, out min
, out max
);
241 throw new Win32Exception();
248 throw new InvalidOperationException("The process " + ProcessName
+ " (ID " + Id
+ ") has exited");
251 bool ok
=SetWorkingSet_internal(process_handle
, 0, value.ToInt32(), false);
253 throw new Win32Exception();
258 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
259 [MonitoringDescription ("The minimum working set for this process.")]
260 public IntPtr MinWorkingSet
{
263 throw new InvalidOperationException("The process " + ProcessName
+ " (ID " + Id
+ ") has exited");
268 bool ok
=GetWorkingSet_internal(process_handle
, out min
, out max
);
270 throw new Win32Exception();
277 throw new InvalidOperationException("The process " + ProcessName
+ " (ID " + Id
+ ") has exited");
280 bool ok
=SetWorkingSet_internal(process_handle
, value.ToInt32(), 0, true);
282 throw new Win32Exception();
287 /* Returns the list of process modules. The main module is
290 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
291 private extern ProcessModule
[] GetModules_internal();
293 private ProcessModuleCollection module_collection
;
295 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
296 [MonitoringDescription ("The modules that are loaded as part of this process.")]
297 public ProcessModuleCollection Modules
{
299 if(module_collection
==null) {
300 module_collection
=new ProcessModuleCollection(GetModules_internal());
303 return(module_collection
);
308 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
309 [MonitoringDescription ("The number of bytes that are not pageable.")]
310 public int NonpagedSystemMemorySize
{
317 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
318 [MonitoringDescription ("The number of bytes that are paged.")]
319 public int PagedMemorySize
{
326 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
327 [MonitoringDescription ("The amount of paged system memory in bytes.")]
328 public int PagedSystemMemorySize
{
335 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
336 [MonitoringDescription ("The maximum amount of paged memory used by this process.")]
337 public int PeakPagedMemorySize
{
344 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
345 [MonitoringDescription ("The maximum amount of virtual memory used by this process.")]
346 public int PeakVirtualMemorySize
{
353 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
354 [MonitoringDescription ("The maximum amount of system memory used by this process.")]
355 public int PeakWorkingSet
{
362 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
363 [MonitoringDescription ("Process will be of higher priority while it is actively used.")]
364 public bool PriorityBoostEnabled
{
373 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
374 [MonitoringDescription ("The relative process priority.")]
375 public ProcessPriorityClass PriorityClass
{
377 return(ProcessPriorityClass
.Normal
);
384 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
385 [MonitoringDescription ("The amount of memory exclusively used by this process.")]
386 public int PrivateMemorySize
{
393 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
394 [MonitoringDescription ("The amount of processing time spent in the OS core for this process.")]
395 public TimeSpan PrivilegedProcessorTime
{
397 return(new TimeSpan(0));
401 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
402 private extern static string ProcessName_internal(IntPtr handle
);
404 private string process_name
=null;
406 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
407 [MonitoringDescription ("The name of this process.")]
408 public string ProcessName
{
410 if(process_name
==null) {
411 process_name
=ProcessName_internal(process_handle
);
412 /* If process_name is _still_
413 * null, assume the process
416 if(process_name
==null) {
417 throw new SystemException("The process has exited");
420 /* Strip the suffix (if it
421 * exists) simplistically
422 * instead of removing any
423 * trailing \.???, so we dont
424 * get stupid results on sane
427 if(process_name
.EndsWith(".exe") ||
428 process_name
.EndsWith(".bat") ||
429 process_name
.EndsWith(".com")) {
430 process_name
=process_name
.Substring(0, process_name
.Length
-4);
433 return(process_name
);
438 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
439 [MonitoringDescription ("Allowed processor that can be used by this process.")]
440 public IntPtr ProcessorAffinity
{
449 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
450 [MonitoringDescription ("Is this process responsive.")]
451 public bool Responding
{
457 private StreamReader error_stream
=null;
459 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
460 [MonitoringDescription ("The standard error stream of this process.")]
461 public StreamReader StandardError
{
463 if (error_stream
== null) {
464 throw new InvalidOperationException("Standard error has not been redirected");
467 return(error_stream
);
471 private StreamWriter input_stream
=null;
473 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
474 [MonitoringDescription ("The standard input stream of this process.")]
475 public StreamWriter StandardInput
{
477 if (input_stream
== null) {
478 throw new InvalidOperationException("Standard input has not been redirected");
481 return(input_stream
);
485 private StreamReader output_stream
=null;
487 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
488 [MonitoringDescription ("The standard output stream of this process.")]
489 public StreamReader StandardOutput
{
491 if (output_stream
== null) {
492 throw new InvalidOperationException("Standard output has not been redirected");
495 return(output_stream
);
499 private ProcessStartInfo start_info
=null;
501 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
502 [MonitoringDescription ("Information for the start of this process.")]
503 public ProcessStartInfo StartInfo
{
505 if(start_info
==null) {
506 start_info
=new ProcessStartInfo();
513 throw new ArgumentException("value is null");
520 /* Returns the process start time in Windows file
521 * times (ticks from DateTime(1/1/1601 00:00 GMT))
523 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
524 private extern static long StartTime_internal(IntPtr handle
);
526 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
527 [MonitoringDescription ("The time this process started.")]
528 public DateTime StartTime
{
530 return(DateTime
.FromFileTime(StartTime_internal(process_handle
)));
534 [DefaultValue (null), Browsable (false)]
535 [MonitoringDescription ("The object that is used to synchronize event handler calls for this process.")]
536 public ISynchronizeInvoke SynchronizingObject
{
537 get { return synchronizingObject; }
538 set { synchronizingObject = value; }
542 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
), Browsable (false)]
543 [MonitoringDescription ("The number of threads of this process.")]
544 public ProcessThreadCollection Threads
{
551 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
552 [MonitoringDescription ("The total CPU time spent for this process.")]
553 public TimeSpan TotalProcessorTime
{
555 return(new TimeSpan(0));
560 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
561 [MonitoringDescription ("The CPU time spent for this process in user mode.")]
562 public TimeSpan UserProcessorTime
{
564 return(new TimeSpan(0));
569 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
570 [MonitoringDescription ("The amount of virtual memory currently used for this process.")]
571 public int VirtualMemorySize
{
578 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
579 [MonitoringDescription ("The amount of physical memory currently used for this process.")]
580 public int WorkingSet
{
591 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
592 extern static bool Kill_internal (IntPtr handle
, int signo
);
594 /* int kill -> 1 KILL, 2 CloseMainWindow */
595 bool Close (int signo
)
597 if (process_handle
== IntPtr
.Zero
)
598 throw new SystemException ("No process to kill.");
600 int exitcode
= ExitCode_internal (process_handle
);
602 throw new InvalidOperationException ("The process already finished.");
604 return Kill_internal (process_handle
, signo
);
607 public bool CloseMainWindow ()
613 public static void EnterDebugMode() {
616 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
617 private extern static IntPtr
GetProcess_internal(int pid
);
619 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
620 private extern static int GetPid_internal();
622 public static Process
GetCurrentProcess() {
623 int pid
=GetPid_internal();
624 IntPtr proc
=GetProcess_internal(pid
);
626 if(proc
==IntPtr
.Zero
) {
627 throw new SystemException("Can't find current process");
630 return(new Process(proc
, pid
));
633 public static Process
GetProcessById(int processId
) {
634 IntPtr proc
=GetProcess_internal(processId
);
636 if(proc
==IntPtr
.Zero
) {
637 throw new ArgumentException("Can't find process with ID " + processId
.ToString());
640 return(new Process(proc
, processId
));
644 public static Process
GetProcessById(int processId
, string machineName
) {
645 throw new NotImplementedException();
648 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
649 private extern static int[] GetProcesses_internal();
651 public static Process
[] GetProcesses() {
652 int[] pids
=GetProcesses_internal();
653 ArrayList proclist
=new ArrayList();
655 for(int i
=0; i
<pids
.Length
; i
++) {
657 proclist
.Add(GetProcessById(pids
[i
]));
658 } catch (SystemException
) {
659 /* The process might exit
661 * GetProcesses_internal and
667 return((Process
[])proclist
.ToArray(typeof(Process
)));
671 public static Process
[] GetProcesses(string machineName
) {
672 throw new NotImplementedException();
675 public static Process
[] GetProcessesByName(string processName
) {
676 Process
[] procs
=GetProcesses();
677 ArrayList proclist
=new ArrayList();
679 for(int i
=0; i
<procs
.Length
; i
++) {
681 if(String
.Compare(processName
,
682 procs
[i
].ProcessName
,
684 proclist
.Add(procs
[i
]);
688 return((Process
[])proclist
.ToArray(typeof(Process
)));
692 public static Process
[] GetProcessesByName(string processName
, string machineName
) {
693 throw new NotImplementedException();
702 public static void LeaveDebugMode() {
706 public void Refresh() {
709 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
710 private extern static bool Start_internal(string appname
,
716 ref ProcInfo proc_info
);
718 private static bool Start_common(ProcessStartInfo startInfo
,
720 ProcInfo proc_info
=new ProcInfo();
721 IntPtr stdin_rd
, stdin_wr
;
722 IntPtr stdout_rd
, stdout_wr
;
723 IntPtr stderr_rd
, stderr_wr
;
726 if(startInfo
.FileName
== null || startInfo
.FileName
== "") {
727 throw new InvalidOperationException("File name has not been set");
730 proc_info
.useShellExecute
= startInfo
.UseShellExecute
;
731 if (proc_info
.useShellExecute
&& (startInfo
.RedirectStandardInput
||
732 startInfo
.RedirectStandardOutput
|| startInfo
.RedirectStandardError
)) {
733 throw new InvalidOperationException ("UseShellExecute must be false when " +
737 if (startInfo
.HaveEnvVars
) {
738 if (startInfo
.UseShellExecute
)
739 throw new InvalidOperationException ("UseShellExecute must be false in order " +
740 "to use environment variables.");
742 string [] strs
= new string [startInfo
.EnvironmentVariables
.Count
];
743 startInfo
.EnvironmentVariables
.Keys
.CopyTo (strs
, 0);
744 proc_info
.envKeys
= strs
;
746 strs
= new string [startInfo
.EnvironmentVariables
.Count
];
747 startInfo
.EnvironmentVariables
.Values
.CopyTo (strs
, 0);
748 proc_info
.envValues
= strs
;
751 if(startInfo
.RedirectStandardInput
==true) {
752 ret
=MonoIO
.CreatePipe(out stdin_rd
,
755 throw new IOException("Error creating standard input pipe");
758 stdin_rd
=MonoIO
.ConsoleInput
;
759 /* This is required to stop the
760 * &$*£ing stupid compiler moaning
761 * that stdin_wr is unassigned, below.
766 if(startInfo
.RedirectStandardOutput
==true) {
767 ret
=MonoIO
.CreatePipe(out stdout_rd
,
770 throw new IOException("Error creating standard output pipe");
774 stdout_wr
=MonoIO
.ConsoleOutput
;
777 if(startInfo
.RedirectStandardError
==true) {
778 ret
=MonoIO
.CreatePipe(out stderr_rd
,
781 throw new IOException("Error creating standard error pipe");
785 stderr_wr
=MonoIO
.ConsoleError
;
790 if (startInfo
.UseShellExecute
) {
792 string args
= startInfo
.Arguments
;
793 if (args
== null || args
.Trim () == "")
794 cmdline
= startInfo
.FileName
;
796 cmdline
= startInfo
.FileName
+ " " + startInfo
.Arguments
.Trim ();
798 appname
= startInfo
.FileName
;
799 // FIXME: There seems something wrong in process.c. We should not require extraneous command line
800 if (Path
.DirectorySeparatorChar
== '\\')
801 cmdline
= appname
+ " " + startInfo
.Arguments
.Trim ();
803 cmdline
= startInfo
.Arguments
.Trim ();
806 ret
=Start_internal(appname
,
808 startInfo
.WorkingDirectory
,
809 stdin_rd
, stdout_wr
, stderr_wr
,
815 if (startInfo
.RedirectStandardInput
== true)
816 MonoIO
.Close (stdin_rd
, out error
);
818 if (startInfo
.RedirectStandardOutput
== true)
819 MonoIO
.Close (stdout_wr
, out error
);
821 if (startInfo
.RedirectStandardError
== true)
822 MonoIO
.Close (stderr_wr
, out error
);
824 throw new Win32Exception (-proc_info
.pid
);
827 if (process
.enableRaisingEvents
&& process
.Exited
!= null) {
828 WaitOrTimerCallback cb
= new WaitOrTimerCallback (CBOnExit
);
829 ProcessWaitHandle h
= new ProcessWaitHandle (proc_info
.process_handle
);
830 ThreadPool
.RegisterWaitForSingleObject (h
, cb
, process
, -1, true);
833 process
.process_handle
=proc_info
.process_handle
;
834 process
.pid
=proc_info
.pid
;
836 if(startInfo
.RedirectStandardInput
==true) {
837 MonoIO
.Close(stdin_rd
, out error
);
838 process
.input_stream
=new StreamWriter(new FileStream(stdin_wr
, FileAccess
.Write
, true));
839 process
.input_stream
.AutoFlush
=true;
842 if(startInfo
.RedirectStandardOutput
==true) {
843 MonoIO
.Close(stdout_wr
, out error
);
844 process
.output_stream
=new StreamReader(new FileStream(stdout_rd
, FileAccess
.Read
, true));
847 if(startInfo
.RedirectStandardError
==true) {
848 MonoIO
.Close(stderr_wr
, out error
);
849 process
.error_stream
=new StreamReader(new FileStream(stderr_rd
, FileAccess
.Read
, true));
855 public bool Start() {
858 ret
=Start_common(start_info
, this);
863 public static Process
Start(ProcessStartInfo startInfo
) {
864 Process process
=new Process();
867 ret
=Start_common(startInfo
, process
);
876 public static Process
Start(string fileName
) {
877 return Start(new ProcessStartInfo(fileName
));
880 public static Process
Start(string fileName
,
882 return Start(new ProcessStartInfo(fileName
, arguments
));
885 public override string ToString() {
886 return(base.ToString() +
887 " (" + this.ProcessName
+ ")");
890 /* Waits up to ms milliseconds for process 'handle' to
891 * exit. ms can be <0 to mean wait forever.
893 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
894 private extern bool WaitForExit_internal(IntPtr handle
,
897 public void WaitForExit() {
898 WaitForExit_internal(process_handle
, -1);
901 public bool WaitForExit(int milliseconds
) {
902 if (milliseconds
== int.MaxValue
)
905 return WaitForExit_internal (process_handle
, milliseconds
);
909 public bool WaitForInputIdle() {
914 public bool WaitForInputIdle(int milliseconds
) {
919 [MonitoringDescription ("Raised when this process exits.")]
920 public event EventHandler Exited
;
922 // Closes the system process handle
923 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
924 private extern void Process_free_internal(IntPtr handle
);
926 private bool disposed
= false;
928 protected override void Dispose(bool disposing
) {
929 // Check to see if Dispose has already been called.
930 if(this.disposed
== false) {
932 // If this is a call to Dispose,
933 // dispose all managed resources.
938 // Release unmanaged resources
941 if(process_handle
!=IntPtr
.Zero
) {
943 Process_free_internal(process_handle
);
944 process_handle
=IntPtr
.Zero
;
947 if (input_stream
!= null) {
948 input_stream
.Close();
952 if (output_stream
!= null) {
953 output_stream
.Close();
954 output_stream
= null;
957 if (error_stream
!= null) {
958 error_stream
.Close();
963 base.Dispose (disposing
);
966 static void CBOnExit (object state
, bool unused
)
968 Process p
= (Process
) state
;
972 protected void OnExited()
977 if (synchronizingObject
== null) {
978 Exited (this, EventArgs
.Empty
);
982 object [] args
= new object [] {this, EventArgs.Empty}
;
983 synchronizingObject
.BeginInvoke (Exited
, args
);
986 class ProcessWaitHandle
: WaitHandle
988 public ProcessWaitHandle (IntPtr handle
)
993 protected override void Dispose (bool explicitDisposing
)
995 // Do nothing, we don't own the handle and we won't close it.