Fix infrequent hangs in test-runner. (#16793)
[mono-project.git] / mcs / class / referencesource / System / services / monitoring / system / diagnosticts / Process.cs
blob7e5b7402c565fff530d672f65fbdb277fef199e2
1 //------------------------------------------------------------------------------
2 // <copyright file="Process.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
7 #if MONO
8 #undef FEATURE_PAL
9 #endif
11 namespace System.Diagnostics {
12 using System.Text;
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;
20 using System;
21 using System.Collections;
22 using System.IO;
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;
33 /// <devdoc>
34 /// <para>
35 /// Provides access to local and remote
36 /// processes. Enables you to start and stop system processes.
37 /// </para>
38 /// </devdoc>
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 {
51 // FIELDS
54 bool haveProcessId;
55 int processId;
56 bool haveProcessHandle;
57 SafeProcessHandle m_processHandle;
58 bool isRemoteMachine;
59 string machineName;
60 #if !MONO
61 ProcessInfo processInfo;
62 #endif
63 Int32 m_processAccess;
65 #if !FEATURE_PAL
66 ProcessThreadCollection threads;
67 ProcessModuleCollection modules;
68 #endif // !FEATURE_PAL
70 #if !MONO
71 bool haveMainWindow;
72 IntPtr mainWindowHandle; // no need to use SafeHandle for window
73 string mainWindowTitle;
74 #endif
76 bool haveWorkingSetLimits;
77 IntPtr minWorkingSet;
78 IntPtr maxWorkingSet;
80 #if !MONO
81 bool haveProcessorAffinity;
82 IntPtr processorAffinity;
83 #endif
85 bool havePriorityClass;
86 ProcessPriorityClass priorityClass;
88 ProcessStartInfo startInfo;
90 bool watchForExit;
91 bool watchingForExit;
92 EventHandler onExited;
93 bool exited;
94 int exitCode;
95 bool signaled;
97 DateTime exitTime;
98 bool haveExitTime;
100 #if !MONO
101 bool responding;
102 bool haveResponding;
104 bool priorityBoostEnabled;
105 bool havePriorityBoostEnabled;
106 #endif
108 bool raisedOnExited;
109 RegisteredWaitHandle registeredWaitHandle;
110 WaitHandle waitHandle;
111 ISynchronizeInvoke synchronizingObject;
112 StreamReader standardOutput;
113 StreamWriter standardInput;
114 StreamReader standardError;
115 OperatingSystem operatingSystem;
116 bool disposed;
118 #if !MONO
119 static object s_CreateProcessLock = new object();
120 #endif
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
126 undefined,
127 syncMode,
128 asyncMode
131 StreamReadMode outputStreamReadMode;
132 StreamReadMode errorStreamReadMode;
134 #if MONO
135 StreamReadMode inputStreamReadMode;
136 #endif
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;
151 #if !MONO
152 private static SafeFileHandle InvalidPipeHandle = new SafeFileHandle(IntPtr.Zero, false);
153 #endif
154 #if DEBUG
155 internal static TraceSwitch processTracing = new TraceSwitch("processTracing", "Controls debug output from Process component");
156 #else
157 internal static TraceSwitch processTracing = null;
158 #endif
161 // CONSTRUCTORS
164 /// <devdoc>
165 /// <para>
166 /// Initializes a new instance of the <see cref='System.Diagnostics.Process'/> class.
167 /// </para>
168 /// </devdoc>
169 public Process() {
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!");
179 #if !MONO
180 this.processInfo = processInfo;
181 #endif
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;
192 // PROPERTIES
195 /// <devdoc>
196 /// Returns whether this process component is associated with a real process.
197 /// </devdoc>
198 /// <internalonly/>
199 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessAssociated)]
200 bool Associated {
201 get {
202 return haveProcessId || haveProcessHandle;
206 #if !FEATURE_PAL && !MONO
207 /// <devdoc>
208 /// <para>
209 /// Gets the base priority of
210 /// the associated process.
211 /// </para>
212 /// </devdoc>
213 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessBasePriority)]
214 public int BasePriority {
215 get {
216 EnsureState(State.HaveProcessInfo);
217 return processInfo.basePriority;
220 #endif // !FEATURE_PAL && !MONO
222 /// <devdoc>
223 /// <para>
224 /// Gets
225 /// the
226 /// value that was specified by the associated process when it was terminated.
227 /// </para>
228 /// </devdoc>
229 [Browsable(false),DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessExitCode)]
230 public int ExitCode {
231 get {
232 EnsureState(State.Exited);
233 #if MONO
234 if (exitCode == -1 && !RuntimeInformation.IsOSPlatform (OSPlatform.Windows))
235 throw new InvalidOperationException ("Cannot get the exit code from a non-child process on Unix");
236 #endif
237 return exitCode;
241 /// <devdoc>
242 /// <para>
243 /// Gets a
244 /// value indicating whether the associated process has been terminated.
245 /// </para>
246 /// </devdoc>
247 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessTerminated)]
248 public bool HasExited {
249 get {
250 if (!exited) {
251 EnsureState(State.Associated);
252 SafeProcessHandle handle = null;
253 try {
254 handle = GetProcessHandle(NativeMethods.PROCESS_QUERY_INFORMATION | NativeMethods.SYNCHRONIZE, false);
255 if (handle.IsInvalid) {
256 exited = true;
258 else {
259 int exitCode;
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) {
269 this.exited = true;
270 this.exitCode = exitCode;
272 else {
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;
281 try
283 wh = new ProcessWaitHandle(handle);
284 this.signaled = wh.WaitOne(0, false);
286 finally
289 if (wh != null)
290 wh.Close();
293 if (signaled)
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();
301 this.exited = true;
302 this.exitCode = exitCode;
307 finally
309 ReleaseProcessHandle(handle);
312 if (exited) {
313 RaiseOnExited();
316 return exited;
320 private ProcessThreadTimes GetProcessTimes() {
321 ProcessThreadTimes processTimes = new ProcessThreadTimes();
322 SafeProcessHandle handle = null;
323 try {
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();
346 finally {
347 ReleaseProcessHandle(handle);
349 return processTimes;
352 #if !FEATURE_PAL
353 /// <devdoc>
354 /// <para>
355 /// Gets the time that the associated process exited.
356 /// </para>
357 /// </devdoc>
358 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessExitTime)]
359 public DateTime ExitTime {
360 get {
361 if (!haveExitTime) {
362 EnsureState(State.IsNt | State.Exited);
363 exitTime = GetProcessTimes().ExitTime;
364 haveExitTime = true;
366 return exitTime;
369 #endif // !FEATURE_PAL
371 /// <devdoc>
372 /// <para>
373 /// Returns the native handle for the associated process. The handle is only available
374 /// if this component started the process.
375 /// </para>
376 /// </devdoc>
377 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessHandle)]
378 public IntPtr Handle {
379 [ResourceExposure(ResourceScope.Machine)]
380 [ResourceConsumption(ResourceScope.Machine)]
381 get {
382 EnsureState(State.Associated);
383 return OpenProcessHandle(this.m_processAccess).DangerousGetHandle();
387 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
388 public SafeProcessHandle SafeHandle {
389 get {
390 EnsureState(State.Associated);
391 return OpenProcessHandle(this.m_processAccess);
395 #if !FEATURE_PAL && !MONO
396 /// <devdoc>
397 /// <para>
398 /// Gets the number of handles that are associated
399 /// with the process.
400 /// </para>
401 /// </devdoc>
402 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessHandleCount)]
403 public int HandleCount {
404 get {
405 EnsureState(State.HaveProcessInfo);
406 return processInfo.handleCount;
409 #endif // !FEATURE_PAL && !MONO
411 /// <devdoc>
412 /// <para>
413 /// Gets
414 /// the unique identifier for the associated process.
415 /// </para>
416 /// </devdoc>
417 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessId)]
418 public int Id {
419 get {
420 EnsureState(State.HaveId);
421 return processId;
425 /// <devdoc>
426 /// <para>
427 /// Gets
428 /// the name of the computer on which the associated process is running.
429 /// </para>
430 /// </devdoc>
431 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessMachineName)]
432 public string MachineName {
433 get {
434 EnsureState(State.Associated);
435 return machineName;
439 #if !FEATURE_PAL
441 #if !MONO
442 /// <devdoc>
443 /// <para>
444 /// Returns the window handle of the main window of the associated process.
445 /// </para>
446 /// </devdoc>
447 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessMainWindowHandle)]
448 public IntPtr MainWindowHandle {
449 [ResourceExposure(ResourceScope.Machine)]
450 [ResourceConsumption(ResourceScope.Machine)]
451 get {
452 if (!haveMainWindow) {
453 EnsureState(State.IsLocal | State.HaveId);
454 mainWindowHandle = ProcessManager.GetMainWindowHandle(processId);
456 if (mainWindowHandle != (IntPtr)0) {
457 haveMainWindow = true;
458 } else {
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;
469 /// <devdoc>
470 /// <para>
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.
473 /// </para>
474 /// </devdoc>
475 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessMainWindowTitle)]
476 public string MainWindowTitle {
477 [ResourceExposure(ResourceScope.None)]
478 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
479 get {
480 if (mainWindowTitle == null) {
481 IntPtr handle = MainWindowHandle;
482 if (handle == (IntPtr)0) {
483 mainWindowTitle = String.Empty;
485 else {
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;
498 /// <devdoc>
499 /// <para>
500 /// Gets
501 /// the main module for the associated process.
502 /// </para>
503 /// </devdoc>
504 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessMainModule)]
505 public ProcessModule MainModule {
506 [ResourceExposure(ResourceScope.Process)]
507 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
508 get {
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);
521 else {
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) {
527 return pm;
530 return null;
534 #endif
536 /// <devdoc>
537 /// <para>
538 /// Gets or sets the maximum allowable working set for the associated
539 /// process.
540 /// </para>
541 /// </devdoc>
542 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessMaxWorkingSet)]
543 public IntPtr MaxWorkingSet {
544 get {
545 EnsureWorkingSetLimits();
546 return maxWorkingSet;
548 [ResourceExposure(ResourceScope.Process)]
549 [ResourceConsumption(ResourceScope.Process)]
550 set {
551 SetWorkingSetLimits(null, value);
555 /// <devdoc>
556 /// <para>
557 /// Gets or sets the minimum allowable working set for the associated
558 /// process.
559 /// </para>
560 /// </devdoc>
561 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessMinWorkingSet)]
562 public IntPtr MinWorkingSet {
563 get {
564 EnsureWorkingSetLimits();
565 return minWorkingSet;
567 [ResourceExposure(ResourceScope.Process)]
568 [ResourceConsumption(ResourceScope.Process)]
569 set {
570 SetWorkingSetLimits(value, null);
574 #if !MONO
575 /// <devdoc>
576 /// <para>
577 /// Gets
578 /// the modules that have been loaded by the associated process.
579 /// </para>
580 /// </devdoc>
581 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessModules)]
582 public ProcessModuleCollection Modules {
583 [ResourceExposure(ResourceScope.None)]
584 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
585 get {
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;
596 return modules;
600 /// <devdoc>
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.
603 /// </devdoc>
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 {
607 get {
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 {
616 get {
617 EnsureState(State.HaveNtProcessInfo);
618 return processInfo.poolNonpagedBytes;
622 /// <devdoc>
623 /// Returns the amount of memory that the associated process has allocated
624 /// that can be written to the virtual memory paging file.
625 /// </devdoc>
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 {
629 get {
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 {
638 get {
639 EnsureState(State.HaveNtProcessInfo);
640 return processInfo.pageFileBytes;
645 /// <devdoc>
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.
648 /// </devdoc>
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 {
652 get {
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 {
661 get {
662 EnsureState(State.HaveNtProcessInfo);
663 return processInfo.poolPagedBytes;
668 /// <devdoc>
669 /// <para>
670 /// Returns the maximum amount of memory that the associated process has
671 /// allocated that could be written to the virtual memory paging file.
672 /// </para>
673 /// </devdoc>
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 {
677 get {
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 {
686 get {
687 EnsureState(State.HaveNtProcessInfo);
688 return processInfo.pageFileBytesPeak;
692 /// <devdoc>
693 /// <para>
694 /// Returns the maximum amount of physical memory that the associated
695 /// process required at once.
696 /// </para>
697 /// </devdoc>
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 {
701 get {
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 {
710 get {
711 EnsureState(State.HaveNtProcessInfo);
712 return processInfo.workingSetPeak;
716 /// <devdoc>
717 /// Returns the maximum amount of virtual memory that the associated
718 /// process has requested.
719 /// </devdoc>
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 {
723 get {
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 {
732 get {
733 EnsureState(State.HaveNtProcessInfo);
734 return processInfo.virtualBytesPeak;
737 #endif
739 private OperatingSystem OperatingSystem {
740 get {
741 if (operatingSystem == null) {
742 operatingSystem = Environment.OSVersion;
744 return operatingSystem;
748 #if !MONO
749 /// <devdoc>
750 /// <para>
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
753 /// has focus.
754 /// </para>
755 /// </devdoc>
756 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessPriorityBoostEnabled)]
757 public bool PriorityBoostEnabled {
758 get {
759 EnsureState(State.IsNt);
760 if (!havePriorityBoostEnabled) {
761 SafeProcessHandle handle = null;
762 try {
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;
771 finally {
772 ReleaseProcessHandle(handle);
775 return priorityBoostEnabled;
777 set {
778 EnsureState(State.IsNt);
779 SafeProcessHandle handle = null;
780 try {
781 handle = GetProcessHandle(NativeMethods.PROCESS_SET_INFORMATION);
782 if (!NativeMethods.SetProcessPriorityBoost(handle, !value))
783 throw new Win32Exception();
784 priorityBoostEnabled = value;
785 havePriorityBoostEnabled = true;
787 finally {
788 ReleaseProcessHandle(handle);
792 #endif
794 /// <devdoc>
795 /// <para>
796 /// Gets or sets the overall priority category for the
797 /// associated process.
798 /// </para>
799 /// </devdoc>
800 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessPriorityClass)]
801 public ProcessPriorityClass PriorityClass {
802 get {
803 if (!havePriorityClass) {
804 SafeProcessHandle handle = null;
805 try {
806 handle = GetProcessHandle(NativeMethods.PROCESS_QUERY_INFORMATION);
807 int value = NativeMethods.GetPriorityClass(handle);
808 if (value == 0) {
809 throw new Win32Exception();
811 priorityClass = (ProcessPriorityClass)value;
812 havePriorityClass = true;
814 finally {
815 ReleaseProcessHandle(handle);
818 return priorityClass;
820 [ResourceExposure(ResourceScope.Machine)]
821 [ResourceConsumption(ResourceScope.Machine)]
822 set {
823 if (!Enum.IsDefined(typeof(ProcessPriorityClass), value)) {
824 throw new InvalidEnumArgumentException("value", (int)value, typeof(ProcessPriorityClass));
827 #if !MONO
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);
833 #endif // !MONO
835 SafeProcessHandle handle = null;
837 try {
838 handle = GetProcessHandle(NativeMethods.PROCESS_SET_INFORMATION);
839 if (!NativeMethods.SetPriorityClass(handle, (int)value)) {
840 throw new Win32Exception();
842 priorityClass = value;
843 havePriorityClass = true;
845 finally {
846 ReleaseProcessHandle(handle);
851 #if !MONO
852 /// <devdoc>
853 /// Returns the number of bytes that the associated process has allocated that cannot
854 /// be shared with other processes.
855 /// </devdoc>
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 {
859 get {
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 {
868 get {
869 EnsureState(State.HaveNtProcessInfo);
870 return processInfo.privateBytes;
873 #endif
875 /// <devdoc>
876 /// Returns the amount of time the process has spent running code inside the operating
877 /// system core.
878 /// </devdoc>
879 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessPrivilegedProcessorTime)]
880 public TimeSpan PrivilegedProcessorTime {
881 get {
882 EnsureState(State.IsNt);
883 return GetProcessTimes().PrivilegedProcessorTime;
887 #if !MONO
888 /// <devdoc>
889 /// <para>
890 /// Gets
891 /// the friendly name of the process.
892 /// </para>
893 /// </devdoc>
894 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessProcessName)]
895 public string ProcessName {
896 [ResourceExposure(ResourceScope.None)]
897 [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
898 get {
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) {
912 try {
913 String mainModuleName = MainModule.ModuleName;
914 if (mainModuleName != null) {
915 processInfo.processName = Path.ChangeExtension(Path.GetFileName(mainModuleName), null);
918 catch(Exception) {
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;
930 /// <devdoc>
931 /// <para>
932 /// Gets
933 /// or sets which processors the threads in this process can be scheduled to run on.
934 /// </para>
935 /// </devdoc>
936 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessProcessorAffinity)]
937 public IntPtr ProcessorAffinity {
938 get {
939 if (!haveProcessorAffinity) {
940 SafeProcessHandle handle = null;
941 try {
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;
949 finally {
950 ReleaseProcessHandle(handle);
952 haveProcessorAffinity = true;
954 return processorAffinity;
956 [ResourceExposure(ResourceScope.Machine)]
957 [ResourceConsumption(ResourceScope.Machine)]
958 set {
959 SafeProcessHandle handle = null;
960 try {
961 handle = GetProcessHandle(NativeMethods.PROCESS_SET_INFORMATION);
962 if (!NativeMethods.SetProcessAffinityMask(handle, value))
963 throw new Win32Exception();
965 processorAffinity = value;
966 haveProcessorAffinity = true;
968 finally {
969 ReleaseProcessHandle(handle);
974 /// <devdoc>
975 /// <para>
976 /// Gets a value indicating whether or not the user
977 /// interface of the process is responding.
978 /// </para>
979 /// </devdoc>
980 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessResponding)]
981 public bool Responding {
982 [ResourceExposure(ResourceScope.None)]
983 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
984 get {
985 if (!haveResponding) {
986 IntPtr mainWindow = MainWindowHandle;
987 if (mainWindow == (IntPtr)0) {
988 responding = true;
990 else {
991 IntPtr result;
992 responding = NativeMethods.SendMessageTimeout(new HandleRef(this, mainWindow), NativeMethods.WM_NULL, IntPtr.Zero, IntPtr.Zero, NativeMethods.SMTO_ABORTIFHUNG, 5000, out result) != (IntPtr)0;
995 return responding;
999 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessSessionId)]
1000 public int SessionId {
1001 get {
1002 EnsureState(State.HaveNtProcessInfo);
1003 return processInfo.sessionId;
1006 #endif // !MONO
1008 #endif // !FEATURE_PAL
1010 #if MONO_FEATURE_PROCESS_START
1011 /// <devdoc>
1012 /// <para>
1013 /// Gets or sets the properties to pass into the <see cref='System.Diagnostics.Process.Start'/> method for the <see cref='System.Diagnostics.Process'/>
1014 /// .
1015 /// </para>
1016 /// </devdoc>
1017 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), MonitoringDescription(SR.ProcessStartInfo)]
1018 public ProcessStartInfo StartInfo {
1019 get {
1020 if (startInfo == null) {
1021 startInfo = new ProcessStartInfo(this);
1023 return startInfo;
1025 [ResourceExposure(ResourceScope.Machine)]
1026 set {
1027 if (value == null) {
1028 throw new ArgumentNullException("value");
1030 startInfo = value;
1033 #endif
1035 #if !FEATURE_PAL
1036 /// <devdoc>
1037 /// Returns the time the associated process was started.
1038 /// </devdoc>
1039 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessStartTime)]
1040 public DateTime StartTime {
1041 get {
1042 EnsureState(State.IsNt);
1043 return GetProcessTimes().StartTime;
1046 #endif // !FEATURE_PAL
1048 /// <devdoc>
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.
1054 /// </devdoc>
1056 Browsable(false),
1057 DefaultValue(null),
1058 MonitoringDescription(SR.ProcessSynchronizingObject)
1060 public ISynchronizeInvoke SynchronizingObject {
1061 get {
1062 if (this.synchronizingObject == null && DesignMode) {
1063 IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
1064 if (host != null) {
1065 object baseComponent = host.RootComponent;
1066 if (baseComponent != null && baseComponent is ISynchronizeInvoke)
1067 this.synchronizingObject = (ISynchronizeInvoke)baseComponent;
1071 return this.synchronizingObject;
1074 set {
1075 this.synchronizingObject = value;
1079 #if !FEATURE_PAL
1081 #if !MONO
1082 /// <devdoc>
1083 /// <para>
1084 /// Gets the set of threads that are running in the associated
1085 /// process.
1086 /// </para>
1087 /// </devdoc>
1088 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessThreads)]
1089 public ProcessThreadCollection Threads {
1090 [ResourceExposure(ResourceScope.Process)]
1091 [ResourceConsumption(ResourceScope.Process)]
1092 get {
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;
1103 return threads;
1106 #endif
1108 /// <devdoc>
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'/>.
1112 /// </devdoc>
1113 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessTotalProcessorTime)]
1114 public TimeSpan TotalProcessorTime {
1115 get {
1116 EnsureState(State.IsNt);
1117 return GetProcessTimes().TotalProcessorTime;
1121 /// <devdoc>
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).
1124 /// </devdoc>
1125 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessUserProcessorTime)]
1126 public TimeSpan UserProcessorTime {
1127 get {
1128 EnsureState(State.IsNt);
1129 return GetProcessTimes().UserProcessorTime;
1133 #if !MONO
1134 /// <devdoc>
1135 /// Returns the amount of virtual memory that the associated process has requested.
1136 /// </devdoc>
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 {
1140 get {
1141 EnsureState(State.HaveNtProcessInfo);
1142 return unchecked((int)processInfo.virtualBytes);
1145 #endif // !MONO
1147 #endif // !FEATURE_PAL
1149 #if !MONO
1150 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessVirtualMemorySize)]
1151 [System.Runtime.InteropServices.ComVisible(false)]
1152 public long VirtualMemorySize64 {
1153 get {
1154 EnsureState(State.HaveNtProcessInfo);
1155 return processInfo.virtualBytes;
1158 #endif
1160 /// <devdoc>
1161 /// <para>
1162 /// Gets or sets whether the <see cref='System.Diagnostics.Process.Exited'/>
1163 /// event is fired
1164 /// when the process terminates.
1165 /// </para>
1166 /// </devdoc>
1167 [Browsable(false), DefaultValue(false), MonitoringDescription(SR.ProcessEnableRaisingEvents)]
1168 public bool EnableRaisingEvents {
1169 get {
1170 return watchForExit;
1172 set {
1173 if (value != watchForExit) {
1174 if (Associated) {
1175 if (value) {
1176 OpenProcessHandle();
1177 EnsureWatchingForExit();
1179 else {
1180 StopWatchingForExit();
1183 watchForExit = value;
1188 #if MONO_FEATURE_PROCESS_START
1189 /// <devdoc>
1190 /// <para>[To be supplied.]</para>
1191 /// </devdoc>
1192 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessStandardInput)]
1193 public StreamWriter StandardInput {
1194 get {
1195 if (standardInput == null) {
1196 throw new InvalidOperationException(SR.GetString(SR.CantGetStandardIn));
1199 #if MONO
1200 inputStreamReadMode = StreamReadMode.syncMode;
1201 #endif
1202 return standardInput;
1206 /// <devdoc>
1207 /// <para>[To be supplied.]</para>
1208 /// </devdoc>
1209 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessStandardOutput)]
1210 public StreamReader StandardOutput {
1211 get {
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;
1227 /// <devdoc>
1228 /// <para>[To be supplied.]</para>
1229 /// </devdoc>
1230 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessStandardError)]
1231 public StreamReader StandardError {
1232 get {
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;
1247 #endif
1249 #if !FEATURE_PAL && !MONO
1250 /// <devdoc>
1251 /// Returns the total amount of physical memory the associated process.
1252 /// </devdoc>
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 {
1256 get {
1257 EnsureState(State.HaveNtProcessInfo);
1258 return unchecked((int)processInfo.workingSet);
1261 #endif // !FEATURE_PAL && !MONO
1263 #if !MONO
1264 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessWorkingSet)]
1265 [System.Runtime.InteropServices.ComVisible(false)]
1266 public long WorkingSet64 {
1267 get {
1268 EnsureState(State.HaveNtProcessInfo);
1269 return processInfo.workingSet;
1272 #endif
1274 [Category("Behavior"), MonitoringDescription(SR.ProcessExited)]
1275 public event EventHandler Exited {
1276 add {
1277 onExited += value;
1279 remove {
1280 onExited -= value;
1284 #if !FEATURE_PAL && !MONO
1285 /// <devdoc>
1286 /// <para>
1287 /// Closes a process that has a user interface by sending a close message
1288 /// to its main window.
1289 /// </para>
1290 /// </devdoc>
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);
1299 return true;
1301 #endif // !FEATURE_PAL && !MONO
1303 /// <devdoc>
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.
1306 /// </devdoc>
1307 /// <internalonly/>
1308 void ReleaseProcessHandle(SafeProcessHandle handle) {
1309 if (handle == null) {
1310 return;
1313 if (haveProcessHandle && handle == m_processHandle) {
1314 return;
1316 Debug.WriteLineIf(processTracing.TraceVerbose, "Process - CloseHandle(process)");
1317 handle.Close();
1320 /// <devdoc>
1321 /// This is called from the threadpool when a proces exits.
1322 /// </devdoc>
1323 /// <internalonly/>
1324 private void CompletionCallback(object context, bool wasSignaled) {
1325 StopWatchingForExit();
1326 RaiseOnExited();
1329 /// <internalonly/>
1330 /// <devdoc>
1331 /// <para>
1332 /// Free any resources associated with this component.
1333 /// </para>
1334 /// </devdoc>
1335 protected override void Dispose(bool disposing) {
1336 if( !disposed) {
1337 if (disposing) {
1338 //Dispose managed and unmanaged resources
1339 Close();
1341 this.disposed = true;
1342 base.Dispose(disposing);
1346 /// <devdoc>
1347 /// <para>
1348 /// Frees any resources associated with this component.
1349 /// </para>
1350 /// </devdoc>
1351 public void Close() {
1352 if (Associated) {
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;
1362 machineName = ".";
1363 raisedOnExited = false;
1365 #if MONO
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)
1373 tmpIn.Close ();
1375 var tmpOut = standardOutput;
1376 standardOutput = null;
1377 if (outputStreamReadMode == StreamReadMode.undefined && tmpOut != null)
1378 tmpOut.Close ();
1380 tmpOut = standardError;
1381 standardError = null;
1382 if (errorStreamReadMode == StreamReadMode.undefined && tmpOut != null)
1383 tmpOut.Close ();
1385 var tmpAsync = output;
1386 output = null;
1387 if (outputStreamReadMode == StreamReadMode.asyncMode && tmpAsync != null) {
1388 tmpAsync.CancelOperation ();
1389 tmpAsync.Close ();
1392 tmpAsync = error;
1393 error = null;
1394 if (errorStreamReadMode == StreamReadMode.asyncMode && tmpAsync != null) {
1395 tmpAsync.CancelOperation ();
1396 tmpAsync.Close ();
1398 #else
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;
1406 output = null;
1407 error = null;
1409 #endif
1411 Refresh();
1415 /// <devdoc>
1416 /// Helper method for checking preconditions when accessing properties.
1417 /// </devdoc>
1418 /// <internalonly/>
1419 [ResourceExposure(ResourceScope.None)]
1420 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
1421 void EnsureState(State state) {
1423 #if !MONO
1424 if ((state & State.IsWin2k) != (State)0) {
1425 #if !FEATURE_PAL
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) {
1432 #if !FEATURE_PAL
1433 if (OperatingSystem.Platform != PlatformID.Win32NT)
1434 #endif // !FEATURE_PAL
1435 throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequired));
1437 #endif // !MONO
1439 if ((state & State.Associated) != (State)0)
1440 if (!Associated)
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));
1449 else {
1450 EnsureState(State.Associated);
1451 throw new InvalidOperationException(SR.GetString(SR.ProcessIdRequired));
1453 #else
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];
1472 break;
1475 if (processInfo == null) {
1476 throw new InvalidOperationException(SR.GetString(SR.NoProcessInfo));
1479 #else
1480 throw new InvalidOperationException(SR.GetString(SR.NoProcessInfo));
1481 #endif // !FEATURE_PAL && !MONO
1484 if ((state & State.Exited) != (State)0) {
1485 if (!HasExited) {
1486 throw new InvalidOperationException(SR.GetString(SR.WaitTillExit));
1489 if (!haveProcessHandle) {
1490 throw new InvalidOperationException(SR.GetString(SR.NoProcessHandle));
1495 /// <devdoc>
1496 /// Make sure we are watching for a process exit.
1497 /// </devdoc>
1498 /// <internalonly/>
1499 void EnsureWatchingForExit() {
1500 if (!watchingForExit) {
1501 lock (this) {
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;
1506 try {
1507 this.waitHandle = new ProcessWaitHandle(m_processHandle);
1508 this.registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(this.waitHandle,
1509 new WaitOrTimerCallback(this.CompletionCallback), null, -1, true);
1511 catch {
1512 watchingForExit = false;
1513 throw;
1520 #if !FEATURE_PAL
1522 /// <devdoc>
1523 /// Make sure we have obtained the min and max working set limits.
1524 /// </devdoc>
1525 /// <internalonly/>
1526 void EnsureWorkingSetLimits() {
1527 EnsureState(State.IsNt);
1528 if (!haveWorkingSetLimits) {
1529 SafeProcessHandle handle = null;
1530 try {
1531 handle = GetProcessHandle(NativeMethods.PROCESS_QUERY_INFORMATION);
1532 IntPtr min;
1533 IntPtr max;
1534 if (!NativeMethods.GetProcessWorkingSetSize(handle, out min, out max)) {
1535 throw new Win32Exception();
1537 minWorkingSet = min;
1538 maxWorkingSet = max;
1539 haveWorkingSetLimits = true;
1541 finally {
1542 ReleaseProcessHandle(handle);
1547 public static void EnterDebugMode() {
1548 #if !MONO
1549 if (ProcessManager.IsNt) {
1550 SetPrivilege("SeDebugPrivilege", NativeMethods.SE_PRIVILEGE_ENABLED);
1552 #endif
1555 #if !MONO
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();
1571 try {
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();
1588 finally {
1589 Debug.WriteLineIf(processTracing.TraceVerbose, "Process - CloseHandle(processToken)");
1590 SafeNativeMethods.CloseHandle(hToken);
1593 #endif
1595 /// <devdoc>
1596 /// <para>[To be supplied.]</para>
1597 /// </devdoc>
1598 public static void LeaveDebugMode() {
1599 #if !MONO
1600 if (ProcessManager.IsNt) {
1601 SetPrivilege("SeDebugPrivilege", 0);
1603 #endif
1606 #if !MONO
1607 /// <devdoc>
1608 /// <para>
1609 /// Returns a new <see cref='System.Diagnostics.Process'/> component given a process identifier and
1610 /// the name of a computer in the network.
1611 /// </para>
1612 /// </devdoc>
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);
1622 #endif
1624 /// <devdoc>
1625 /// <para>
1626 /// Returns a new <see cref='System.Diagnostics.Process'/> component given the
1627 /// identifier of a process on the local computer.
1628 /// </para>
1629 /// </devdoc>
1630 [ResourceExposure(ResourceScope.Machine)]
1631 [ResourceConsumption(ResourceScope.Machine)]
1632 public static Process GetProcessById(int processId) {
1633 return GetProcessById(processId, ".");
1636 /// <devdoc>
1637 /// <para>
1638 /// Creates an array of <see cref='System.Diagnostics.Process'/> components that are
1639 /// associated
1640 /// with process resources on the
1641 /// local computer. These process resources share the specified process name.
1642 /// </para>
1643 /// </devdoc>
1644 [ResourceExposure(ResourceScope.Machine)]
1645 [ResourceConsumption(ResourceScope.Machine)]
1646 public static Process[] GetProcessesByName(string processName) {
1647 return GetProcessesByName(processName, ".");
1650 #if !MONO
1651 /// <devdoc>
1652 /// <para>
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.
1655 /// </para>
1656 /// </devdoc>
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]);
1667 } else {
1668 procs[i].Dispose();
1672 Process[] temp = new Process[list.Count];
1673 list.CopyTo(temp, 0);
1674 return temp;
1676 #endif
1678 /// <devdoc>
1679 /// <para>
1680 /// Creates a new <see cref='System.Diagnostics.Process'/>
1681 /// component for each process resource on the local computer.
1682 /// </para>
1683 /// </devdoc>
1684 [ResourceExposure(ResourceScope.Machine)]
1685 [ResourceConsumption(ResourceScope.Machine)]
1686 public static Process[] GetProcesses() {
1687 return GetProcesses(".");
1690 #if !MONO
1691 /// <devdoc>
1692 /// <para>
1693 /// Creates a new <see cref='System.Diagnostics.Process'/>
1694 /// component for each
1695 /// process resource on the specified computer.
1696 /// </para>
1697 /// </devdoc>
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 + ")");
1709 #if DEBUG
1710 if (processTracing.TraceVerbose) {
1711 Debug.Indent();
1712 for (int i = 0; i < processInfos.Length; i++) {
1713 Debug.WriteLine(processes[i].Id + ": " + processes[i].ProcessName);
1715 Debug.Unindent();
1717 #endif // DEBUG
1718 return processes;
1720 #endif // !MONO
1722 #endif // !FEATURE_PAL
1724 /// <devdoc>
1725 /// <para>
1726 /// Returns a new <see cref='System.Diagnostics.Process'/>
1727 /// component and associates it with the current active process.
1728 /// </para>
1729 /// </devdoc>
1730 [ResourceExposure(ResourceScope.Process)]
1731 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Process)]
1732 public static Process GetCurrentProcess() {
1733 return new Process(".", false, NativeMethods.GetCurrentProcessId(), null);
1736 /// <devdoc>
1737 /// <para>
1738 /// Raises the <see cref='System.Diagnostics.Process.Exited'/> event.
1739 /// </para>
1740 /// </devdoc>
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});
1746 else
1747 exited(this, EventArgs.Empty);
1751 /// <devdoc>
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.
1755 /// </devdoc>
1756 /// <internalonly/>
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 + ")");
1761 #if DEBUG
1762 if (processTracing.TraceVerbose) {
1763 StackFrame calledFrom = new StackTrace(true).GetFrame(0);
1764 Debug.WriteLine(" called from " + calledFrom.GetFileName() + ", line " + calledFrom.GetFileLineNumber());
1766 #endif
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;
1773 try {
1774 waitHandle = new ProcessWaitHandle(m_processHandle);
1775 if (waitHandle.WaitOne(0, false)) {
1776 if (haveProcessId)
1777 throw new InvalidOperationException(SR.GetString(SR.ProcessHasExited, processId.ToString(CultureInfo.CurrentCulture)));
1778 else
1779 throw new InvalidOperationException(SR.GetString(SR.ProcessHasExitedNoId));
1782 finally {
1783 if( waitHandle != null) {
1784 waitHandle.Close();
1788 return m_processHandle;
1790 else {
1791 EnsureState(State.HaveId | State.IsLocal);
1792 SafeProcessHandle handle = SafeProcessHandle.InvalidHandle;
1793 #if !FEATURE_PAL && !MONO
1794 handle = ProcessManager.OpenProcess(processId, access, throwIfExited);
1795 #else
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),
1801 out handle,
1803 false,
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)));
1814 return handle;
1819 /// <devdoc>
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.
1822 /// </devdoc>
1823 /// <internalonly/>
1824 SafeProcessHandle GetProcessHandle(int access) {
1825 return GetProcessHandle(access, true);
1828 /// <devdoc>
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.
1831 /// </devdoc>
1832 /// <internalonly/>
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;
1849 #if !MONO
1850 /// <devdoc>
1851 /// Raise the Exited event, but make sure we don't do it more than once.
1852 /// </devdoc>
1853 /// <internalonly/>
1854 void RaiseOnExited() {
1855 if (!raisedOnExited) {
1856 lock (this) {
1857 if (!raisedOnExited) {
1858 raisedOnExited = true;
1859 OnExited();
1864 #endif
1866 /// <devdoc>
1867 /// <para>
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.
1872 /// </para>
1873 /// </devdoc>
1874 public void Refresh() {
1875 #if !MONO
1876 processInfo = null;
1877 #endif
1878 #if !FEATURE_PAL
1879 threads = null;
1880 modules = null;
1881 #endif // !FEATURE_PAL
1882 #if !MONO
1883 mainWindowTitle = null;
1884 #endif
1885 exited = false;
1886 signaled = false;
1887 #if !MONO
1888 haveMainWindow = false;
1889 #endif
1890 haveWorkingSetLimits = false;
1891 #if !MONO
1892 haveProcessorAffinity = false;
1893 #endif
1894 havePriorityClass = false;
1895 haveExitTime = false;
1896 #if !MONO
1897 haveResponding = false;
1898 havePriorityBoostEnabled = false;
1899 #endif
1902 /// <devdoc>
1903 /// Helper to associate a process handle with this component.
1904 /// </devdoc>
1905 /// <internalonly/>
1906 void SetProcessHandle(SafeProcessHandle processHandle) {
1907 this.m_processHandle = processHandle;
1908 this.haveProcessHandle = true;
1909 if (watchForExit) {
1910 EnsureWatchingForExit();
1914 /// <devdoc>
1915 /// Helper to associate a process id with this component.
1916 /// </devdoc>
1917 /// <internalonly/>
1918 [ResourceExposure(ResourceScope.Machine)]
1919 void SetProcessId(int processId) {
1920 this.processId = processId;
1921 this.haveProcessId = true;
1924 #if !FEATURE_PAL
1926 /// <devdoc>
1927 /// Helper to set minimum or maximum working set limits.
1928 /// </devdoc>
1929 /// <internalonly/>
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;
1936 try {
1937 handle = GetProcessHandle(NativeMethods.PROCESS_QUERY_INFORMATION | NativeMethods.PROCESS_SET_QUOTA);
1938 IntPtr min;
1939 IntPtr max;
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));
1956 else {
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;
1973 finally {
1974 ReleaseProcessHandle(handle);
1978 #endif // !FEATURE_PAL
1980 #if MONO_FEATURE_PROCESS_START
1982 /// <devdoc>
1983 /// <para>
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'/>
1988 /// component.
1989 /// </para>
1990 /// </devdoc>
1991 [ResourceExposure(ResourceScope.None)]
1992 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
1993 public bool Start() {
1994 Close();
1995 ProcessStartInfo startInfo = StartInfo;
1996 if (startInfo.FileName.Length == 0)
1997 throw new InvalidOperationException(SR.GetString(SR.FileNameMissing));
1999 if (startInfo.UseShellExecute) {
2000 #if !FEATURE_PAL
2001 return StartWithShellExecuteEx(startInfo);
2002 #else
2003 throw new InvalidOperationException(SR.GetString(SR.net_perm_invalid_val, "StartInfo.UseShellExecute", true));
2004 #endif // !FEATURE_PAL
2005 } else {
2006 return StartWithCreateProcess(startInfo);
2010 #if !MONO
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;
2034 try {
2035 if (parentInputs) {
2036 CreatePipeWithSecurityAttributes(out childHandle, out hTmp, securityAttributesParent, 0);
2038 else {
2039 CreatePipeWithSecurityAttributes(out hTmp,
2040 out childHandle,
2041 securityAttributesParent,
2042 0);
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()),
2050 hTmp,
2051 new HandleRef(this, NativeMethods.GetCurrentProcess()),
2052 out parentHandle,
2054 false,
2055 NativeMethods.DUPLICATE_SAME_ACCESS)) {
2056 throw new Win32Exception();
2059 finally {
2060 if( hTmp != null && !hTmp.IsInvalid) {
2061 hTmp.Close();
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);
2090 return commandLine;
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);
2118 string arguments;
2119 if (startInfo.ArgumentList.Count > 0) {
2120 StringBuilder sb = new StringBuilder ();
2121 Process.AppendArguments (sb, startInfo.ArgumentList);
2122 arguments = sb.ToString ();
2124 else {
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();
2134 bool retVal;
2135 int errorCode = 0;
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) {
2142 try {
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);
2147 } else {
2148 startupInfo.hStdInput = new SafeFileHandle(NativeMethods.GetStdHandle(NativeMethods.STD_INPUT_HANDLE), false);
2151 if (startInfo.RedirectStandardOutput) {
2152 CreatePipe(out standardOutputReadPipeHandle, out startupInfo.hStdOutput, false);
2153 } else {
2154 startupInfo.hStdOutput = new SafeFileHandle(NativeMethods.GetStdHandle(NativeMethods.STD_OUTPUT_HANDLE), false);
2157 if (startInfo.RedirectStandardError) {
2158 CreatePipe(out standardErrorReadPipeHandle, out startupInfo.hStdError, false);
2159 } else {
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;
2168 #if !FEATURE_PAL
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;
2176 #if !FEATURE_PAL
2177 if (ProcessManager.IsNt) {
2178 creationFlags |= NativeMethods.CREATE_UNICODE_ENVIRONMENT;
2179 unicode = true;
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;
2192 #if !FEATURE_PAL
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;
2203 try {
2204 if( startInfo.Password != null) {
2205 password = Marshal.SecureStringToCoTaskMemUnicode(startInfo.Password);
2206 } else if( startInfo.PasswordInClearText != null) {
2207 password = Marshal.StringToCoTaskMemUni(startInfo.PasswordInClearText);
2208 } else {
2209 password = Marshal.StringToCoTaskMemUni(String.Empty);
2212 RuntimeHelpers.PrepareConstrainedRegions();
2213 try {} finally {
2214 retVal = NativeMethods.CreateProcessWithLogonW(
2215 startInfo.UserName,
2216 startInfo.Domain,
2217 password,
2218 logonFlags,
2219 null, // we don't need this since all the info is in commandLine
2220 commandLine,
2221 creationFlags,
2222 environmentPtr,
2223 workingDirectory,
2224 startupInfo, // pointer to STARTUPINFO
2225 processInfo // pointer to PROCESS_INFORMATION
2227 if (!retVal)
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);
2234 if (!retVal){
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);
2241 } finally {
2242 if( password != IntPtr.Zero) {
2243 Marshal.ZeroFreeCoTaskMemUnicode(password);
2246 } else {
2247 #endif // !FEATURE_PAL
2248 RuntimeHelpers.PrepareConstrainedRegions();
2249 try {} finally {
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
2262 if (!retVal)
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);
2269 if (!retVal) {
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);
2275 #if !FEATURE_PAL
2277 #endif
2278 } finally {
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);
2301 bool ret = false;
2302 if (!procSH.IsInvalid) {
2303 SetProcessHandle(procSH);
2304 SetProcessId(processInfo.dwProcessId);
2305 threadSH.Close();
2306 ret = true;
2309 return ret;
2312 #endif // !MONO
2314 #if !FEATURE_PAL
2316 #if !MONO
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.
2321 if (this.disposed)
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;
2350 else {
2351 shellExecuteInfo.fMask |= NativeMethods.SEE_MASK_FLAG_NO_UI;
2354 switch (startInfo.WindowStyle) {
2355 case ProcessWindowStyle.Hidden:
2356 shellExecuteInfo.nShow = NativeMethods.SW_HIDE;
2357 break;
2358 case ProcessWindowStyle.Minimized:
2359 shellExecuteInfo.nShow = NativeMethods.SW_SHOWMINIMIZED;
2360 break;
2361 case ProcessWindowStyle.Maximized:
2362 shellExecuteInfo.nShow = NativeMethods.SW_SHOWMAXIMIZED;
2363 break;
2364 default:
2365 shellExecuteInfo.nShow = NativeMethods.SW_SHOWNORMAL;
2366 break;
2370 try {
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;
2385 if (error == 0) {
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);
2407 finally {
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);
2417 return true;
2420 return false;
2422 #endif
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
2449 /// <devdoc>
2450 /// <para>
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'/>
2453 /// component.
2454 /// </para>
2455 /// </devdoc>
2456 [ResourceExposure(ResourceScope.Machine)]
2457 [ResourceConsumption(ResourceScope.Machine)]
2458 public static Process Start(string fileName) {
2459 return Start(new ProcessStartInfo(fileName));
2462 /// <devdoc>
2463 /// <para>
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'/>
2467 /// component.
2468 /// </para>
2469 /// </devdoc>
2470 [ResourceExposure(ResourceScope.Machine)]
2471 [ResourceConsumption(ResourceScope.Machine)]
2472 public static Process Start(string fileName, string arguments) {
2473 return Start(new ProcessStartInfo(fileName, arguments));
2476 /// <devdoc>
2477 /// <para>
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'/>
2481 /// component.
2482 /// </para>
2483 /// </devdoc>
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()) {
2491 return process;
2493 return null;
2496 #endif // MONO_FEATURE_PROCESS_START
2498 /// <devdoc>
2499 /// <para>
2500 /// Stops the
2501 /// associated process immediately.
2502 /// </para>
2503 /// </devdoc>
2504 [ResourceExposure(ResourceScope.Machine)]
2505 [ResourceConsumption(ResourceScope.Machine)]
2506 public void Kill() {
2507 SafeProcessHandle handle = null;
2508 try {
2509 handle = GetProcessHandle(NativeMethods.PROCESS_TERMINATE);
2510 if (!NativeMethods.TerminateProcess(handle, -1))
2511 throw new Win32Exception();
2513 finally {
2514 ReleaseProcessHandle(handle);
2518 /// <devdoc>
2519 /// Make sure we are not watching for process exit.
2520 /// </devdoc>
2521 /// <internalonly/>
2522 void StopWatchingForExit() {
2523 if (watchingForExit) {
2524 lock (this) {
2525 if (watchingForExit) {
2526 watchingForExit = false;
2527 registeredWaitHandle.Unregister(null);
2528 waitHandle.Close();
2529 waitHandle = null;
2530 registeredWaitHandle = null;
2536 public override string ToString() {
2537 #if !FEATURE_PAL
2538 if (Associated) {
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.
2546 try {
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();
2556 else
2557 #endif // !FEATURE_PAL
2558 return base.ToString();
2561 /// <devdoc>
2562 /// <para>
2563 /// Instructs the <see cref='System.Diagnostics.Process'/> component to wait the specified number of milliseconds for the associated process to exit.
2564 /// </para>
2565 /// </devdoc>
2566 public bool WaitForExit(int milliseconds) {
2567 SafeProcessHandle handle = null;
2568 bool exited;
2569 ProcessWaitHandle processWaitHandle = null;
2570 try {
2571 handle = GetProcessHandle(NativeMethods.SYNCHRONIZE, false);
2572 if (handle.IsInvalid) {
2573 exited = true;
2575 else {
2576 processWaitHandle = new ProcessWaitHandle(handle);
2577 if( processWaitHandle.WaitOne(milliseconds, false)) {
2578 exited = true;
2579 signaled = true;
2581 else {
2582 exited = false;
2583 signaled = 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();
2596 finally {
2597 if( processWaitHandle != null) {
2598 processWaitHandle.Close();
2601 ReleaseProcessHandle(handle);
2605 if (exited && watchForExit) {
2606 RaiseOnExited();
2609 return exited;
2612 /// <devdoc>
2613 /// <para>
2614 /// Instructs the <see cref='System.Diagnostics.Process'/> component to wait
2615 /// indefinitely for the associated process to exit.
2616 /// </para>
2617 /// </devdoc>
2618 public void WaitForExit() {
2619 WaitForExit(-1);
2622 #if !FEATURE_PAL
2624 /// <devdoc>
2625 /// <para>
2626 /// Causes the <see cref='System.Diagnostics.Process'/> component to wait the
2627 /// specified number of milliseconds for the associated process to enter an
2628 /// idle state.
2629 /// This is only applicable for processes with a user interface,
2630 /// therefore a message loop.
2631 /// </para>
2632 /// </devdoc>
2633 public bool WaitForInputIdle(int milliseconds) {
2634 SafeProcessHandle handle = null;
2635 bool idle;
2636 try {
2637 handle = GetProcessHandle(NativeMethods.SYNCHRONIZE | NativeMethods.PROCESS_QUERY_INFORMATION);
2638 int ret = NativeMethods.WaitForInputIdle(handle, milliseconds);
2639 switch (ret) {
2640 case NativeMethods.WAIT_OBJECT_0:
2641 idle = true;
2642 break;
2643 case NativeMethods.WAIT_TIMEOUT:
2644 idle = false;
2645 break;
2646 case NativeMethods.WAIT_FAILED:
2647 default:
2648 throw new InvalidOperationException(SR.GetString(SR.InputIdleUnkownError));
2651 finally {
2652 ReleaseProcessHandle(handle);
2654 return idle;
2657 /// <devdoc>
2658 /// <para>
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.
2662 /// </para>
2663 /// </devdoc>
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
2672 /// <devdoc>
2673 /// <para>
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.
2678 /// </para>
2679 /// </devdoc>
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();
2707 /// <devdoc>
2708 /// <para>
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.
2713 /// </para>
2714 /// </devdoc>
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();
2742 /// <devdoc>
2743 /// <para>
2744 /// Instructs the <see cref='System.Diagnostics.Process'/> component to cancel the asynchronous operation
2745 /// specified by BeginOutputReadLine().
2746 /// </para>
2747 /// </devdoc>
2748 [System.Runtime.InteropServices.ComVisible(false)]
2749 public void CancelOutputRead() {
2750 if (output != null) {
2751 output.CancelOperation();
2753 else {
2754 throw new InvalidOperationException(SR.GetString(SR.NoAsyncOperation));
2757 pendingOutputRead = false;
2760 /// <devdoc>
2761 /// <para>
2762 /// Instructs the <see cref='System.Diagnostics.Process'/> component to cancel the asynchronous operation
2763 /// specified by BeginErrorReadLine().
2764 /// </para>
2765 /// </devdoc>
2766 [System.Runtime.InteropServices.ComVisible(false)]
2767 public void CancelErrorRead() {
2768 if (error != null) {
2769 error.CancelOperation();
2771 else {
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});
2786 else {
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});
2800 else {
2801 errorDataReceived(this,e); // Call back to user informing data is available.
2805 #endif // MONO_FEATURE_PROCESS_START
2807 /// <summary>
2808 /// A desired internal state.
2809 /// </summary>
2810 /// <internalonly/>
2811 enum State {
2812 HaveId = 0x1,
2813 IsLocal = 0x2,
2814 IsNt = 0x4,
2815 HaveProcessInfo = 0x8,
2816 Exited = 0x10,
2817 Associated = 0x20,
2818 IsWin2k = 0x40,
2819 HaveNtProcessInfo = HaveProcessInfo | IsNt
2823 /// <devdoc>
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.
2828 /// </devdoc>
2829 /// <internalonly/>
2830 internal class ProcessInfo {
2831 #if !MONO
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;
2848 #endif
2851 #if !MONO
2852 /// <devdoc>
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.
2857 /// </devdoc>
2858 /// <internalonly/>
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;
2866 #if !FEATURE_PAL
2867 public ThreadWaitReason threadWaitReason;
2868 #endif // !FEATURE_PAL
2871 /// <devdoc>
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.
2876 /// </devdoc>
2877 /// <internalonly/>
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
2886 #endif
2888 internal static class EnvironmentBlock {
2889 public static byte[] ToByteArray(StringDictionary sd, bool unicode) {
2890 // get the keys
2891 string[] keys = new string[sd.Count];
2892 byte[] envBlock = null;
2893 sd.Keys.CopyTo(keys, 0);
2895 // get the values
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');
2915 if( unicode) {
2916 envBlock = Encoding.Unicode.GetBytes(stringBuff.ToString());
2918 else {
2919 envBlock = Encoding.Default.GetBytes(stringBuff.ToString());
2921 if (envBlock.Length > UInt16.MaxValue)
2922 throw new InvalidOperationException(SR.GetString(SR.EnvironmentBlockTooLong, envBlock.Length));
2925 return envBlock;
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;
2944 internal long exit;
2945 internal long kernel;
2946 internal long user;
2948 public DateTime StartTime {
2949 get {
2950 return DateTime.FromFileTime(create);
2954 public DateTime ExitTime {
2955 get {
2956 return DateTime.FromFileTime(exit);
2960 public TimeSpan PrivilegedProcessorTime {
2961 get {
2962 return new TimeSpan(kernel);
2966 public TimeSpan UserProcessorTime {
2967 get {
2968 return new TimeSpan(user);
2972 public TimeSpan TotalProcessorTime {
2973 get {
2974 return new TimeSpan(user + kernel);
2979 #if !MONO
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();
3009 else {
3010 ShellExecuteFunction();
3012 return _succeeded;
3015 public int ErrorCode {
3016 get {
3017 return _errorCode;
3021 #endif