1 //------------------------------------------------------------------------------
2 // <copyright file="Process.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
11 namespace System
.Diagnostics
{
13 using System
.Threading
;
14 using System
.Runtime
.InteropServices
;
15 using System
.ComponentModel
;
16 using System
.ComponentModel
.Design
;
17 using System
.Runtime
.CompilerServices
;
18 using System
.Runtime
.ConstrainedExecution
;
19 using System
.Diagnostics
;
21 using System
.Collections
;
23 using Microsoft
.Win32
;
24 using Microsoft
.Win32
.SafeHandles
;
25 using System
.Collections
.Specialized
;
26 using System
.Collections
.Generic
;
27 using System
.Globalization
;
28 using System
.Security
;
29 using System
.Security
.Permissions
;
30 using System
.Security
.Principal
;
31 using System
.Runtime
.Versioning
;
35 /// Provides access to local and remote
36 /// processes. Enables you to start and stop system processes.
40 MonitoringDescription(SR
.ProcessDesc
),
41 DefaultEvent("Exited"),
42 DefaultProperty("StartInfo"),
43 Designer("System.Diagnostics.Design.ProcessDesigner, " + AssemblyRef
.SystemDesign
),
44 // Disabling partial trust scenarios
45 PermissionSet(SecurityAction
.LinkDemand
, Name
="FullTrust"),
46 PermissionSet(SecurityAction
.InheritanceDemand
, Name
="FullTrust"),
47 HostProtection(SharedState
=true, Synchronization
=true, ExternalProcessMgmt
=true, SelfAffectingProcessMgmt
=true)
49 public partial class Process
: Component
{
56 bool haveProcessHandle
;
57 SafeProcessHandle m_processHandle
;
61 ProcessInfo processInfo
;
63 Int32 m_processAccess
;
66 ProcessThreadCollection threads
;
67 ProcessModuleCollection modules
;
68 #endif // !FEATURE_PAL
72 IntPtr mainWindowHandle
; // no need to use SafeHandle for window
73 string mainWindowTitle
;
76 bool haveWorkingSetLimits
;
81 bool haveProcessorAffinity
;
82 IntPtr processorAffinity
;
85 bool havePriorityClass
;
86 ProcessPriorityClass priorityClass
;
88 ProcessStartInfo startInfo
;
92 EventHandler onExited
;
104 bool priorityBoostEnabled
;
105 bool havePriorityBoostEnabled
;
109 RegisteredWaitHandle registeredWaitHandle
;
110 WaitHandle waitHandle
;
111 ISynchronizeInvoke synchronizingObject
;
112 StreamReader standardOutput
;
113 StreamWriter standardInput
;
114 StreamReader standardError
;
115 OperatingSystem operatingSystem
;
119 static object s_CreateProcessLock
= new object();
122 // This enum defines the operation mode for redirected process stream.
123 // We don't support switching between synchronous mode and asynchronous mode.
124 private enum StreamReadMode
131 StreamReadMode outputStreamReadMode
;
132 StreamReadMode errorStreamReadMode
;
135 StreamReadMode inputStreamReadMode
;
138 // Support for asynchrously reading streams
139 [Browsable(true), MonitoringDescription(SR
.ProcessAssociated
)]
140 //[System.Runtime.InteropServices.ComVisible(false)]
141 public event DataReceivedEventHandler OutputDataReceived
;
142 [Browsable(true), MonitoringDescription(SR
.ProcessAssociated
)]
143 //[System.Runtime.InteropServices.ComVisible(false)]
144 public event DataReceivedEventHandler ErrorDataReceived
;
145 // Abstract the stream details
146 internal AsyncStreamReader output
;
147 internal AsyncStreamReader error
;
148 internal bool pendingOutputRead
;
149 internal bool pendingErrorRead
;
152 private static SafeFileHandle InvalidPipeHandle
= new SafeFileHandle(IntPtr
.Zero
, false);
155 internal static TraceSwitch processTracing
= new TraceSwitch("processTracing", "Controls debug output from Process component");
157 internal static TraceSwitch processTracing
= null;
166 /// Initializes a new instance of the <see cref='System.Diagnostics.Process'/> class.
170 this.machineName
= ".";
171 this.outputStreamReadMode
= StreamReadMode
.undefined
;
172 this.errorStreamReadMode
= StreamReadMode
.undefined
;
173 this.m_processAccess
= NativeMethods
.PROCESS_ALL_ACCESS
;
176 [ResourceExposure(ResourceScope
.Machine
)]
177 Process(string machineName
, bool isRemoteMachine
, int processId
, ProcessInfo processInfo
) : base() {
178 Debug
.Assert(SyntaxCheck
.CheckMachineName(machineName
), "The machine name should be valid!");
180 this.processInfo
= processInfo
;
182 this.machineName
= machineName
;
183 this.isRemoteMachine
= isRemoteMachine
;
184 this.processId
= processId
;
185 this.haveProcessId
= true;
186 this.outputStreamReadMode
= StreamReadMode
.undefined
;
187 this.errorStreamReadMode
= StreamReadMode
.undefined
;
188 this.m_processAccess
= NativeMethods
.PROCESS_ALL_ACCESS
;
196 /// Returns whether this process component is associated with a real process.
199 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessAssociated
)]
202 return haveProcessId
|| haveProcessHandle
;
206 #if !FEATURE_PAL && !MONO
209 /// Gets the base priority of
210 /// the associated process.
213 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessBasePriority
)]
214 public int BasePriority
{
216 EnsureState(State
.HaveProcessInfo
);
217 return processInfo
.basePriority
;
220 #endif // !FEATURE_PAL && !MONO
226 /// value that was specified by the associated process when it was terminated.
229 [Browsable(false),DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessExitCode
)]
230 public int ExitCode
{
232 EnsureState(State
.Exited
);
234 if (exitCode
== -1 && !RuntimeInformation
.IsOSPlatform (OSPlatform
.Windows
))
235 throw new InvalidOperationException ("Cannot get the exit code from a non-child process on Unix");
244 /// value indicating whether the associated process has been terminated.
247 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessTerminated
)]
248 public bool HasExited
{
251 EnsureState(State
.Associated
);
252 SafeProcessHandle handle
= null;
254 handle
= GetProcessHandle(NativeMethods
.PROCESS_QUERY_INFORMATION
| NativeMethods
.SYNCHRONIZE
, false);
255 if (handle
.IsInvalid
) {
261 // Although this is the wrong way to check whether the process has exited,
262 // it was historically the way we checked for it, and a lot of code then took a dependency on
263 // the fact that this would always be set before the pipes were closed, so they would read
264 // the exit code out after calling ReadToEnd() or standard output or standard error. In order
265 // to allow 259 to function as a valid exit code and to break as few people as possible that
266 // took the ReadToEnd dependency, we check for an exit code before doing the more correct
267 // check to see if we have been signalled.
268 if (NativeMethods
.GetExitCodeProcess(handle
, out exitCode
) && exitCode
!= NativeMethods
.STILL_ACTIVE
) {
270 this.exitCode
= exitCode
;
274 // The best check for exit is that the kernel process object handle is invalid,
275 // or that it is valid and signaled. Checking if the exit code != STILL_ACTIVE
276 // does not guarantee the process is closed,
277 // since some process could return an actual STILL_ACTIVE exit code (259).
278 if (!signaled
) // if we just came from WaitForExit, don't repeat
280 ProcessWaitHandle wh
= null;
283 wh
= new ProcessWaitHandle(handle
);
284 this.signaled
= wh
.WaitOne(0, false);
295 /* If it's a non-child process, it's impossible to get its exit code on
296 * Unix. We don't throw here, but GetExitCodeProcess (in the io-layer)
297 * will set exitCode to -1, and we will throw if we try to call ExitCode */
298 if (!NativeMethods
.GetExitCodeProcess(handle
, out exitCode
))
299 throw new Win32Exception();
302 this.exitCode
= exitCode
;
309 ReleaseProcessHandle(handle
);
320 private ProcessThreadTimes
GetProcessTimes() {
321 ProcessThreadTimes processTimes
= new ProcessThreadTimes();
322 SafeProcessHandle handle
= null;
324 int access
= NativeMethods
.PROCESS_QUERY_INFORMATION
;
326 if (EnvironmentHelpers
.IsWindowsVistaOrAbove())
327 access
= NativeMethods
.PROCESS_QUERY_LIMITED_INFORMATION
;
329 handle
= GetProcessHandle(access
, false);
330 if( handle
.IsInvalid
) {
331 // On OS older than XP, we will not be able to get the handle for a process
332 // after it terminates.
333 // On Windows XP and newer OS, the information about a process will stay longer.
334 throw new InvalidOperationException(SR
.GetString(SR
.ProcessHasExited
, processId
.ToString(CultureInfo
.CurrentCulture
)));
337 if (!NativeMethods
.GetProcessTimes(handle
,
338 out processTimes
.create
,
339 out processTimes
.exit
,
340 out processTimes
.kernel
,
341 out processTimes
.user
)) {
342 throw new Win32Exception();
347 ReleaseProcessHandle(handle
);
355 /// Gets the time that the associated process exited.
358 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessExitTime
)]
359 public DateTime ExitTime
{
362 EnsureState(State
.IsNt
| State
.Exited
);
363 exitTime
= GetProcessTimes().ExitTime
;
369 #endif // !FEATURE_PAL
373 /// Returns the native handle for the associated process. The handle is only available
374 /// if this component started the process.
377 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessHandle
)]
378 public IntPtr Handle
{
379 [ResourceExposure(ResourceScope
.Machine
)]
380 [ResourceConsumption(ResourceScope
.Machine
)]
382 EnsureState(State
.Associated
);
383 return OpenProcessHandle(this.m_processAccess
).DangerousGetHandle();
387 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
388 public SafeProcessHandle SafeHandle
{
390 EnsureState(State
.Associated
);
391 return OpenProcessHandle(this.m_processAccess
);
395 #if !FEATURE_PAL && !MONO
398 /// Gets the number of handles that are associated
399 /// with the process.
402 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessHandleCount
)]
403 public int HandleCount
{
405 EnsureState(State
.HaveProcessInfo
);
406 return processInfo
.handleCount
;
409 #endif // !FEATURE_PAL && !MONO
414 /// the unique identifier for the associated process.
417 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessId
)]
420 EnsureState(State
.HaveId
);
428 /// the name of the computer on which the associated process is running.
431 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessMachineName
)]
432 public string MachineName
{
434 EnsureState(State
.Associated
);
444 /// Returns the window handle of the main window of the associated process.
447 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessMainWindowHandle
)]
448 public IntPtr MainWindowHandle
{
449 [ResourceExposure(ResourceScope
.Machine
)]
450 [ResourceConsumption(ResourceScope
.Machine
)]
452 if (!haveMainWindow
) {
453 EnsureState(State
.IsLocal
| State
.HaveId
);
454 mainWindowHandle
= ProcessManager
.GetMainWindowHandle(processId
);
456 if (mainWindowHandle
!= (IntPtr
)0) {
457 haveMainWindow
= true;
459 // We do the following only for the side-effect that it will throw when if the process no longer exists on the system. In Whidbey
460 // we always did this check but have now changed it to just require a ProcessId. In the case where someone has called Refresh()
461 // and the process has exited this call will throw an exception where as the above code would return 0 as the handle.
462 EnsureState(State
.HaveProcessInfo
);
465 return mainWindowHandle
;
471 /// Returns the caption of the <see cref='System.Diagnostics.Process.MainWindowHandle'/> of
472 /// the process. If the handle is zero (0), then an empty string is returned.
475 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessMainWindowTitle
)]
476 public string MainWindowTitle
{
477 [ResourceExposure(ResourceScope
.None
)]
478 [ResourceConsumption(ResourceScope
.Machine
, ResourceScope
.Machine
)]
480 if (mainWindowTitle
== null) {
481 IntPtr handle
= MainWindowHandle
;
482 if (handle
== (IntPtr
)0) {
483 mainWindowTitle
= String
.Empty
;
486 int length
= NativeMethods
.GetWindowTextLength(new HandleRef(this, handle
)) * 2;
487 StringBuilder builder
= new StringBuilder(length
);
488 NativeMethods
.GetWindowText(new HandleRef(this, handle
), builder
, builder
.Capacity
);
489 mainWindowTitle
= builder
.ToString();
492 return mainWindowTitle
;
501 /// the main module for the associated process.
504 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessMainModule
)]
505 public ProcessModule MainModule
{
506 [ResourceExposure(ResourceScope
.Process
)]
507 [ResourceConsumption(ResourceScope
.Machine
, ResourceScope
.Machine
)]
509 // We only return null if we couldn't find a main module.
510 // This could be because
511 // 1. The process hasn't finished loading the main module (most likely)
512 // 2. There are no modules loaded (possible for certain OS processes)
513 // 3. Possibly other?
515 if (OperatingSystem
.Platform
== PlatformID
.Win32NT
) {
516 EnsureState(State
.HaveId
| State
.IsLocal
);
517 // on NT the first module is the main module
518 ModuleInfo module
= NtProcessManager
.GetFirstModuleInfo(processId
);
519 return new ProcessModule(module
);
522 ProcessModuleCollection moduleCollection
= Modules
;
523 // on 9x we have to do a little more work
524 EnsureState(State
.HaveProcessInfo
);
525 foreach (ProcessModule pm
in moduleCollection
) {
526 if (pm
.moduleInfo
.Id
== processInfo
.mainModuleId
) {
538 /// Gets or sets the maximum allowable working set for the associated
542 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessMaxWorkingSet
)]
543 public IntPtr MaxWorkingSet
{
545 EnsureWorkingSetLimits();
546 return maxWorkingSet
;
548 [ResourceExposure(ResourceScope
.Process
)]
549 [ResourceConsumption(ResourceScope
.Process
)]
551 SetWorkingSetLimits(null, value);
557 /// Gets or sets the minimum allowable working set for the associated
561 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessMinWorkingSet
)]
562 public IntPtr MinWorkingSet
{
564 EnsureWorkingSetLimits();
565 return minWorkingSet
;
567 [ResourceExposure(ResourceScope
.Process
)]
568 [ResourceConsumption(ResourceScope
.Process
)]
570 SetWorkingSetLimits(value, null);
578 /// the modules that have been loaded by the associated process.
581 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessModules
)]
582 public ProcessModuleCollection Modules
{
583 [ResourceExposure(ResourceScope
.None
)]
584 [ResourceConsumption(ResourceScope
.Machine
, ResourceScope
.Machine
)]
586 if (modules
== null) {
587 EnsureState(State
.HaveId
| State
.IsLocal
);
588 ModuleInfo
[] moduleInfos
= ProcessManager
.GetModuleInfos(processId
);
589 ProcessModule
[] newModulesArray
= new ProcessModule
[moduleInfos
.Length
];
590 for (int i
= 0; i
< moduleInfos
.Length
; i
++) {
591 newModulesArray
[i
] = new ProcessModule(moduleInfos
[i
]);
593 ProcessModuleCollection newModules
= new ProcessModuleCollection(newModulesArray
);
594 modules
= newModules
;
601 /// Returns the amount of memory that the system has allocated on behalf of the
602 /// associated process that can not be written to the virtual memory paging file.
604 [Obsolete("This property has been deprecated. Please use System.Diagnostics.Process.NonpagedSystemMemorySize64 instead. http://go.microsoft.com/fwlink/?linkid=14202")]
605 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessNonpagedSystemMemorySize
)]
606 public int NonpagedSystemMemorySize
{
608 EnsureState(State
.HaveNtProcessInfo
);
609 return unchecked((int)processInfo
.poolNonpagedBytes
);
613 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessNonpagedSystemMemorySize
)]
614 [System
.Runtime
.InteropServices
.ComVisible(false)]
615 public long NonpagedSystemMemorySize64
{
617 EnsureState(State
.HaveNtProcessInfo
);
618 return processInfo
.poolNonpagedBytes
;
623 /// Returns the amount of memory that the associated process has allocated
624 /// that can be written to the virtual memory paging file.
626 [Obsolete("This property has been deprecated. Please use System.Diagnostics.Process.PagedMemorySize64 instead. http://go.microsoft.com/fwlink/?linkid=14202")]
627 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessPagedMemorySize
)]
628 public int PagedMemorySize
{
630 EnsureState(State
.HaveNtProcessInfo
);
631 return unchecked((int)processInfo
.pageFileBytes
);
635 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessPagedMemorySize
)]
636 [System
.Runtime
.InteropServices
.ComVisible(false)]
637 public long PagedMemorySize64
{
639 EnsureState(State
.HaveNtProcessInfo
);
640 return processInfo
.pageFileBytes
;
646 /// Returns the amount of memory that the system has allocated on behalf of the
647 /// associated process that can be written to the virtual memory paging file.
649 [Obsolete("This property has been deprecated. Please use System.Diagnostics.Process.PagedSystemMemorySize64 instead. http://go.microsoft.com/fwlink/?linkid=14202")]
650 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessPagedSystemMemorySize
)]
651 public int PagedSystemMemorySize
{
653 EnsureState(State
.HaveNtProcessInfo
);
654 return unchecked((int)processInfo
.poolPagedBytes
);
658 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessPagedSystemMemorySize
)]
659 [System
.Runtime
.InteropServices
.ComVisible(false)]
660 public long PagedSystemMemorySize64
{
662 EnsureState(State
.HaveNtProcessInfo
);
663 return processInfo
.poolPagedBytes
;
670 /// Returns the maximum amount of memory that the associated process has
671 /// allocated that could be written to the virtual memory paging file.
674 [Obsolete("This property has been deprecated. Please use System.Diagnostics.Process.PeakPagedMemorySize64 instead. http://go.microsoft.com/fwlink/?linkid=14202")]
675 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessPeakPagedMemorySize
)]
676 public int PeakPagedMemorySize
{
678 EnsureState(State
.HaveNtProcessInfo
);
679 return unchecked((int)processInfo
.pageFileBytesPeak
);
683 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessPeakPagedMemorySize
)]
684 [System
.Runtime
.InteropServices
.ComVisible(false)]
685 public long PeakPagedMemorySize64
{
687 EnsureState(State
.HaveNtProcessInfo
);
688 return processInfo
.pageFileBytesPeak
;
694 /// Returns the maximum amount of physical memory that the associated
695 /// process required at once.
698 [Obsolete("This property has been deprecated. Please use System.Diagnostics.Process.PeakWorkingSet64 instead. http://go.microsoft.com/fwlink/?linkid=14202")]
699 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessPeakWorkingSet
)]
700 public int PeakWorkingSet
{
702 EnsureState(State
.HaveNtProcessInfo
);
703 return unchecked((int)processInfo
.workingSetPeak
);
707 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessPeakWorkingSet
)]
708 [System
.Runtime
.InteropServices
.ComVisible(false)]
709 public long PeakWorkingSet64
{
711 EnsureState(State
.HaveNtProcessInfo
);
712 return processInfo
.workingSetPeak
;
717 /// Returns the maximum amount of virtual memory that the associated
718 /// process has requested.
720 [Obsolete("This property has been deprecated. Please use System.Diagnostics.Process.PeakVirtualMemorySize64 instead. http://go.microsoft.com/fwlink/?linkid=14202")]
721 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessPeakVirtualMemorySize
)]
722 public int PeakVirtualMemorySize
{
724 EnsureState(State
.HaveNtProcessInfo
);
725 return unchecked((int)processInfo
.virtualBytesPeak
);
729 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessPeakVirtualMemorySize
)]
730 [System
.Runtime
.InteropServices
.ComVisible(false)]
731 public long PeakVirtualMemorySize64
{
733 EnsureState(State
.HaveNtProcessInfo
);
734 return processInfo
.virtualBytesPeak
;
739 private OperatingSystem OperatingSystem
{
741 if (operatingSystem
== null) {
742 operatingSystem
= Environment
.OSVersion
;
744 return operatingSystem
;
751 /// Gets or sets a value indicating whether the associated process priority
752 /// should be temporarily boosted by the operating system when the main window
756 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessPriorityBoostEnabled
)]
757 public bool PriorityBoostEnabled
{
759 EnsureState(State
.IsNt
);
760 if (!havePriorityBoostEnabled
) {
761 SafeProcessHandle handle
= null;
763 handle
= GetProcessHandle(NativeMethods
.PROCESS_QUERY_INFORMATION
);
764 bool disabled
= false;
765 if (!NativeMethods
.GetProcessPriorityBoost(handle
, out disabled
)) {
766 throw new Win32Exception();
768 priorityBoostEnabled
= !disabled
;
769 havePriorityBoostEnabled
= true;
772 ReleaseProcessHandle(handle
);
775 return priorityBoostEnabled
;
778 EnsureState(State
.IsNt
);
779 SafeProcessHandle handle
= null;
781 handle
= GetProcessHandle(NativeMethods
.PROCESS_SET_INFORMATION
);
782 if (!NativeMethods
.SetProcessPriorityBoost(handle
, !value))
783 throw new Win32Exception();
784 priorityBoostEnabled
= value;
785 havePriorityBoostEnabled
= true;
788 ReleaseProcessHandle(handle
);
796 /// Gets or sets the overall priority category for the
797 /// associated process.
800 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessPriorityClass
)]
801 public ProcessPriorityClass PriorityClass
{
803 if (!havePriorityClass
) {
804 SafeProcessHandle handle
= null;
806 handle
= GetProcessHandle(NativeMethods
.PROCESS_QUERY_INFORMATION
);
807 int value = NativeMethods
.GetPriorityClass(handle
);
809 throw new Win32Exception();
811 priorityClass
= (ProcessPriorityClass
)value;
812 havePriorityClass
= true;
815 ReleaseProcessHandle(handle
);
818 return priorityClass
;
820 [ResourceExposure(ResourceScope
.Machine
)]
821 [ResourceConsumption(ResourceScope
.Machine
)]
823 if (!Enum
.IsDefined(typeof(ProcessPriorityClass
), value)) {
824 throw new InvalidEnumArgumentException("value", (int)value, typeof(ProcessPriorityClass
));
828 // BelowNormal and AboveNormal are only available on Win2k and greater.
829 if (((value & (ProcessPriorityClass
.BelowNormal
| ProcessPriorityClass
.AboveNormal
)) != 0) &&
830 (OperatingSystem
.Platform
!= PlatformID
.Win32NT
|| OperatingSystem
.Version
.Major
< 5)) {
831 throw new PlatformNotSupportedException(SR
.GetString(SR
.PriorityClassNotSupported
), null);
835 SafeProcessHandle handle
= null;
838 handle
= GetProcessHandle(NativeMethods
.PROCESS_SET_INFORMATION
);
839 if (!NativeMethods
.SetPriorityClass(handle
, (int)value)) {
840 throw new Win32Exception();
842 priorityClass
= value;
843 havePriorityClass
= true;
846 ReleaseProcessHandle(handle
);
853 /// Returns the number of bytes that the associated process has allocated that cannot
854 /// be shared with other processes.
856 [Obsolete("This property has been deprecated. Please use System.Diagnostics.Process.PrivateMemorySize64 instead. http://go.microsoft.com/fwlink/?linkid=14202")]
857 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessPrivateMemorySize
)]
858 public int PrivateMemorySize
{
860 EnsureState(State
.HaveNtProcessInfo
);
861 return unchecked((int)processInfo
.privateBytes
);
865 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessPrivateMemorySize
)]
866 [System
.Runtime
.InteropServices
.ComVisible(false)]
867 public long PrivateMemorySize64
{
869 EnsureState(State
.HaveNtProcessInfo
);
870 return processInfo
.privateBytes
;
876 /// Returns the amount of time the process has spent running code inside the operating
879 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessPrivilegedProcessorTime
)]
880 public TimeSpan PrivilegedProcessorTime
{
882 EnsureState(State
.IsNt
);
883 return GetProcessTimes().PrivilegedProcessorTime
;
891 /// the friendly name of the process.
894 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessProcessName
)]
895 public string ProcessName
{
896 [ResourceExposure(ResourceScope
.None
)]
897 [ResourceConsumption(ResourceScope
.Process
, ResourceScope
.Process
)]
899 EnsureState(State
.HaveProcessInfo
);
900 String processName
= processInfo
.processName
;
902 // On some old NT-based OS like win2000, the process name from NTQuerySystemInformation is up to 15 characters.
903 // Processes executing notepad_1234567.exe and notepad_12345678.exe will have the same process name.
904 // GetProcessByNames will not be able find the process for notepad_12345678.exe.
905 // So we will try to replace the name of the process by its main module name if the name is 15 characters.
906 // However we can't always get the module name:
907 // (1) Normal user will not be able to get module information about processes.
908 // (2) We can't get module information about remoting process.
909 // We can't get module name for a remote process
911 if (processName
.Length
== 15 && ProcessManager
.IsNt
&& ProcessManager
.IsOSOlderThanXP
&& !isRemoteMachine
) {
913 String mainModuleName
= MainModule
.ModuleName
;
914 if (mainModuleName
!= null) {
915 processInfo
.processName
= Path
.ChangeExtension(Path
.GetFileName(mainModuleName
), null);
919 // If we can't access the module information, we can still use the might-be-truncated name.
920 // We could fail for a few reasons:
921 // (1) We don't enough privilege to get module information.
922 // (2) The process could have terminated.
926 return processInfo
.processName
;
933 /// or sets which processors the threads in this process can be scheduled to run on.
936 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessProcessorAffinity
)]
937 public IntPtr ProcessorAffinity
{
939 if (!haveProcessorAffinity
) {
940 SafeProcessHandle handle
= null;
942 handle
= GetProcessHandle(NativeMethods
.PROCESS_QUERY_INFORMATION
);
943 IntPtr processAffinity
;
944 IntPtr systemAffinity
;
945 if (!NativeMethods
.GetProcessAffinityMask(handle
, out processAffinity
, out systemAffinity
))
946 throw new Win32Exception();
947 processorAffinity
= processAffinity
;
950 ReleaseProcessHandle(handle
);
952 haveProcessorAffinity
= true;
954 return processorAffinity
;
956 [ResourceExposure(ResourceScope
.Machine
)]
957 [ResourceConsumption(ResourceScope
.Machine
)]
959 SafeProcessHandle handle
= null;
961 handle
= GetProcessHandle(NativeMethods
.PROCESS_SET_INFORMATION
);
962 if (!NativeMethods
.SetProcessAffinityMask(handle
, value))
963 throw new Win32Exception();
965 processorAffinity
= value;
966 haveProcessorAffinity
= true;
969 ReleaseProcessHandle(handle
);
976 /// Gets a value indicating whether or not the user
977 /// interface of the process is responding.
980 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessResponding
)]
981 public bool Responding
{
982 [ResourceExposure(ResourceScope
.None
)]
983 [ResourceConsumption(ResourceScope
.Machine
, ResourceScope
.Machine
)]
985 if (!haveResponding
) {
986 IntPtr mainWindow
= MainWindowHandle
;
987 if (mainWindow
== (IntPtr
)0) {
992 responding
= NativeMethods
.SendMessageTimeout(new HandleRef(this, mainWindow
), NativeMethods
.WM_NULL
, IntPtr
.Zero
, IntPtr
.Zero
, NativeMethods
.SMTO_ABORTIFHUNG
, 5000, out result
) != (IntPtr
)0;
999 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessSessionId
)]
1000 public int SessionId
{
1002 EnsureState(State
.HaveNtProcessInfo
);
1003 return processInfo
.sessionId
;
1008 #endif // !FEATURE_PAL
1010 #if MONO_FEATURE_PROCESS_START
1013 /// Gets or sets the properties to pass into the <see cref='System.Diagnostics.Process.Start'/> method for the <see cref='System.Diagnostics.Process'/>
1017 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility
.Content
), MonitoringDescription(SR
.ProcessStartInfo
)]
1018 public ProcessStartInfo StartInfo
{
1020 if (startInfo
== null) {
1021 startInfo
= new ProcessStartInfo(this);
1025 [ResourceExposure(ResourceScope
.Machine
)]
1027 if (value == null) {
1028 throw new ArgumentNullException("value");
1037 /// Returns the time the associated process was started.
1039 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessStartTime
)]
1040 public DateTime StartTime
{
1042 EnsureState(State
.IsNt
);
1043 return GetProcessTimes().StartTime
;
1046 #endif // !FEATURE_PAL
1049 /// Represents the object used to marshal the event handler
1050 /// calls issued as a result of a Process exit. Normally
1051 /// this property will be set when the component is placed
1052 /// inside a control or a from, since those components are
1053 /// bound to a specific thread.
1058 MonitoringDescription(SR
.ProcessSynchronizingObject
)
1060 public ISynchronizeInvoke SynchronizingObject
{
1062 if (this.synchronizingObject
== null && DesignMode
) {
1063 IDesignerHost host
= (IDesignerHost
)GetService(typeof(IDesignerHost
));
1065 object baseComponent
= host
.RootComponent
;
1066 if (baseComponent
!= null && baseComponent
is ISynchronizeInvoke
)
1067 this.synchronizingObject
= (ISynchronizeInvoke
)baseComponent
;
1071 return this.synchronizingObject
;
1075 this.synchronizingObject
= value;
1084 /// Gets the set of threads that are running in the associated
1088 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessThreads
)]
1089 public ProcessThreadCollection Threads
{
1090 [ResourceExposure(ResourceScope
.Process
)]
1091 [ResourceConsumption(ResourceScope
.Process
)]
1093 if (threads
== null) {
1094 EnsureState(State
.HaveProcessInfo
);
1095 int count
= processInfo
.threadInfoList
.Count
;
1096 ProcessThread
[] newThreadsArray
= new ProcessThread
[count
];
1097 for (int i
= 0; i
< count
; i
++) {
1098 newThreadsArray
[i
] = new ProcessThread(isRemoteMachine
, (ThreadInfo
)processInfo
.threadInfoList
[i
]);
1100 ProcessThreadCollection newThreads
= new ProcessThreadCollection(newThreadsArray
);
1101 threads
= newThreads
;
1109 /// Returns the amount of time the associated process has spent utilizing the CPU.
1110 /// It is the sum of the <see cref='System.Diagnostics.Process.UserProcessorTime'/> and
1111 /// <see cref='System.Diagnostics.Process.PrivilegedProcessorTime'/>.
1113 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessTotalProcessorTime
)]
1114 public TimeSpan TotalProcessorTime
{
1116 EnsureState(State
.IsNt
);
1117 return GetProcessTimes().TotalProcessorTime
;
1122 /// Returns the amount of time the associated process has spent running code
1123 /// inside the application portion of the process (not the operating system core).
1125 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessUserProcessorTime
)]
1126 public TimeSpan UserProcessorTime
{
1128 EnsureState(State
.IsNt
);
1129 return GetProcessTimes().UserProcessorTime
;
1135 /// Returns the amount of virtual memory that the associated process has requested.
1137 [Obsolete("This property has been deprecated. Please use System.Diagnostics.Process.VirtualMemorySize64 instead. http://go.microsoft.com/fwlink/?linkid=14202")]
1138 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessVirtualMemorySize
)]
1139 public int VirtualMemorySize
{
1141 EnsureState(State
.HaveNtProcessInfo
);
1142 return unchecked((int)processInfo
.virtualBytes
);
1147 #endif // !FEATURE_PAL
1150 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessVirtualMemorySize
)]
1151 [System
.Runtime
.InteropServices
.ComVisible(false)]
1152 public long VirtualMemorySize64
{
1154 EnsureState(State
.HaveNtProcessInfo
);
1155 return processInfo
.virtualBytes
;
1162 /// Gets or sets whether the <see cref='System.Diagnostics.Process.Exited'/>
1164 /// when the process terminates.
1167 [Browsable(false), DefaultValue(false), MonitoringDescription(SR
.ProcessEnableRaisingEvents
)]
1168 public bool EnableRaisingEvents
{
1170 return watchForExit
;
1173 if (value != watchForExit
) {
1176 OpenProcessHandle();
1177 EnsureWatchingForExit();
1180 StopWatchingForExit();
1183 watchForExit
= value;
1188 #if MONO_FEATURE_PROCESS_START
1190 /// <para>[To be supplied.]</para>
1192 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessStandardInput
)]
1193 public StreamWriter StandardInput
{
1195 if (standardInput
== null) {
1196 throw new InvalidOperationException(SR
.GetString(SR
.CantGetStandardIn
));
1200 inputStreamReadMode
= StreamReadMode
.syncMode
;
1202 return standardInput
;
1207 /// <para>[To be supplied.]</para>
1209 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessStandardOutput
)]
1210 public StreamReader StandardOutput
{
1212 if (standardOutput
== null) {
1213 throw new InvalidOperationException(SR
.GetString(SR
.CantGetStandardOut
));
1216 if(outputStreamReadMode
== StreamReadMode
.undefined
) {
1217 outputStreamReadMode
= StreamReadMode
.syncMode
;
1219 else if (outputStreamReadMode
!= StreamReadMode
.syncMode
) {
1220 throw new InvalidOperationException(SR
.GetString(SR
.CantMixSyncAsyncOperation
));
1223 return standardOutput
;
1228 /// <para>[To be supplied.]</para>
1230 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessStandardError
)]
1231 public StreamReader StandardError
{
1233 if (standardError
== null) {
1234 throw new InvalidOperationException(SR
.GetString(SR
.CantGetStandardError
));
1237 if(errorStreamReadMode
== StreamReadMode
.undefined
) {
1238 errorStreamReadMode
= StreamReadMode
.syncMode
;
1240 else if (errorStreamReadMode
!= StreamReadMode
.syncMode
) {
1241 throw new InvalidOperationException(SR
.GetString(SR
.CantMixSyncAsyncOperation
));
1244 return standardError
;
1249 #if !FEATURE_PAL && !MONO
1251 /// Returns the total amount of physical memory the associated process.
1253 [Obsolete("This property has been deprecated. Please use System.Diagnostics.Process.WorkingSet64 instead. http://go.microsoft.com/fwlink/?linkid=14202")]
1254 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessWorkingSet
)]
1255 public int WorkingSet
{
1257 EnsureState(State
.HaveNtProcessInfo
);
1258 return unchecked((int)processInfo
.workingSet
);
1261 #endif // !FEATURE_PAL && !MONO
1264 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
), MonitoringDescription(SR
.ProcessWorkingSet
)]
1265 [System
.Runtime
.InteropServices
.ComVisible(false)]
1266 public long WorkingSet64
{
1268 EnsureState(State
.HaveNtProcessInfo
);
1269 return processInfo
.workingSet
;
1274 [Category("Behavior"), MonitoringDescription(SR
.ProcessExited
)]
1275 public event EventHandler Exited
{
1284 #if !FEATURE_PAL && !MONO
1287 /// Closes a process that has a user interface by sending a close message
1288 /// to its main window.
1291 [ResourceExposure(ResourceScope
.Machine
)] // Review usages of this.
1292 [ResourceConsumption(ResourceScope
.Machine
)]
1293 public bool CloseMainWindow() {
1294 IntPtr mainWindowHandle
= MainWindowHandle
;
1295 if (mainWindowHandle
== (IntPtr
)0) return false;
1296 int style
= NativeMethods
.GetWindowLong(new HandleRef(this, mainWindowHandle
), NativeMethods
.GWL_STYLE
);
1297 if ((style
& NativeMethods
.WS_DISABLED
) != 0) return false;
1298 NativeMethods
.PostMessage(new HandleRef(this, mainWindowHandle
), NativeMethods
.WM_CLOSE
, IntPtr
.Zero
, IntPtr
.Zero
);
1301 #endif // !FEATURE_PAL && !MONO
1304 /// Release the temporary handle we used to get process information.
1305 /// If we used the process handle stored in the process object (we have all access to the handle,) don't release it.
1308 void ReleaseProcessHandle(SafeProcessHandle handle
) {
1309 if (handle
== null) {
1313 if (haveProcessHandle
&& handle
== m_processHandle
) {
1316 Debug
.WriteLineIf(processTracing
.TraceVerbose
, "Process - CloseHandle(process)");
1321 /// This is called from the threadpool when a proces exits.
1324 private void CompletionCallback(object context
, bool wasSignaled
) {
1325 StopWatchingForExit();
1332 /// Free any resources associated with this component.
1335 protected override void Dispose(bool disposing
) {
1338 //Dispose managed and unmanaged resources
1341 this.disposed
= true;
1342 base.Dispose(disposing
);
1348 /// Frees any resources associated with this component.
1351 public void Close() {
1353 if (haveProcessHandle
) {
1354 StopWatchingForExit();
1355 Debug
.WriteLineIf(processTracing
.TraceVerbose
, "Process - CloseHandle(process) in Close()");
1356 m_processHandle
.Close();
1357 m_processHandle
= null;
1358 haveProcessHandle
= false;
1360 haveProcessId
= false;
1361 isRemoteMachine
= false;
1363 raisedOnExited
= false;
1366 //Call close on streams if the user never saw them.
1367 //A stream in the undefined mode was never fetched by the user.
1368 //A stream in the async mode is wrapped on a AsyncStreamReader and we should dispose that instead.
1369 // no way for users to get a hand on a AsyncStreamReader.
1370 var tmpIn
= standardInput
;
1371 standardInput
= null;
1372 if (inputStreamReadMode
== StreamReadMode
.undefined
&& tmpIn
!= null)
1375 var tmpOut
= standardOutput
;
1376 standardOutput
= null;
1377 if (outputStreamReadMode
== StreamReadMode
.undefined
&& tmpOut
!= null)
1380 tmpOut
= standardError
;
1381 standardError
= null;
1382 if (errorStreamReadMode
== StreamReadMode
.undefined
&& tmpOut
!= null)
1385 var tmpAsync
= output
;
1387 if (outputStreamReadMode
== StreamReadMode
.asyncMode
&& tmpAsync
!= null) {
1388 tmpAsync
.CancelOperation ();
1394 if (errorStreamReadMode
== StreamReadMode
.asyncMode
&& tmpAsync
!= null) {
1395 tmpAsync
.CancelOperation ();
1399 //Don't call close on the Readers and writers
1400 //since they might be referenced by somebody else while the
1401 //process is still alive but this method called.
1402 standardOutput
= null;
1403 standardInput
= null;
1404 standardError
= null;
1416 /// Helper method for checking preconditions when accessing properties.
1419 [ResourceExposure(ResourceScope
.None
)]
1420 [ResourceConsumption(ResourceScope
.Machine
, ResourceScope
.Machine
)]
1421 void EnsureState(State state
) {
1424 if ((state
& State
.IsWin2k
) != (State
)0) {
1426 if (OperatingSystem
.Platform
!= PlatformID
.Win32NT
|| OperatingSystem
.Version
.Major
< 5)
1427 #endif // !FEATURE_PAL
1428 throw new PlatformNotSupportedException(SR
.GetString(SR
.Win2kRequired
));
1431 if ((state
& State
.IsNt
) != (State
)0) {
1433 if (OperatingSystem
.Platform
!= PlatformID
.Win32NT
)
1434 #endif // !FEATURE_PAL
1435 throw new PlatformNotSupportedException(SR
.GetString(SR
.WinNTRequired
));
1439 if ((state
& State
.Associated
) != (State
)0)
1441 throw new InvalidOperationException(SR
.GetString(SR
.NoAssociatedProcess
));
1443 if ((state
& State
.HaveId
) != (State
)0) {
1444 if (!haveProcessId
) {
1445 #if !FEATURE_PAL && !MONO
1446 if (haveProcessHandle
) {
1447 SetProcessId(ProcessManager
.GetProcessIdFromHandle(m_processHandle
));
1450 EnsureState(State
.Associated
);
1451 throw new InvalidOperationException(SR
.GetString(SR
.ProcessIdRequired
));
1454 EnsureState(State
.Associated
);
1455 throw new InvalidOperationException(SR
.GetString(SR
.ProcessIdRequired
));
1456 #endif // !FEATURE_PAL && !MONO
1460 if ((state
& State
.IsLocal
) != (State
)0 && isRemoteMachine
) {
1461 throw new NotSupportedException(SR
.GetString(SR
.NotSupportedRemote
));
1464 if ((state
& State
.HaveProcessInfo
) != (State
)0) {
1465 #if !FEATURE_PAL && !MONO
1466 if (processInfo
== null) {
1467 if ((state
& State
.HaveId
) == (State
)0) EnsureState(State
.HaveId
);
1468 ProcessInfo
[] processInfos
= ProcessManager
.GetProcessInfos(machineName
);
1469 for (int i
= 0; i
< processInfos
.Length
; i
++) {
1470 if (processInfos
[i
].processId
== processId
) {
1471 this.processInfo
= processInfos
[i
];
1475 if (processInfo
== null) {
1476 throw new InvalidOperationException(SR
.GetString(SR
.NoProcessInfo
));
1480 throw new InvalidOperationException(SR
.GetString(SR
.NoProcessInfo
));
1481 #endif // !FEATURE_PAL && !MONO
1484 if ((state
& State
.Exited
) != (State
)0) {
1486 throw new InvalidOperationException(SR
.GetString(SR
.WaitTillExit
));
1489 if (!haveProcessHandle
) {
1490 throw new InvalidOperationException(SR
.GetString(SR
.NoProcessHandle
));
1496 /// Make sure we are watching for a process exit.
1499 void EnsureWatchingForExit() {
1500 if (!watchingForExit
) {
1502 if (!watchingForExit
) {
1503 Debug
.Assert(haveProcessHandle
, "Process.EnsureWatchingForExit called with no process handle");
1504 Debug
.Assert(Associated
, "Process.EnsureWatchingForExit called with no associated process");
1505 watchingForExit
= true;
1507 this.waitHandle
= new ProcessWaitHandle(m_processHandle
);
1508 this.registeredWaitHandle
= ThreadPool
.RegisterWaitForSingleObject(this.waitHandle
,
1509 new WaitOrTimerCallback(this.CompletionCallback
), null, -1, true);
1512 watchingForExit
= false;
1523 /// Make sure we have obtained the min and max working set limits.
1526 void EnsureWorkingSetLimits() {
1527 EnsureState(State
.IsNt
);
1528 if (!haveWorkingSetLimits
) {
1529 SafeProcessHandle handle
= null;
1531 handle
= GetProcessHandle(NativeMethods
.PROCESS_QUERY_INFORMATION
);
1534 if (!NativeMethods
.GetProcessWorkingSetSize(handle
, out min
, out max
)) {
1535 throw new Win32Exception();
1537 minWorkingSet
= min
;
1538 maxWorkingSet
= max
;
1539 haveWorkingSetLimits
= true;
1542 ReleaseProcessHandle(handle
);
1547 public static void EnterDebugMode() {
1549 if (ProcessManager
.IsNt
) {
1550 SetPrivilege("SeDebugPrivilege", NativeMethods
.SE_PRIVILEGE_ENABLED
);
1556 [ResourceExposure(ResourceScope
.None
)]
1557 [ResourceConsumption(ResourceScope
.Process
, ResourceScope
.Process
)]
1558 private static void SetPrivilege(string privilegeName
, int attrib
) {
1559 IntPtr hToken
= (IntPtr
)0;
1560 NativeMethods
.LUID debugValue
= new NativeMethods
.LUID();
1562 // this is only a "pseudo handle" to the current process - no need to close it later
1563 IntPtr processHandle
= NativeMethods
.GetCurrentProcess();
1565 // get the process token so we can adjust the privilege on it. We DO need to
1566 // close the token when we're done with it.
1567 if (!NativeMethods
.OpenProcessToken(new HandleRef(null, processHandle
), NativeMethods
.TOKEN_ADJUST_PRIVILEGES
, out hToken
)) {
1568 throw new Win32Exception();
1572 if (!NativeMethods
.LookupPrivilegeValue(null, privilegeName
, out debugValue
)) {
1573 throw new Win32Exception();
1576 NativeMethods
.TokenPrivileges tkp
= new NativeMethods
.TokenPrivileges();
1577 tkp
.Luid
= debugValue
;
1578 tkp
.Attributes
= attrib
;
1580 NativeMethods
.AdjustTokenPrivileges(new HandleRef(null, hToken
), false, tkp
, 0, IntPtr
.Zero
, IntPtr
.Zero
);
1582 // AdjustTokenPrivileges can return true even if it failed to
1583 // set the privilege, so we need to use GetLastError
1584 if (Marshal
.GetLastWin32Error() != NativeMethods
.ERROR_SUCCESS
) {
1585 throw new Win32Exception();
1589 Debug
.WriteLineIf(processTracing
.TraceVerbose
, "Process - CloseHandle(processToken)");
1590 SafeNativeMethods
.CloseHandle(hToken
);
1596 /// <para>[To be supplied.]</para>
1598 public static void LeaveDebugMode() {
1600 if (ProcessManager
.IsNt
) {
1601 SetPrivilege("SeDebugPrivilege", 0);
1609 /// Returns a new <see cref='System.Diagnostics.Process'/> component given a process identifier and
1610 /// the name of a computer in the network.
1613 [ResourceExposure(ResourceScope
.Machine
)]
1614 [ResourceConsumption(ResourceScope
.Machine
)]
1615 public static Process
GetProcessById(int processId
, string machineName
) {
1616 if (!ProcessManager
.IsProcessRunning(processId
, machineName
)) {
1617 throw new ArgumentException(SR
.GetString(SR
.MissingProccess
, processId
.ToString(CultureInfo
.CurrentCulture
)));
1620 return new Process(machineName
, ProcessManager
.IsRemoteMachine(machineName
), processId
, null);
1626 /// Returns a new <see cref='System.Diagnostics.Process'/> component given the
1627 /// identifier of a process on the local computer.
1630 [ResourceExposure(ResourceScope
.Machine
)]
1631 [ResourceConsumption(ResourceScope
.Machine
)]
1632 public static Process
GetProcessById(int processId
) {
1633 return GetProcessById(processId
, ".");
1638 /// Creates an array of <see cref='System.Diagnostics.Process'/> components that are
1640 /// with process resources on the
1641 /// local computer. These process resources share the specified process name.
1644 [ResourceExposure(ResourceScope
.Machine
)]
1645 [ResourceConsumption(ResourceScope
.Machine
)]
1646 public static Process
[] GetProcessesByName(string processName
) {
1647 return GetProcessesByName(processName
, ".");
1653 /// Creates an array of <see cref='System.Diagnostics.Process'/> components that are associated with process resources on a
1654 /// remote computer. These process resources share the specified process name.
1657 [ResourceExposure(ResourceScope
.Machine
)]
1658 [ResourceConsumption(ResourceScope
.Machine
)]
1659 public static Process
[] GetProcessesByName(string processName
, string machineName
) {
1660 if (processName
== null) processName
= String
.Empty
;
1661 Process
[] procs
= GetProcesses(machineName
);
1662 ArrayList list
= new ArrayList();
1664 for(int i
= 0; i
< procs
.Length
; i
++) {
1665 if( String
.Equals(processName
, procs
[i
].ProcessName
, StringComparison
.OrdinalIgnoreCase
)) {
1666 list
.Add( procs
[i
]);
1672 Process
[] temp
= new Process
[list
.Count
];
1673 list
.CopyTo(temp
, 0);
1680 /// Creates a new <see cref='System.Diagnostics.Process'/>
1681 /// component for each process resource on the local computer.
1684 [ResourceExposure(ResourceScope
.Machine
)]
1685 [ResourceConsumption(ResourceScope
.Machine
)]
1686 public static Process
[] GetProcesses() {
1687 return GetProcesses(".");
1693 /// Creates a new <see cref='System.Diagnostics.Process'/>
1694 /// component for each
1695 /// process resource on the specified computer.
1698 [ResourceExposure(ResourceScope
.Machine
)]
1699 [ResourceConsumption(ResourceScope
.Machine
)]
1700 public static Process
[] GetProcesses(string machineName
) {
1701 bool isRemoteMachine
= ProcessManager
.IsRemoteMachine(machineName
);
1702 ProcessInfo
[] processInfos
= ProcessManager
.GetProcessInfos(machineName
);
1703 Process
[] processes
= new Process
[processInfos
.Length
];
1704 for (int i
= 0; i
< processInfos
.Length
; i
++) {
1705 ProcessInfo processInfo
= processInfos
[i
];
1706 processes
[i
] = new Process(machineName
, isRemoteMachine
, processInfo
.processId
, processInfo
);
1708 Debug
.WriteLineIf(processTracing
.TraceVerbose
, "Process.GetProcesses(" + machineName
+ ")");
1710 if (processTracing
.TraceVerbose
) {
1712 for (int i
= 0; i
< processInfos
.Length
; i
++) {
1713 Debug
.WriteLine(processes
[i
].Id
+ ": " + processes
[i
].ProcessName
);
1722 #endif // !FEATURE_PAL
1726 /// Returns a new <see cref='System.Diagnostics.Process'/>
1727 /// component and associates it with the current active process.
1730 [ResourceExposure(ResourceScope
.Process
)]
1731 [ResourceConsumption(ResourceScope
.Machine
, ResourceScope
.Process
)]
1732 public static Process
GetCurrentProcess() {
1733 return new Process(".", false, NativeMethods
.GetCurrentProcessId(), null);
1738 /// Raises the <see cref='System.Diagnostics.Process.Exited'/> event.
1741 protected void OnExited() {
1742 EventHandler exited
= onExited
;
1743 if (exited
!= null) {
1744 if (this.SynchronizingObject
!= null && this.SynchronizingObject
.InvokeRequired
)
1745 this.SynchronizingObject
.BeginInvoke(exited
, new object[]{this, EventArgs.Empty}
);
1747 exited(this, EventArgs
.Empty
);
1752 /// Gets a short-term handle to the process, with the given access.
1753 /// If a handle is stored in current process object, then use it.
1754 /// Note that the handle we stored in current process object will have all access we need.
1757 [ResourceExposure(ResourceScope
.None
)]
1758 [ResourceConsumption(ResourceScope
.Machine
, ResourceScope
.Machine
)]
1759 SafeProcessHandle
GetProcessHandle(int access
, bool throwIfExited
) {
1760 Debug
.WriteLineIf(processTracing
.TraceVerbose
, "GetProcessHandle(access = 0x" + access
.ToString("X8", CultureInfo
.InvariantCulture
) + ", throwIfExited = " + throwIfExited
+ ")");
1762 if (processTracing
.TraceVerbose
) {
1763 StackFrame calledFrom
= new StackTrace(true).GetFrame(0);
1764 Debug
.WriteLine(" called from " + calledFrom
.GetFileName() + ", line " + calledFrom
.GetFileLineNumber());
1767 if (haveProcessHandle
) {
1768 if (throwIfExited
) {
1769 // Since haveProcessHandle is true, we know we have the process handle
1770 // open with at least SYNCHRONIZE access, so we can wait on it with
1771 // zero timeout to see if the process has exited.
1772 ProcessWaitHandle waitHandle
= null;
1774 waitHandle
= new ProcessWaitHandle(m_processHandle
);
1775 if (waitHandle
.WaitOne(0, false)) {
1777 throw new InvalidOperationException(SR
.GetString(SR
.ProcessHasExited
, processId
.ToString(CultureInfo
.CurrentCulture
)));
1779 throw new InvalidOperationException(SR
.GetString(SR
.ProcessHasExitedNoId
));
1783 if( waitHandle
!= null) {
1788 return m_processHandle
;
1791 EnsureState(State
.HaveId
| State
.IsLocal
);
1792 SafeProcessHandle handle
= SafeProcessHandle
.InvalidHandle
;
1793 #if !FEATURE_PAL && !MONO
1794 handle
= ProcessManager
.OpenProcess(processId
, access
, throwIfExited
);
1796 IntPtr pseudohandle
= NativeMethods
.GetCurrentProcess();
1797 // Get a real handle
1798 if (!NativeMethods
.DuplicateHandle (new HandleRef(this, pseudohandle
),
1799 new HandleRef(this, pseudohandle
),
1800 new HandleRef(this, pseudohandle
),
1804 NativeMethods
.DUPLICATE_SAME_ACCESS
|
1805 NativeMethods
.DUPLICATE_CLOSE_SOURCE
)) {
1806 throw new Win32Exception();
1808 #endif // !FEATURE_PAL && !MONO
1809 if (throwIfExited
&& (access
& NativeMethods
.PROCESS_QUERY_INFORMATION
) != 0) {
1810 if (NativeMethods
.GetExitCodeProcess(handle
, out exitCode
) && exitCode
!= NativeMethods
.STILL_ACTIVE
) {
1811 throw new InvalidOperationException(SR
.GetString(SR
.ProcessHasExited
, processId
.ToString(CultureInfo
.CurrentCulture
)));
1820 /// Gets a short-term handle to the process, with the given access. If a handle exists,
1821 /// then it is reused. If the process has exited, it throws an exception.
1824 SafeProcessHandle
GetProcessHandle(int access
) {
1825 return GetProcessHandle(access
, true);
1829 /// Opens a long-term handle to the process, with all access. If a handle exists,
1830 /// then it is reused. If the process has exited, it throws an exception.
1833 SafeProcessHandle
OpenProcessHandle() {
1834 return OpenProcessHandle(NativeMethods
.PROCESS_ALL_ACCESS
);
1837 SafeProcessHandle
OpenProcessHandle(Int32 access
) {
1838 if (!haveProcessHandle
) {
1839 //Cannot open a new process handle if the object has been disposed, since finalization has been suppressed.
1840 if (this.disposed
) {
1841 throw new ObjectDisposedException(GetType().Name
);
1844 SetProcessHandle(GetProcessHandle(access
));
1846 return m_processHandle
;
1851 /// Raise the Exited event, but make sure we don't do it more than once.
1854 void RaiseOnExited() {
1855 if (!raisedOnExited
) {
1857 if (!raisedOnExited
) {
1858 raisedOnExited
= true;
1868 /// Discards any information about the associated process
1869 /// that has been cached inside the process component. After <see cref='System.Diagnostics.Process.Refresh'/> is called, the
1870 /// first request for information for each property causes the process component
1871 /// to obtain a new value from the associated process.
1874 public void Refresh() {
1881 #endif // !FEATURE_PAL
1883 mainWindowTitle
= null;
1888 haveMainWindow
= false;
1890 haveWorkingSetLimits
= false;
1892 haveProcessorAffinity
= false;
1894 havePriorityClass
= false;
1895 haveExitTime
= false;
1897 haveResponding
= false;
1898 havePriorityBoostEnabled
= false;
1903 /// Helper to associate a process handle with this component.
1906 void SetProcessHandle(SafeProcessHandle processHandle
) {
1907 this.m_processHandle
= processHandle
;
1908 this.haveProcessHandle
= true;
1910 EnsureWatchingForExit();
1915 /// Helper to associate a process id with this component.
1918 [ResourceExposure(ResourceScope
.Machine
)]
1919 void SetProcessId(int processId
) {
1920 this.processId
= processId
;
1921 this.haveProcessId
= true;
1927 /// Helper to set minimum or maximum working set limits.
1930 [ResourceExposure(ResourceScope
.Process
)]
1931 [ResourceConsumption(ResourceScope
.Machine
, ResourceScope
.Machine
)]
1932 void SetWorkingSetLimits(object newMin
, object newMax
) {
1933 EnsureState(State
.IsNt
);
1935 SafeProcessHandle handle
= null;
1937 handle
= GetProcessHandle(NativeMethods
.PROCESS_QUERY_INFORMATION
| NativeMethods
.PROCESS_SET_QUOTA
);
1940 if (!NativeMethods
.GetProcessWorkingSetSize(handle
, out min
, out max
)) {
1941 throw new Win32Exception();
1944 if (newMin
!= null) {
1945 min
= (IntPtr
)newMin
;
1948 if (newMax
!= null) {
1949 max
= (IntPtr
)newMax
;
1952 if ((long)min
> (long)max
) {
1953 if (newMin
!= null) {
1954 throw new ArgumentException(SR
.GetString(SR
.BadMinWorkset
));
1957 throw new ArgumentException(SR
.GetString(SR
.BadMaxWorkset
));
1961 if (!NativeMethods
.SetProcessWorkingSetSize(handle
, min
, max
)) {
1962 throw new Win32Exception();
1965 // The value may be rounded/changed by the OS, so go get it
1966 if (!NativeMethods
.GetProcessWorkingSetSize(handle
, out min
, out max
)) {
1967 throw new Win32Exception();
1969 minWorkingSet
= min
;
1970 maxWorkingSet
= max
;
1971 haveWorkingSetLimits
= true;
1974 ReleaseProcessHandle(handle
);
1978 #endif // !FEATURE_PAL
1980 #if MONO_FEATURE_PROCESS_START
1984 /// Starts a process specified by the <see cref='System.Diagnostics.Process.StartInfo'/> property of this <see cref='System.Diagnostics.Process'/>
1985 /// component and associates it with the
1986 /// <see cref='System.Diagnostics.Process'/> . If a process resource is reused
1987 /// rather than started, the reused process is associated with this <see cref='System.Diagnostics.Process'/>
1991 [ResourceExposure(ResourceScope
.None
)]
1992 [ResourceConsumption(ResourceScope
.Machine
, ResourceScope
.Machine
)]
1993 public bool Start() {
1995 ProcessStartInfo startInfo
= StartInfo
;
1996 if (startInfo
.FileName
.Length
== 0)
1997 throw new InvalidOperationException(SR
.GetString(SR
.FileNameMissing
));
1999 if (startInfo
.UseShellExecute
) {
2001 return StartWithShellExecuteEx(startInfo
);
2003 throw new InvalidOperationException(SR
.GetString(SR
.net_perm_invalid_val
, "StartInfo.UseShellExecute", true));
2004 #endif // !FEATURE_PAL
2006 return StartWithCreateProcess(startInfo
);
2011 [ResourceExposure(ResourceScope
.Process
)]
2012 [ResourceConsumption(ResourceScope
.Process
)]
2013 private static void CreatePipeWithSecurityAttributes(out SafeFileHandle hReadPipe
, out SafeFileHandle hWritePipe
, NativeMethods
.SECURITY_ATTRIBUTES lpPipeAttributes
, int nSize
) {
2014 bool ret
= NativeMethods
.CreatePipe(out hReadPipe
, out hWritePipe
, lpPipeAttributes
, nSize
);
2015 if (!ret
|| hReadPipe
.IsInvalid
|| hWritePipe
.IsInvalid
) {
2016 throw new Win32Exception();
2020 // Using synchronous Anonymous pipes for process input/output redirection means we would end up
2021 // wasting a worker threadpool thread per pipe instance. Overlapped pipe IO is desirable, since
2022 // it will take advantage of the NT IO completion port infrastructure. But we can't really use
2023 // Overlapped I/O for process input/output as it would break Console apps (managed Console class
2024 // methods such as WriteLine as well as native CRT functions like printf) which are making an
2025 // assumption that the console standard handles (obtained via GetStdHandle()) are opened
2026 // for synchronous I/O and hence they can work fine with ReadFile/WriteFile synchrnously!
2027 [ResourceExposure(ResourceScope
.None
)]
2028 [ResourceConsumption(ResourceScope
.Machine
, ResourceScope
.Machine
)]
2029 private void CreatePipe(out SafeFileHandle parentHandle
, out SafeFileHandle childHandle
, bool parentInputs
) {
2030 NativeMethods
.SECURITY_ATTRIBUTES securityAttributesParent
= new NativeMethods
.SECURITY_ATTRIBUTES();
2031 securityAttributesParent
.bInheritHandle
= true;
2033 SafeFileHandle hTmp
= null;
2036 CreatePipeWithSecurityAttributes(out childHandle
, out hTmp
, securityAttributesParent
, 0);
2039 CreatePipeWithSecurityAttributes(out hTmp
,
2041 securityAttributesParent
,
2044 // Duplicate the parent handle to be non-inheritable so that the child process
2045 // doesn't have access. This is done for correctness sake, exact reason is unclear.
2046 // One potential theory is that child process can do something brain dead like
2047 // closing the parent end of the pipe and there by getting into a blocking situation
2048 // as parent will not be draining the pipe at the other end anymore.
2049 if (!NativeMethods
.DuplicateHandle(new HandleRef(this, NativeMethods
.GetCurrentProcess()),
2051 new HandleRef(this, NativeMethods
.GetCurrentProcess()),
2055 NativeMethods
.DUPLICATE_SAME_ACCESS
)) {
2056 throw new Win32Exception();
2060 if( hTmp
!= null && !hTmp
.IsInvalid
) {
2066 private static StringBuilder
BuildCommandLine(string executableFileName
, string arguments
) {
2067 // Construct a StringBuilder with the appropriate command line
2068 // to pass to CreateProcess. If the filename isn't already
2069 // in quotes, we quote it here. This prevents some security
2070 // problems (it specifies exactly which part of the string
2071 // is the file to execute).
2072 StringBuilder commandLine
= new StringBuilder();
2073 string fileName
= executableFileName
.Trim();
2074 bool fileNameIsQuoted
= (fileName
.StartsWith("\"", StringComparison
.Ordinal
) && fileName
.EndsWith("\"", StringComparison
.Ordinal
));
2075 if (!fileNameIsQuoted
) {
2076 commandLine
.Append("\"");
2079 commandLine
.Append(fileName
);
2081 if (!fileNameIsQuoted
) {
2082 commandLine
.Append("\"");
2085 if (!String
.IsNullOrEmpty(arguments
)) {
2086 commandLine
.Append(" ");
2087 commandLine
.Append(arguments
);
2093 [ResourceExposure(ResourceScope
.Machine
)]
2094 [ResourceConsumption(ResourceScope
.Machine
)]
2095 private bool StartWithCreateProcess(ProcessStartInfo startInfo
) {
2096 if( startInfo
.StandardOutputEncoding
!= null && !startInfo
.RedirectStandardOutput
) {
2097 throw new InvalidOperationException(SR
.GetString(SR
.StandardOutputEncodingNotAllowed
));
2100 if( startInfo
.StandardErrorEncoding
!= null && !startInfo
.RedirectStandardError
) {
2101 throw new InvalidOperationException(SR
.GetString(SR
.StandardErrorEncodingNotAllowed
));
2104 if (!string.IsNullOrEmpty(startInfo
.Arguments
) && startInfo
.ArgumentList
.Count
> 0)
2105 throw new InvalidOperationException(SR
.ArgumentAndArgumentListInitialized
);
2107 // See knowledge base article Q190351 for an explanation of the following code. Noteworthy tricky points:
2108 // * The handles are duplicated as non-inheritable before they are passed to CreateProcess so
2109 // that the child process can not close them
2110 // * CreateProcess allows you to redirect all or none of the standard IO handles, so we use
2111 // GetStdHandle for the handles that are not being redirected
2113 //Cannot start a new process and store its handle if the object has been disposed, since finalization has been suppressed.
2114 if (this.disposed
) {
2115 throw new ObjectDisposedException(GetType().Name
);
2119 if (startInfo
.ArgumentList
.Count
> 0) {
2120 StringBuilder sb
= new StringBuilder ();
2121 Process
.AppendArguments (sb
, startInfo
.ArgumentList
);
2122 arguments
= sb
.ToString ();
2125 arguments
= startInfo
.Arguments
;
2128 StringBuilder commandLine
= BuildCommandLine(startInfo
.FileName
, arguments
);
2130 NativeMethods
.STARTUPINFO startupInfo
= new NativeMethods
.STARTUPINFO();
2131 SafeNativeMethods
.PROCESS_INFORMATION processInfo
= new SafeNativeMethods
.PROCESS_INFORMATION();
2132 SafeProcessHandle procSH
= new SafeProcessHandle();
2133 SafeThreadHandle threadSH
= new SafeThreadHandle();
2136 // handles used in parent process
2137 SafeFileHandle standardInputWritePipeHandle
= null;
2138 SafeFileHandle standardOutputReadPipeHandle
= null;
2139 SafeFileHandle standardErrorReadPipeHandle
= null;
2140 GCHandle environmentHandle
= new GCHandle();
2141 lock (s_CreateProcessLock
) {
2143 // set up the streams
2144 if (startInfo
.RedirectStandardInput
|| startInfo
.RedirectStandardOutput
|| startInfo
.RedirectStandardError
) {
2145 if (startInfo
.RedirectStandardInput
) {
2146 CreatePipe(out standardInputWritePipeHandle
, out startupInfo
.hStdInput
, true);
2148 startupInfo
.hStdInput
= new SafeFileHandle(NativeMethods
.GetStdHandle(NativeMethods
.STD_INPUT_HANDLE
), false);
2151 if (startInfo
.RedirectStandardOutput
) {
2152 CreatePipe(out standardOutputReadPipeHandle
, out startupInfo
.hStdOutput
, false);
2154 startupInfo
.hStdOutput
= new SafeFileHandle(NativeMethods
.GetStdHandle(NativeMethods
.STD_OUTPUT_HANDLE
), false);
2157 if (startInfo
.RedirectStandardError
) {
2158 CreatePipe(out standardErrorReadPipeHandle
, out startupInfo
.hStdError
, false);
2160 startupInfo
.hStdError
= new SafeFileHandle(NativeMethods
.GetStdHandle(NativeMethods
.STD_ERROR_HANDLE
), false);
2163 startupInfo
.dwFlags
= NativeMethods
.STARTF_USESTDHANDLES
;
2166 // set up the creation flags paramater
2167 int creationFlags
= 0;
2169 if (startInfo
.CreateNoWindow
) creationFlags
|= NativeMethods
.CREATE_NO_WINDOW
;
2170 #endif // !FEATURE_PAL
2172 // set up the environment block parameter
2173 IntPtr environmentPtr
= (IntPtr
)0;
2174 if (startInfo
.environmentVariables
!= null) {
2175 bool unicode
= false;
2177 if (ProcessManager
.IsNt
) {
2178 creationFlags
|= NativeMethods
.CREATE_UNICODE_ENVIRONMENT
;
2181 #endif // !FEATURE_PAL
2183 byte[] environmentBytes
= EnvironmentBlock
.ToByteArray(startInfo
.environmentVariables
, unicode
);
2184 environmentHandle
= GCHandle
.Alloc(environmentBytes
, GCHandleType
.Pinned
);
2185 environmentPtr
= environmentHandle
.AddrOfPinnedObject();
2188 string workingDirectory
= startInfo
.WorkingDirectory
;
2189 if (workingDirectory
== string.Empty
)
2190 workingDirectory
= Environment
.CurrentDirectory
;
2193 if (startInfo
.UserName
.Length
!= 0) {
2194 if (startInfo
.Password
!= null && startInfo
.PasswordInClearText
!= null)
2195 throw new ArgumentException(SR
.GetString(SR
.CantSetDuplicatePassword
));
2197 NativeMethods
.LogonFlags logonFlags
= (NativeMethods
.LogonFlags
)0;
2198 if( startInfo
.LoadUserProfile
) {
2199 logonFlags
= NativeMethods
.LogonFlags
.LOGON_WITH_PROFILE
;
2202 IntPtr password
= IntPtr
.Zero
;
2204 if( startInfo
.Password
!= null) {
2205 password
= Marshal
.SecureStringToCoTaskMemUnicode(startInfo
.Password
);
2206 } else if( startInfo
.PasswordInClearText
!= null) {
2207 password
= Marshal
.StringToCoTaskMemUni(startInfo
.PasswordInClearText
);
2209 password
= Marshal
.StringToCoTaskMemUni(String
.Empty
);
2212 RuntimeHelpers
.PrepareConstrainedRegions();
2214 retVal
= NativeMethods
.CreateProcessWithLogonW(
2219 null, // we don't need this since all the info is in commandLine
2224 startupInfo
, // pointer to STARTUPINFO
2225 processInfo
// pointer to PROCESS_INFORMATION
2228 errorCode
= Marshal
.GetLastWin32Error();
2229 if ( processInfo
.hProcess
!= (IntPtr
)0 && processInfo
.hProcess
!= (IntPtr
)NativeMethods
.INVALID_HANDLE_VALUE
)
2230 procSH
.InitialSetHandle(processInfo
.hProcess
);
2231 if ( processInfo
.hThread
!= (IntPtr
)0 && processInfo
.hThread
!= (IntPtr
)NativeMethods
.INVALID_HANDLE_VALUE
)
2232 threadSH
.InitialSetHandle(processInfo
.hThread
);
2235 if (errorCode
== NativeMethods
.ERROR_BAD_EXE_FORMAT
|| errorCode
== NativeMethods
.ERROR_EXE_MACHINE_TYPE_MISMATCH
) {
2236 throw new Win32Exception(errorCode
, SR
.GetString(SR
.InvalidApplication
));
2239 throw new Win32Exception(errorCode
);
2242 if( password
!= IntPtr
.Zero
) {
2243 Marshal
.ZeroFreeCoTaskMemUnicode(password
);
2247 #endif // !FEATURE_PAL
2248 RuntimeHelpers
.PrepareConstrainedRegions();
2250 retVal
= NativeMethods
.CreateProcess (
2251 null, // we don't need this since all the info is in commandLine
2252 commandLine
, // pointer to the command line string
2253 null, // pointer to process security attributes, we don't need to inheriat the handle
2254 null, // pointer to thread security attributes
2255 true, // handle inheritance flag
2256 creationFlags
, // creation flags
2257 environmentPtr
, // pointer to new environment block
2258 workingDirectory
, // pointer to current directory name
2259 startupInfo
, // pointer to STARTUPINFO
2260 processInfo
// pointer to PROCESS_INFORMATION
2263 errorCode
= Marshal
.GetLastWin32Error();
2264 if ( processInfo
.hProcess
!= (IntPtr
)0 && processInfo
.hProcess
!= (IntPtr
)NativeMethods
.INVALID_HANDLE_VALUE
)
2265 procSH
.InitialSetHandle(processInfo
.hProcess
);
2266 if ( processInfo
.hThread
!= (IntPtr
)0 && processInfo
.hThread
!= (IntPtr
)NativeMethods
.INVALID_HANDLE_VALUE
)
2267 threadSH
.InitialSetHandle(processInfo
.hThread
);
2270 if (errorCode
== NativeMethods
.ERROR_BAD_EXE_FORMAT
|| errorCode
== NativeMethods
.ERROR_EXE_MACHINE_TYPE_MISMATCH
) {
2271 throw new Win32Exception(errorCode
, SR
.GetString(SR
.InvalidApplication
));
2273 throw new Win32Exception(errorCode
);
2279 // free environment block
2280 if (environmentHandle
.IsAllocated
) {
2281 environmentHandle
.Free();
2284 startupInfo
.Dispose();
2288 if (startInfo
.RedirectStandardInput
) {
2289 standardInput
= new StreamWriter(new FileStream(standardInputWritePipeHandle
, FileAccess
.Write
, 4096, false), Console
.InputEncoding
, 4096);
2290 standardInput
.AutoFlush
= true;
2292 if (startInfo
.RedirectStandardOutput
) {
2293 Encoding enc
= (startInfo
.StandardOutputEncoding
!= null) ? startInfo
.StandardOutputEncoding
: Console
.OutputEncoding
;
2294 standardOutput
= new StreamReader(new FileStream(standardOutputReadPipeHandle
, FileAccess
.Read
, 4096, false), enc
, true, 4096);
2296 if (startInfo
.RedirectStandardError
) {
2297 Encoding enc
= (startInfo
.StandardErrorEncoding
!= null) ? startInfo
.StandardErrorEncoding
: Console
.OutputEncoding
;
2298 standardError
= new StreamReader(new FileStream(standardErrorReadPipeHandle
, FileAccess
.Read
, 4096, false), enc
, true, 4096);
2302 if (!procSH
.IsInvalid
) {
2303 SetProcessHandle(procSH
);
2304 SetProcessId(processInfo
.dwProcessId
);
2317 [ResourceExposure(ResourceScope
.Machine
)]
2318 [ResourceConsumption(ResourceScope
.Machine
)]
2319 private bool StartWithShellExecuteEx(ProcessStartInfo startInfo
) {
2320 //Cannot start a new process and store its handle if the object has been disposed, since finalization has been suppressed.
2322 throw new ObjectDisposedException(GetType().Name
);
2324 if( !String
.IsNullOrEmpty(startInfo
.UserName
) || (startInfo
.Password
!= null) ) {
2325 throw new InvalidOperationException(SR
.GetString(SR
.CantStartAsUser
));
2328 if (startInfo
.RedirectStandardInput
|| startInfo
.RedirectStandardOutput
|| startInfo
.RedirectStandardError
) {
2329 throw new InvalidOperationException(SR
.GetString(SR
.CantRedirectStreams
));
2332 if (startInfo
.StandardErrorEncoding
!= null) {
2333 throw new InvalidOperationException(SR
.GetString(SR
.StandardErrorEncodingNotAllowed
));
2336 if (startInfo
.StandardOutputEncoding
!= null) {
2337 throw new InvalidOperationException(SR
.GetString(SR
.StandardOutputEncodingNotAllowed
));
2340 // can't set env vars with ShellExecuteEx...
2341 if (startInfo
.environmentVariables
!= null) {
2342 throw new InvalidOperationException(SR
.GetString(SR
.CantUseEnvVars
));
2345 NativeMethods
.ShellExecuteInfo shellExecuteInfo
= new NativeMethods
.ShellExecuteInfo();
2346 shellExecuteInfo
.fMask
= NativeMethods
.SEE_MASK_NOCLOSEPROCESS
;
2347 if (startInfo
.ErrorDialog
) {
2348 shellExecuteInfo
.hwnd
= startInfo
.ErrorDialogParentHandle
;
2351 shellExecuteInfo
.fMask
|= NativeMethods
.SEE_MASK_FLAG_NO_UI
;
2354 switch (startInfo
.WindowStyle
) {
2355 case ProcessWindowStyle
.Hidden
:
2356 shellExecuteInfo
.nShow
= NativeMethods
.SW_HIDE
;
2358 case ProcessWindowStyle
.Minimized
:
2359 shellExecuteInfo
.nShow
= NativeMethods
.SW_SHOWMINIMIZED
;
2361 case ProcessWindowStyle
.Maximized
:
2362 shellExecuteInfo
.nShow
= NativeMethods
.SW_SHOWMAXIMIZED
;
2365 shellExecuteInfo
.nShow
= NativeMethods
.SW_SHOWNORMAL
;
2371 if (startInfo
.FileName
.Length
!= 0)
2372 shellExecuteInfo
.lpFile
= Marshal
.StringToHGlobalAuto(startInfo
.FileName
);
2373 if (startInfo
.Verb
.Length
!= 0)
2374 shellExecuteInfo
.lpVerb
= Marshal
.StringToHGlobalAuto(startInfo
.Verb
);
2375 if (startInfo
.Arguments
.Length
!= 0)
2376 shellExecuteInfo
.lpParameters
= Marshal
.StringToHGlobalAuto(startInfo
.Arguments
);
2377 if (startInfo
.WorkingDirectory
.Length
!= 0)
2378 shellExecuteInfo
.lpDirectory
= Marshal
.StringToHGlobalAuto(startInfo
.WorkingDirectory
);
2380 shellExecuteInfo
.fMask
|= NativeMethods
.SEE_MASK_FLAG_DDEWAIT
;
2382 ShellExecuteHelper executeHelper
= new ShellExecuteHelper(shellExecuteInfo
);
2383 if (!executeHelper
.ShellExecuteOnSTAThread()) {
2384 int error
= executeHelper
.ErrorCode
;
2386 switch ((long)shellExecuteInfo
.hInstApp
) {
2387 case NativeMethods
.SE_ERR_FNF
: error
= NativeMethods
.ERROR_FILE_NOT_FOUND
; break;
2388 case NativeMethods
.SE_ERR_PNF
: error
= NativeMethods
.ERROR_PATH_NOT_FOUND
; break;
2389 case NativeMethods
.SE_ERR_ACCESSDENIED
: error
= NativeMethods
.ERROR_ACCESS_DENIED
; break;
2390 case NativeMethods
.SE_ERR_OOM
: error
= NativeMethods
.ERROR_NOT_ENOUGH_MEMORY
; break;
2391 case NativeMethods
.SE_ERR_DDEFAIL
:
2392 case NativeMethods
.SE_ERR_DDEBUSY
:
2393 case NativeMethods
.SE_ERR_DDETIMEOUT
: error
= NativeMethods
.ERROR_DDE_FAIL
; break;
2394 case NativeMethods
.SE_ERR_SHARE
: error
= NativeMethods
.ERROR_SHARING_VIOLATION
; break;
2395 case NativeMethods
.SE_ERR_NOASSOC
: error
= NativeMethods
.ERROR_NO_ASSOCIATION
; break;
2396 case NativeMethods
.SE_ERR_DLLNOTFOUND
: error
= NativeMethods
.ERROR_DLL_NOT_FOUND
; break;
2397 default: error
= (int)shellExecuteInfo
.hInstApp
; break;
2400 if( error
== NativeMethods
.ERROR_BAD_EXE_FORMAT
|| error
== NativeMethods
.ERROR_EXE_MACHINE_TYPE_MISMATCH
) {
2401 throw new Win32Exception(error
, SR
.GetString(SR
.InvalidApplication
));
2403 throw new Win32Exception(error
);
2408 if (shellExecuteInfo
.lpFile
!= (IntPtr
)0) Marshal
.FreeHGlobal(shellExecuteInfo
.lpFile
);
2409 if (shellExecuteInfo
.lpVerb
!= (IntPtr
)0) Marshal
.FreeHGlobal(shellExecuteInfo
.lpVerb
);
2410 if (shellExecuteInfo
.lpParameters
!= (IntPtr
)0) Marshal
.FreeHGlobal(shellExecuteInfo
.lpParameters
);
2411 if (shellExecuteInfo
.lpDirectory
!= (IntPtr
)0) Marshal
.FreeHGlobal(shellExecuteInfo
.lpDirectory
);
2414 if (shellExecuteInfo
.hProcess
!= (IntPtr
)0) {
2415 SafeProcessHandle handle
= new SafeProcessHandle(shellExecuteInfo
.hProcess
);
2416 SetProcessHandle(handle
);
2424 [ResourceExposure(ResourceScope
.Machine
)]
2425 [ResourceConsumption(ResourceScope
.Machine
)]
2426 public static Process
Start( string fileName
, string userName
, SecureString password
, string domain
) {
2427 ProcessStartInfo startInfo
= new ProcessStartInfo(fileName
);
2428 startInfo
.UserName
= userName
;
2429 startInfo
.Password
= password
;
2430 startInfo
.Domain
= domain
;
2431 startInfo
.UseShellExecute
= false;
2432 return Start(startInfo
);
2435 [ResourceExposure(ResourceScope
.Machine
)]
2436 [ResourceConsumption(ResourceScope
.Machine
)]
2437 public static Process
Start( string fileName
, string arguments
, string userName
, SecureString password
, string domain
) {
2438 ProcessStartInfo startInfo
= new ProcessStartInfo(fileName
, arguments
);
2439 startInfo
.UserName
= userName
;
2440 startInfo
.Password
= password
;
2441 startInfo
.Domain
= domain
;
2442 startInfo
.UseShellExecute
= false;
2443 return Start(startInfo
);
2447 #endif // !FEATURE_PAL
2451 /// Starts a process resource by specifying the name of a
2452 /// document or application file. Associates the process resource with a new <see cref='System.Diagnostics.Process'/>
2456 [ResourceExposure(ResourceScope
.Machine
)]
2457 [ResourceConsumption(ResourceScope
.Machine
)]
2458 public static Process
Start(string fileName
) {
2459 return Start(new ProcessStartInfo(fileName
));
2464 /// Starts a process resource by specifying the name of an
2465 /// application and a set of command line arguments. Associates the process resource
2466 /// with a new <see cref='System.Diagnostics.Process'/>
2470 [ResourceExposure(ResourceScope
.Machine
)]
2471 [ResourceConsumption(ResourceScope
.Machine
)]
2472 public static Process
Start(string fileName
, string arguments
) {
2473 return Start(new ProcessStartInfo(fileName
, arguments
));
2478 /// Starts a process resource specified by the process start
2479 /// information passed in, for example the file name of the process to start.
2480 /// Associates the process resource with a new <see cref='System.Diagnostics.Process'/>
2484 [ResourceExposure(ResourceScope
.Machine
)]
2485 [ResourceConsumption(ResourceScope
.Machine
)]
2486 public static Process
Start(ProcessStartInfo startInfo
) {
2487 Process process
= new Process();
2488 if (startInfo
== null) throw new ArgumentNullException("startInfo");
2489 process
.StartInfo
= startInfo
;
2490 if (process
.Start()) {
2496 #endif // MONO_FEATURE_PROCESS_START
2501 /// associated process immediately.
2504 [ResourceExposure(ResourceScope
.Machine
)]
2505 [ResourceConsumption(ResourceScope
.Machine
)]
2506 public void Kill() {
2507 SafeProcessHandle handle
= null;
2509 handle
= GetProcessHandle(NativeMethods
.PROCESS_TERMINATE
);
2510 if (!NativeMethods
.TerminateProcess(handle
, -1))
2511 throw new Win32Exception();
2514 ReleaseProcessHandle(handle
);
2519 /// Make sure we are not watching for process exit.
2522 void StopWatchingForExit() {
2523 if (watchingForExit
) {
2525 if (watchingForExit
) {
2526 watchingForExit
= false;
2527 registeredWaitHandle
.Unregister(null);
2530 registeredWaitHandle
= null;
2536 public override string ToString() {
2539 string processName
= String
.Empty
;
2541 // On windows 9x, we can't map a handle to an id.
2542 // So ProcessName will throw. We shouldn't throw in Process.ToString though.
2543 // Process.GetProcesses should be used to get all the processes on the machine.
2544 // The processes returned from it will have a nice name.
2547 processName
= this.ProcessName
;
2549 catch(PlatformNotSupportedException
) {
2551 if( processName
.Length
!= 0) {
2552 return String
.Format(CultureInfo
.CurrentCulture
, "{0} ({1})", base.ToString(), processName
);
2554 return base.ToString();
2557 #endif // !FEATURE_PAL
2558 return base.ToString();
2563 /// Instructs the <see cref='System.Diagnostics.Process'/> component to wait the specified number of milliseconds for the associated process to exit.
2566 public bool WaitForExit(int milliseconds
) {
2567 SafeProcessHandle handle
= null;
2569 ProcessWaitHandle processWaitHandle
= null;
2571 handle
= GetProcessHandle(NativeMethods
.SYNCHRONIZE
, false);
2572 if (handle
.IsInvalid
) {
2576 processWaitHandle
= new ProcessWaitHandle(handle
);
2577 if( processWaitHandle
.WaitOne(milliseconds
, false)) {
2587 // If we have a hard timeout, we cannot wait for the streams
2588 if( output
!= null && milliseconds
== -1) {
2589 output
.WaitUtilEOF();
2592 if( error
!= null && milliseconds
== -1) {
2593 error
.WaitUtilEOF();
2597 if( processWaitHandle
!= null) {
2598 processWaitHandle
.Close();
2601 ReleaseProcessHandle(handle
);
2605 if (exited
&& watchForExit
) {
2614 /// Instructs the <see cref='System.Diagnostics.Process'/> component to wait
2615 /// indefinitely for the associated process to exit.
2618 public void WaitForExit() {
2626 /// Causes the <see cref='System.Diagnostics.Process'/> component to wait the
2627 /// specified number of milliseconds for the associated process to enter an
2629 /// This is only applicable for processes with a user interface,
2630 /// therefore a message loop.
2633 public bool WaitForInputIdle(int milliseconds
) {
2634 SafeProcessHandle handle
= null;
2637 handle
= GetProcessHandle(NativeMethods
.SYNCHRONIZE
| NativeMethods
.PROCESS_QUERY_INFORMATION
);
2638 int ret
= NativeMethods
.WaitForInputIdle(handle
, milliseconds
);
2640 case NativeMethods
.WAIT_OBJECT_0
:
2643 case NativeMethods
.WAIT_TIMEOUT
:
2646 case NativeMethods
.WAIT_FAILED
:
2648 throw new InvalidOperationException(SR
.GetString(SR
.InputIdleUnkownError
));
2652 ReleaseProcessHandle(handle
);
2659 /// Instructs the <see cref='System.Diagnostics.Process'/> component to wait
2660 /// indefinitely for the associated process to enter an idle state. This
2661 /// is only applicable for processes with a user interface, therefore a message loop.
2664 public bool WaitForInputIdle() {
2665 return WaitForInputIdle(Int32
.MaxValue
);
2668 #endif // !FEATURE_PAL
2670 #if MONO_FEATURE_PROCESS_START
2671 // Support for working asynchronously with streams
2674 /// Instructs the <see cref='System.Diagnostics.Process'/> component to start
2675 /// reading the StandardOutput stream asynchronously. The user can register a callback
2676 /// that will be called when a line of data terminated by \n,\r or \r\n is reached, or the end of stream is reached
2677 /// then the remaining information is returned. The user can add an event handler to OutputDataReceived.
2680 [System
.Runtime
.InteropServices
.ComVisible(false)]
2681 public void BeginOutputReadLine() {
2683 if(outputStreamReadMode
== StreamReadMode
.undefined
) {
2684 outputStreamReadMode
= StreamReadMode
.asyncMode
;
2686 else if (outputStreamReadMode
!= StreamReadMode
.asyncMode
) {
2687 throw new InvalidOperationException(SR
.GetString(SR
.CantMixSyncAsyncOperation
));
2690 if (pendingOutputRead
)
2691 throw new InvalidOperationException(SR
.GetString(SR
.PendingAsyncOperation
));
2693 pendingOutputRead
= true;
2694 // We can't detect if there's a pending sychronous read, tream also doesn't.
2695 if (output
== null) {
2696 if (standardOutput
== null) {
2697 throw new InvalidOperationException(SR
.GetString(SR
.CantGetStandardOut
));
2700 Stream s
= standardOutput
.BaseStream
;
2701 output
= new AsyncStreamReader(this, s
, new UserCallBack(this.OutputReadNotifyUser
), standardOutput
.CurrentEncoding
);
2703 output
.BeginReadLine();
2709 /// Instructs the <see cref='System.Diagnostics.Process'/> component to start
2710 /// reading the StandardError stream asynchronously. The user can register a callback
2711 /// that will be called when a line of data terminated by \n,\r or \r\n is reached, or the end of stream is reached
2712 /// then the remaining information is returned. The user can add an event handler to ErrorDataReceived.
2715 [System
.Runtime
.InteropServices
.ComVisible(false)]
2716 public void BeginErrorReadLine() {
2718 if(errorStreamReadMode
== StreamReadMode
.undefined
) {
2719 errorStreamReadMode
= StreamReadMode
.asyncMode
;
2721 else if (errorStreamReadMode
!= StreamReadMode
.asyncMode
) {
2722 throw new InvalidOperationException(SR
.GetString(SR
.CantMixSyncAsyncOperation
));
2725 if (pendingErrorRead
) {
2726 throw new InvalidOperationException(SR
.GetString(SR
.PendingAsyncOperation
));
2729 pendingErrorRead
= true;
2730 // We can't detect if there's a pending sychronous read, stream also doesn't.
2731 if (error
== null) {
2732 if (standardError
== null) {
2733 throw new InvalidOperationException(SR
.GetString(SR
.CantGetStandardError
));
2736 Stream s
= standardError
.BaseStream
;
2737 error
= new AsyncStreamReader(this, s
, new UserCallBack(this.ErrorReadNotifyUser
), standardError
.CurrentEncoding
);
2739 error
.BeginReadLine();
2744 /// Instructs the <see cref='System.Diagnostics.Process'/> component to cancel the asynchronous operation
2745 /// specified by BeginOutputReadLine().
2748 [System
.Runtime
.InteropServices
.ComVisible(false)]
2749 public void CancelOutputRead() {
2750 if (output
!= null) {
2751 output
.CancelOperation();
2754 throw new InvalidOperationException(SR
.GetString(SR
.NoAsyncOperation
));
2757 pendingOutputRead
= false;
2762 /// Instructs the <see cref='System.Diagnostics.Process'/> component to cancel the asynchronous operation
2763 /// specified by BeginErrorReadLine().
2766 [System
.Runtime
.InteropServices
.ComVisible(false)]
2767 public void CancelErrorRead() {
2768 if (error
!= null) {
2769 error
.CancelOperation();
2772 throw new InvalidOperationException(SR
.GetString(SR
.NoAsyncOperation
));
2775 pendingErrorRead
= false;
2778 internal void OutputReadNotifyUser(String data
) {
2779 // To avoid ---- between remove handler and raising the event
2780 DataReceivedEventHandler outputDataReceived
= OutputDataReceived
;
2781 if (outputDataReceived
!= null) {
2782 DataReceivedEventArgs e
= new DataReceivedEventArgs(data
);
2783 if (SynchronizingObject
!= null && SynchronizingObject
.InvokeRequired
) {
2784 SynchronizingObject
.Invoke(outputDataReceived
, new object[] {this, e}
);
2787 outputDataReceived(this,e
); // Call back to user informing data is available.
2792 internal void ErrorReadNotifyUser(String data
) {
2793 // To avoid ---- between remove handler and raising the event
2794 DataReceivedEventHandler errorDataReceived
= ErrorDataReceived
;
2795 if (errorDataReceived
!= null) {
2796 DataReceivedEventArgs e
= new DataReceivedEventArgs(data
);
2797 if (SynchronizingObject
!= null && SynchronizingObject
.InvokeRequired
) {
2798 SynchronizingObject
.Invoke(errorDataReceived
, new object[] {this, e}
);
2801 errorDataReceived(this,e
); // Call back to user informing data is available.
2805 #endif // MONO_FEATURE_PROCESS_START
2808 /// A desired internal state.
2815 HaveProcessInfo
= 0x8,
2819 HaveNtProcessInfo
= HaveProcessInfo
| IsNt
2824 /// This data structure contains information about a process that is collected
2825 /// in bulk by querying the operating system. The reason to make this a separate
2826 /// structure from the process component is so that we can throw it away all at once
2827 /// when Refresh is called on the component.
2830 internal class ProcessInfo
{
2832 public ArrayList threadInfoList
= new ArrayList();
2833 public int basePriority
;
2834 public string processName
;
2835 public int processId
;
2836 public int handleCount
;
2837 public long poolPagedBytes
;
2838 public long poolNonpagedBytes
;
2839 public long virtualBytes
;
2840 public long virtualBytesPeak
;
2841 public long workingSetPeak
;
2842 public long workingSet
;
2843 public long pageFileBytesPeak
;
2844 public long pageFileBytes
;
2845 public long privateBytes
;
2846 public int mainModuleId
; // used only for win9x - id is only for use with CreateToolHelp32
2847 public int sessionId
;
2853 /// This data structure contains information about a thread in a process that
2854 /// is collected in bulk by querying the operating system. The reason to
2855 /// make this a separate structure from the ProcessThread component is so that we
2856 /// can throw it away all at once when Refresh is called on the component.
2859 internal class ThreadInfo
{
2860 public int threadId
;
2861 public int processId
;
2862 public int basePriority
;
2863 public int currentPriority
;
2864 public IntPtr startAddress
;
2865 public ThreadState threadState
;
2867 public ThreadWaitReason threadWaitReason
;
2868 #endif // !FEATURE_PAL
2872 /// This data structure contains information about a module in a process that
2873 /// is collected in bulk by querying the operating system. The reason to
2874 /// make this a separate structure from the ProcessModule component is so that we
2875 /// can throw it away all at once when Refresh is called on the component.
2878 internal class ModuleInfo
{
2879 public string baseName
;
2880 public string fileName
;
2881 public IntPtr baseOfDll
;
2882 public IntPtr entryPoint
;
2883 public int sizeOfImage
;
2884 public int Id
; // used only on win9x - for matching up with ProcessInfo.mainModuleId
2888 internal static class EnvironmentBlock
{
2889 public static byte[] ToByteArray(StringDictionary sd
, bool unicode
) {
2891 string[] keys
= new string[sd
.Count
];
2892 byte[] envBlock
= null;
2893 sd
.Keys
.CopyTo(keys
, 0);
2896 string[] values
= new string[sd
.Count
];
2897 sd
.Values
.CopyTo(values
, 0);
2899 // sort both by the keys
2900 // Windows 2000 requires the environment block to be sorted by the key
2901 // It will first converting the case the strings and do ordinal comparison.
2902 Array
.Sort(keys
, values
, OrdinalCaseInsensitiveComparer
.Default
);
2904 // create a list of null terminated "key=val" strings
2905 StringBuilder stringBuff
= new StringBuilder();
2906 for (int i
= 0; i
< sd
.Count
; ++ i
) {
2907 stringBuff
.Append(keys
[i
]);
2908 stringBuff
.Append('=');
2909 stringBuff
.Append(values
[i
]);
2910 stringBuff
.Append('\0');
2912 // an extra null at the end indicates end of list.
2913 stringBuff
.Append('\0');
2916 envBlock
= Encoding
.Unicode
.GetBytes(stringBuff
.ToString());
2919 envBlock
= Encoding
.Default
.GetBytes(stringBuff
.ToString());
2921 if (envBlock
.Length
> UInt16
.MaxValue
)
2922 throw new InvalidOperationException(SR
.GetString(SR
.EnvironmentBlockTooLong
, envBlock
.Length
));
2929 internal class OrdinalCaseInsensitiveComparer
: IComparer
{
2930 internal static readonly OrdinalCaseInsensitiveComparer Default
= new OrdinalCaseInsensitiveComparer();
2932 public int Compare(Object a
, Object b
) {
2933 String sa
= a
as String
;
2934 String sb
= b
as String
;
2935 if (sa
!= null && sb
!= null) {
2936 return String
.Compare(sa
, sb
, StringComparison
.OrdinalIgnoreCase
);
2938 return Comparer
.Default
.Compare(a
,b
);
2942 internal class ProcessThreadTimes
{
2943 internal long create
;
2945 internal long kernel
;
2948 public DateTime StartTime
{
2950 return DateTime
.FromFileTime(create
);
2954 public DateTime ExitTime
{
2956 return DateTime
.FromFileTime(exit
);
2960 public TimeSpan PrivilegedProcessorTime
{
2962 return new TimeSpan(kernel
);
2966 public TimeSpan UserProcessorTime
{
2968 return new TimeSpan(user
);
2972 public TimeSpan TotalProcessorTime
{
2974 return new TimeSpan(user
+ kernel
);
2980 internal class ShellExecuteHelper
{
2981 private NativeMethods
.ShellExecuteInfo _executeInfo
;
2982 private int _errorCode
;
2983 private bool _succeeded
;
2985 public ShellExecuteHelper(NativeMethods
.ShellExecuteInfo executeInfo
) {
2986 _executeInfo
= executeInfo
;
2989 [ResourceExposure(ResourceScope
.None
)]
2990 [ResourceConsumption(ResourceScope
.Machine
, ResourceScope
.Machine
)]
2991 public void ShellExecuteFunction() {
2992 if (!(_succeeded
= NativeMethods
.ShellExecuteEx(_executeInfo
))) {
2993 _errorCode
= Marshal
.GetLastWin32Error();
2997 public bool ShellExecuteOnSTAThread() {
2999 // SHELL API ShellExecute() requires STA in order to work correctly.
3000 // If current thread is not a STA thread, we need to call ShellExecute on a new thread.
3002 if( Thread
.CurrentThread
.GetApartmentState() != ApartmentState
.STA
) {
3003 ThreadStart threadStart
= new ThreadStart(this.ShellExecuteFunction
);
3004 Thread executionThread
= new Thread(threadStart
);
3005 executionThread
.SetApartmentState(ApartmentState
.STA
);
3006 executionThread
.Start();
3007 executionThread
.Join();
3010 ShellExecuteFunction();
3015 public int ErrorCode
{