We need you! We're working hard on the next version of Developer Fusion -
Let us know what you think we should be up to!
- namespace System.Diagnostics
- {
- using System.Text;
- using System.Threading;
- using System.Runtime.InteropServices;
- using System.ComponentModel;
- using System.ComponentModel.Design;
- using System.Runtime.CompilerServices;
- using System.Runtime.ConstrainedExecution;
- using System.Diagnostics;
- using System;
- using System.Collections;
- using System.IO;
- using Microsoft.Win32;
- using Microsoft.Win32.SafeHandles;
- using System.Collections.Specialized;
- using System.Globalization;
- using System.Security;
- using System.Security.Permissions;
- using System.Security.Principal;
- using System.Runtime.Versioning;
-
- /// <devdoc>
- /// <para>
- /// Provides access to local and remote
- /// processes. Enables you to start and stop system processes.
- /// </para>
- /// </devdoc>
-
- [MonitoringDescription(SR.ProcessDesc), DefaultEvent("Exited"), DefaultProperty("StartInfo"), Designer("System.Diagnostics.Design.ProcessDesigner, " + AssemblyRef.SystemDesign), PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust"), PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust"), HostProtection(SharedState = true, Synchronization = true, ExternalProcessMgmt = true, SelfAffectingProcessMgmt = true)]
- public class Process : Component
- {
-
-
-
-
- bool haveProcessId;
- int processId;
- bool haveProcessHandle;
- SafeProcessHandle m_processHandle;
- bool isRemoteMachine;
- string machineName;
- ProcessInfo processInfo;
-
-
- bool haveMainWindow;
- IntPtr mainWindowHandle;
-
- string mainWindowTitle;
-
- bool haveWorkingSetLimits;
- IntPtr minWorkingSet;
- IntPtr maxWorkingSet;
-
- bool haveProcessorAffinity;
- IntPtr processorAffinity;
-
- bool havePriorityClass;
- ProcessPriorityClass priorityClass;
-
- ProcessStartInfo startInfo;
-
- bool watchForExit;
- bool watchingForExit;
- EventHandler onExited;
- bool exited;
- int exitCode;
- bool signaled;
-
- DateTime exitTime;
- bool haveExitTime;
-
- bool responding;
- bool haveResponding;
-
- bool priorityBoostEnabled;
- bool havePriorityBoostEnabled;
-
- bool raisedOnExited;
- RegisteredWaitHandle registeredWaitHandle;
- WaitHandle waitHandle;
- ISynchronizeInvoke synchronizingObject;
- StreamReader standardOutput;
- StreamWriter standardInput;
- StreamReader standardError;
- OperatingSystem operatingSystem;
- bool disposed;
-
-
-
- private enum StreamReadMode
- {
- undefined,
- syncMode,
- asyncMode
- }
-
- StreamReadMode outputStreamReadMode;
- StreamReadMode errorStreamReadMode;
-
-
-
- [Browsable(true), MonitoringDescription(SR.ProcessAssociated)]
-
- public event DataReceivedEventHandler OutputDataReceived;
- [Browsable(true), MonitoringDescription(SR.ProcessAssociated)]
-
- public event DataReceivedEventHandler ErrorDataReceived;
-
- internal AsyncStreamReader output;
- internal AsyncStreamReader error;
- internal bool pendingOutputRead;
- internal bool pendingErrorRead;
-
-
- private static SafeFileHandle InvalidPipeHandle = new SafeFileHandle(IntPtr.Zero, false);
- #if DEBUG
- static internal TraceSwitch processTracing = new TraceSwitch("processTracing", "Controls debug output from Process component");
- #else
- static internal TraceSwitch processTracing = null;
- #endif
-
-
-
-
-
- /// <devdoc>
- /// <para>
- /// Initializes a new instance of the <see cref='System.Diagnostics.Process'/> class.
- /// </para>
- /// </devdoc>
- public Process()
- {
- machineName = ".";
- outputStreamReadMode = StreamReadMode.undefined;
- errorStreamReadMode = StreamReadMode.undefined;
- }
-
- Process(string machineName, bool isRemoteMachine, int processId, ProcessInfo processInfo) : base()
- {
- Debug.Assert(SyntaxCheck.CheckMachineName(machineName), "The machine name should be valid!");
- this.processInfo = processInfo;
- this.machineName = machineName;
- this.isRemoteMachine = isRemoteMachine;
- this.processId = processId;
- this.haveProcessId = true;
- outputStreamReadMode = StreamReadMode.undefined;
- errorStreamReadMode = StreamReadMode.undefined;
- }
-
-
-
-
-
- /// <devdoc>
- /// Returns whether this process component is associated with a real process.
- /// </devdoc>
- /// <internalonly/>
- [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessAssociated)]
- bool Associated {
- get { return haveProcessId || haveProcessHandle; }
- }
-
-
- /// <devdoc>
- /// <para>
- /// Gets
- /// the
- /// value that was specified by the associated process when it was terminated.
- /// </para>
- /// </devdoc>
- [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessExitCode)]
- public int ExitCode {
- get {
- EnsureState(State.Exited);
- return exitCode;
- }
- }
-
- /// <devdoc>
- /// <para>
- /// Gets a
- /// value indicating whether the associated process has been terminated.
- /// </para>
- /// </devdoc>
- [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessTerminated)]
- public bool HasExited {
- get {
- if (!exited) {
- EnsureState(State.Associated);
- SafeProcessHandle handle = null;
- try {
- handle = GetProcessHandle(NativeMethods.PROCESS_QUERY_INFORMATION | NativeMethods.SYNCHRONIZE, false);
- if (handle.IsInvalid) {
- exited = true;
- }
- else {
- int exitCode;
-
- if (NativeMethods.GetExitCodeProcess(handle, out exitCode) && exitCode != NativeMethods.STILL_ACTIVE) {
- this.exited = true;
- this.exitCode = exitCode;
- }
- else {
-
-
-
-
-
-
- if (!signaled) {
- ProcessWaitHandle wh = null;
- try {
- wh = new ProcessWaitHandle(handle);
- this.signaled = wh.WaitOne(0, false);
- }
- finally {
-
- if (wh != null)
- wh.Close();
- }
- }
- if (signaled) {
- if (!NativeMethods.GetExitCodeProcess(handle, out exitCode))
- throw new Win32Exception();
-
- this.exited = true;
- this.exitCode = exitCode;
- }
- }
- }
- }
- finally {
- ReleaseProcessHandle(handle);
- }
-
- if (exited) {
- RaiseOnExited();
- }
- }
- return exited;
- }
- }
-
- private ProcessThreadTimes GetProcessTimes()
- {
- ProcessThreadTimes processTimes = new ProcessThreadTimes();
- SafeProcessHandle handle = null;
- try {
- handle = GetProcessHandle(NativeMethods.PROCESS_QUERY_INFORMATION, false);
- if (handle.IsInvalid) {
-
-
-
- throw new InvalidOperationException(SR.GetString(SR.ProcessHasExited, processId.ToString(CultureInfo.CurrentCulture)));
- }
-
- if (!NativeMethods.GetProcessTimes(handle, out processTimes.create, out processTimes.exit, out processTimes.kernel, out processTimes.user)) {
- throw new Win32Exception();
- }
-
- }
- finally {
- ReleaseProcessHandle(handle);
- }
- return processTimes;
- }
-
-
- /// <devdoc>
- /// <para>
- /// Returns the native handle for the associated process. The handle is only available
- /// if this component started the process.
- /// </para>
- /// </devdoc>
- [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessHandle)]
- public IntPtr Handle {
- [ResourceExposure(ResourceScope.Machine)]
- [ResourceConsumption(ResourceScope.Machine)]
- get {
- EnsureState(State.Associated);
- return OpenProcessHandle().DangerousGetHandle();
- }
- }
-
-
- /// <devdoc>
- /// <para>
- /// Gets
- /// the unique identifier for the associated process.
- /// </para>
- /// </devdoc>
- [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessId)]
- public int Id {
- get {
- EnsureState(State.HaveId);
- return processId;
- }
- }
-
- /// <devdoc>
- /// <para>
- /// Gets
- /// the name of the computer on which the associated process is running.
- /// </para>
- /// </devdoc>
- [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessMachineName)]
- public string MachineName {
- get {
- EnsureState(State.Associated);
- return machineName;
- }
- }
-
-
- /// <devdoc>
- /// <para>
- /// Gets
- /// the friendly name of the process.
- /// </para>
- /// </devdoc>
- [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessProcessName)]
- public string ProcessName {
- get { return "ProcessName not implemented for PAL"; }
- }
-
-
- /// <devdoc>
- /// <para>
- /// Gets or sets the properties to pass into the <see cref='System.Diagnostics.Process.Start'/> method for the <see cref='System.Diagnostics.Process'/>
- /// .
- /// </para>
- /// </devdoc>
- [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), MonitoringDescription(SR.ProcessStartInfo)]
- public ProcessStartInfo StartInfo {
- get {
- if (startInfo == null) {
- startInfo = new ProcessStartInfo(this);
- }
- return startInfo;
- }
- set {
- if (value == null) {
- throw new ArgumentNullException("value");
- }
- startInfo = value;
- }
- }
-
-
- /// <devdoc>
- /// Represents the object used to marshal the event handler
- /// calls issued as a result of a Process exit. Normally
- /// this property will be set when the component is placed
- /// inside a control or a from, since those components are
- /// bound to a specific thread.
- /// </devdoc>
- [Browsable(false), DefaultValue(null), MonitoringDescription(SR.ProcessSynchronizingObject)]
- public ISynchronizeInvoke SynchronizingObject {
- get {
- if (this.synchronizingObject == null && DesignMode) {
- IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
- if (host != null) {
- object baseComponent = host.RootComponent;
- if (baseComponent != null && baseComponent is ISynchronizeInvoke)
- this.synchronizingObject = (ISynchronizeInvoke)baseComponent;
- }
- }
-
- return this.synchronizingObject;
- }
-
- set { this.synchronizingObject = value; }
- }
-
-
- [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessVirtualMemorySize)]
- [System.Runtime.InteropServices.ComVisible(false)]
- public long VirtualMemorySize64 {
- get {
- EnsureState(State.HaveNtProcessInfo);
- return processInfo.virtualBytes;
- }
- }
-
- /// <devdoc>
- /// <para>
- /// Gets or sets whether the <see cref='System.Diagnostics.Process.Exited'/>
- /// event is fired
- /// when the process terminates.
- /// </para>
- /// </devdoc>
- [Browsable(false), DefaultValue(false), MonitoringDescription(SR.ProcessEnableRaisingEvents)]
- public bool EnableRaisingEvents {
- get { return watchForExit; }
- set {
- if (value != watchForExit) {
- if (Associated) {
- if (value) {
- OpenProcessHandle();
- EnsureWatchingForExit();
- }
- else {
- StopWatchingForExit();
- }
- }
- watchForExit = value;
- }
- }
- }
-
-
- /// <devdoc>
- /// <para>[To be supplied.]</para>
- /// </devdoc>
- [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessStandardInput)]
- public StreamWriter StandardInput {
- get {
- if (standardInput == null) {
- throw new InvalidOperationException(SR.GetString(SR.CantGetStandardIn));
- }
-
- return standardInput;
- }
- }
-
- /// <devdoc>
- /// <para>[To be supplied.]</para>
- /// </devdoc>
- [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessStandardOutput)]
- public StreamReader StandardOutput {
- get {
- if (standardOutput == null) {
- throw new InvalidOperationException(SR.GetString(SR.CantGetStandardOut));
- }
-
- if (outputStreamReadMode == StreamReadMode.undefined) {
- outputStreamReadMode = StreamReadMode.syncMode;
- }
- else if (outputStreamReadMode != StreamReadMode.syncMode) {
- throw new InvalidOperationException(SR.GetString(SR.CantMixSyncAsyncOperation));
- }
-
- return standardOutput;
- }
- }
-
- /// <devdoc>
- /// <para>[To be supplied.]</para>
- /// </devdoc>
- [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessStandardError)]
- public StreamReader StandardError {
- get {
- if (standardError == null) {
- throw new InvalidOperationException(SR.GetString(SR.CantGetStandardError));
- }
-
- if (errorStreamReadMode == StreamReadMode.undefined) {
- errorStreamReadMode = StreamReadMode.syncMode;
- }
- else if (errorStreamReadMode != StreamReadMode.syncMode) {
- throw new InvalidOperationException(SR.GetString(SR.CantMixSyncAsyncOperation));
- }
-
- return standardError;
- }
- }
-
-
- [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessWorkingSet)]
- [System.Runtime.InteropServices.ComVisible(false)]
- public long WorkingSet64 {
- get {
- EnsureState(State.HaveNtProcessInfo);
- return processInfo.workingSet;
- }
- }
-
- [Category("Behavior"), MonitoringDescription(SR.ProcessExited)]
- public event EventHandler Exited {
- add { onExited += value; }
- remove { onExited -= value; }
- }
-
-
- /// <devdoc>
- /// Release the temporary handle we used to get process information.
- /// If we used the process handle stored in the process object (we have all access to the handle,) don't release it.
- /// </devdoc>
- /// <internalonly/>
- void ReleaseProcessHandle(SafeProcessHandle handle)
- {
- if (handle == null) {
- return;
- }
-
- if (haveProcessHandle && handle == m_processHandle) {
- return;
- }
- Debug.WriteLineIf(processTracing.TraceVerbose, "Process - CloseHandle(process)");
- handle.Close();
- }
-
- /// <devdoc>
- /// This is called from the threadpool when a proces exits.
- /// </devdoc>
- /// <internalonly/>
- private void CompletionCallback(object context, bool wasSignaled)
- {
- StopWatchingForExit();
- RaiseOnExited();
- }
-
- /// <internalonly/>
- /// <devdoc>
- /// <para>
- /// Free any resources associated with this component.
- /// </para>
- /// </devdoc>
- protected override void Dispose(bool disposing)
- {
- if (!disposed) {
- if (disposing) {
-
- Close();
- }
- this.disposed = true;
- base.Dispose(disposing);
- }
- }
-
- /// <devdoc>
- /// <para>
- /// Frees any resources associated with this component.
- /// </para>
- /// </devdoc>
- public void Close()
- {
- if (Associated) {
- if (haveProcessHandle) {
- StopWatchingForExit();
- Debug.WriteLineIf(processTracing.TraceVerbose, "Process - CloseHandle(process) in Close()");
- m_processHandle.Close();
- m_processHandle = null;
- haveProcessHandle = false;
- }
- haveProcessId = false;
- isRemoteMachine = false;
- machineName = ".";
- raisedOnExited = false;
-
-
-
-
- standardOutput = null;
- standardInput = null;
- standardError = null;
-
-
- Refresh();
- }
- }
-
- /// <devdoc>
- /// Helper method for checking preconditions when accessing properties.
- /// </devdoc>
- /// <internalonly/>
- void EnsureState(State state)
- {
- if ((state & State.IsWin2k) != (State)0) {
- throw new PlatformNotSupportedException(SR.GetString(SR.Win2kRequired));
- }
-
- if ((state & State.IsNt) != (State)0) {
- throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequired));
- }
-
- if ((state & State.Associated) != (State)0)
- if (!Associated)
- throw new InvalidOperationException(SR.GetString(SR.NoAssociatedProcess));
-
- if ((state & State.HaveId) != (State)0) {
- if (!haveProcessId) {
- EnsureState(State.Associated);
- throw new InvalidOperationException(SR.GetString(SR.ProcessIdRequired));
- }
- }
-
- if ((state & State.IsLocal) != (State)0 && isRemoteMachine) {
- throw new NotSupportedException(SR.GetString(SR.NotSupportedRemote));
- }
-
- if ((state & State.HaveProcessInfo) != (State)0) {
- throw new InvalidOperationException(SR.GetString(SR.NoProcessInfo));
- }
-
- if ((state & State.Exited) != (State)0) {
- if (!HasExited) {
- throw new InvalidOperationException(SR.GetString(SR.WaitTillExit));
- }
-
- if (!haveProcessHandle) {
- throw new InvalidOperationException(SR.GetString(SR.NoProcessHandle));
- }
- }
- }
-
- /// <devdoc>
- /// Make sure we are watching for a process exit.
- /// </devdoc>
- /// <internalonly/>
- void EnsureWatchingForExit()
- {
- if (!watchingForExit) {
- Debug.Assert(haveProcessHandle, "Process.EnsureWatchingForExit called with no process handle");
- Debug.Assert(Associated, "Process.EnsureWatchingForExit called with no associated process");
- watchingForExit = true;
- try {
- this.waitHandle = new ProcessWaitHandle(m_processHandle);
- this.registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(this.waitHandle, new WaitOrTimerCallback(this.CompletionCallback), null, -1, true);
- }
- catch {
- watchingForExit = false;
- throw;
- }
- }
- }
-
-
- /// <devdoc>
- /// <para>
- /// Returns a new <see cref='System.Diagnostics.Process'/>
- /// component and associates it with the current active process.
- /// </para>
- /// </devdoc>
- public static Process GetCurrentProcess()
- {
- return new Process(".", false, NativeMethods.GetCurrentProcessId(), null);
- }
-
- /// <devdoc>
- /// <para>
- /// Raises the <see cref='System.Diagnostics.Process.Exited'/> event.
- /// </para>
- /// </devdoc>
- protected void OnExited()
- {
- EventHandler exited = onExited;
- if (exited != null) {
- if (this.SynchronizingObject != null && this.SynchronizingObject.InvokeRequired)
- this.SynchronizingObject.BeginInvoke(exited, new object[] {this, EventArgs.Empty});
- else
- exited(this, EventArgs.Empty);
- }
- }
-
- /// <devdoc>
- /// Gets a short-term handle to the process, with the given access.
- /// If a handle is stored in current process object, then use it.
- /// Note that the handle we stored in current process object will have all access we need.
- /// </devdoc>
- /// <internalonly/>
- SafeProcessHandle GetProcessHandle(int access, bool throwIfExited)
- {
- Debug.WriteLineIf(processTracing.TraceVerbose, "GetProcessHandle(access = 0x" + access.ToString("X8", CultureInfo.InvariantCulture) + ", throwIfExited = " + throwIfExited + ")");
- #if DEBUG
- if (processTracing.TraceVerbose) {
- StackFrame calledFrom = new StackTrace(true).GetFrame(0);
- Debug.WriteLine(" called from " + calledFrom.GetFileName() + ", line " + calledFrom.GetFileLineNumber());
- }
- #endif
- if (haveProcessHandle) {
- if (throwIfExited) {
-
-
-
- ProcessWaitHandle waitHandle = null;
- try {
- waitHandle = new ProcessWaitHandle(m_processHandle);
- if (waitHandle.WaitOne(0, false)) {
- if (haveProcessId)
- throw new InvalidOperationException(SR.GetString(SR.ProcessHasExited, processId.ToString(CultureInfo.CurrentCulture)));
- else
- throw new InvalidOperationException(SR.GetString(SR.ProcessHasExitedNoId));
- }
- }
- finally {
- if (waitHandle != null) {
- waitHandle.Close();
- }
- }
- }
- return m_processHandle;
- }
- else {
- EnsureState(State.HaveId | State.IsLocal);
- SafeProcessHandle handle = SafeProcessHandle.InvalidHandle;
- IntPtr pseudohandle = NativeMethods.GetCurrentProcess();
-
- if (!NativeMethods.DuplicateHandle(new HandleRef(this, pseudohandle), new HandleRef(this, pseudohandle), new HandleRef(this, pseudohandle), out handle, 0, false, NativeMethods.DUPLICATE_SAME_ACCESS | NativeMethods.DUPLICATE_CLOSE_SOURCE)) {
- throw new Win32Exception();
- }
- if (throwIfExited && (access & NativeMethods.PROCESS_QUERY_INFORMATION) != 0) {
- if (NativeMethods.GetExitCodeProcess(handle, out exitCode) && exitCode != NativeMethods.STILL_ACTIVE) {
- throw new InvalidOperationException(SR.GetString(SR.ProcessHasExited, processId.ToString(CultureInfo.CurrentCulture)));
- }
- }
- return handle;
- }
-
- }
-
- /// <devdoc>
- /// Gets a short-term handle to the process, with the given access. If a handle exists,
- /// then it is reused. If the process has exited, it throws an exception.
- /// </devdoc>
- /// <internalonly/>
- SafeProcessHandle GetProcessHandle(int access)
- {
- return GetProcessHandle(access, true);
- }
-
- /// <devdoc>
- /// Opens a long-term handle to the process, with all access. If a handle exists,
- /// then it is reused. If the process has exited, it throws an exception.
- /// </devdoc>
- /// <internalonly/>
- SafeProcessHandle OpenProcessHandle()
- {
- if (!haveProcessHandle) {
-
- if (this.disposed) {
- throw new ObjectDisposedException(GetType().Name);
- }
-
- SetProcessHandle(GetProcessHandle(NativeMethods.PROCESS_ALL_ACCESS));
- }
- return m_processHandle;
- }
-
- /// <devdoc>
- /// Raise the Exited event, but make sure we don't do it more than once.
- /// </devdoc>
- /// <internalonly/>
- void RaiseOnExited()
- {
- if (!raisedOnExited) {
- lock (this) {
- if (!raisedOnExited) {
- raisedOnExited = true;
- OnExited();
- }
- }
- }
- }
-
- /// <devdoc>
- /// <para>
- /// Discards any information about the associated process
- /// that has been cached inside the process component. After <see cref='System.Diagnostics.Process.Refresh'/> is called, the
- /// first request for information for each property causes the process component
- /// to obtain a new value from the associated process.
- /// </para>
- /// </devdoc>
- public void Refresh()
- {
- processInfo = null;
- mainWindowTitle = null;
- exited = false;
- signaled = false;
- haveMainWindow = false;
- haveWorkingSetLimits = false;
- haveProcessorAffinity = false;
- havePriorityClass = false;
- haveExitTime = false;
- haveResponding = false;
- havePriorityBoostEnabled = false;
- }
-
- /// <devdoc>
- /// Helper to associate a process handle with this component.
- /// </devdoc>
- /// <internalonly/>
- void SetProcessHandle(SafeProcessHandle processHandle)
- {
- this.m_processHandle = processHandle;
- this.haveProcessHandle = true;
-