The Labs \ Source Viewer \ SSCLI \ System.Diagnostics \ ProcessThreadTimes

  1. //------------------------------------------------------------------------------
  2. // <copyright file="Process.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.Diagnostics
  16. {
  17.     using System.Text;
  18.     using System.Threading;
  19.     using System.Runtime.InteropServices;
  20.     using System.ComponentModel;
  21.     using System.ComponentModel.Design;
  22.     using System.Runtime.CompilerServices;
  23.     using System.Runtime.ConstrainedExecution;
  24.     using System.Diagnostics;
  25.     using System;
  26.     using System.Collections;
  27.     using System.IO;
  28.     using Microsoft.Win32;
  29.     using Microsoft.Win32.SafeHandles;
  30.     using System.Collections.Specialized;
  31.     using System.Globalization;
  32.     using System.Security;
  33.     using System.Security.Permissions;
  34.     using System.Security.Principal;
  35.     using System.Runtime.Versioning;
  36.    
  37.     /// <devdoc>
  38.     /// <para>
  39.     /// Provides access to local and remote
  40.     /// processes. Enables you to start and stop system processes.
  41.     /// </para>
  42.     /// </devdoc>
  43.         // Disabling partial trust scenarios
  44.     [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)]
  45.     public class Process : Component
  46.     {
  47.         //
  48.         // FIELDS
  49.         //
  50.        
  51.         bool haveProcessId;
  52.         int processId;
  53.         bool haveProcessHandle;
  54.         SafeProcessHandle m_processHandle;
  55.         bool isRemoteMachine;
  56.         string machineName;
  57.         ProcessInfo processInfo;
  58.        
  59.        
  60.         bool haveMainWindow;
  61.         IntPtr mainWindowHandle;
  62.         // no need to use SafeHandle for window
  63.         string mainWindowTitle;
  64.        
  65.         bool haveWorkingSetLimits;
  66.         IntPtr minWorkingSet;
  67.         IntPtr maxWorkingSet;
  68.        
  69.         bool haveProcessorAffinity;
  70.         IntPtr processorAffinity;
  71.        
  72.         bool havePriorityClass;
  73.         ProcessPriorityClass priorityClass;
  74.        
  75.         ProcessStartInfo startInfo;
  76.        
  77.         bool watchForExit;
  78.         bool watchingForExit;
  79.         EventHandler onExited;
  80.         bool exited;
  81.         int exitCode;
  82.         bool signaled;
  83.        
  84.         DateTime exitTime;
  85.         bool haveExitTime;
  86.        
  87.         bool responding;
  88.         bool haveResponding;
  89.        
  90.         bool priorityBoostEnabled;
  91.         bool havePriorityBoostEnabled;
  92.        
  93.         bool raisedOnExited;
  94.         RegisteredWaitHandle registeredWaitHandle;
  95.         WaitHandle waitHandle;
  96.         ISynchronizeInvoke synchronizingObject;
  97.         StreamReader standardOutput;
  98.         StreamWriter standardInput;
  99.         StreamReader standardError;
  100.         OperatingSystem operatingSystem;
  101.         bool disposed;
  102.        
  103.         // This enum defines the operation mode for redirected process stream.
  104.         // We don't support switching between synchronous mode and asynchronous mode.
  105.         private enum StreamReadMode
  106.         {
  107.             undefined,
  108.             syncMode,
  109.             asyncMode
  110.         }
  111.        
  112.         StreamReadMode outputStreamReadMode;
  113.         StreamReadMode errorStreamReadMode;
  114.        
  115.        
  116.         // Support for asynchrously reading streams
  117.         [Browsable(true), MonitoringDescription(SR.ProcessAssociated)]
  118.         //[System.Runtime.InteropServices.ComVisible(false)]
  119.         public event DataReceivedEventHandler OutputDataReceived;
  120.         [Browsable(true), MonitoringDescription(SR.ProcessAssociated)]
  121.         //[System.Runtime.InteropServices.ComVisible(false)]
  122.         public event DataReceivedEventHandler ErrorDataReceived;
  123.         // Abstract the stream details
  124.         internal AsyncStreamReader output;
  125.         internal AsyncStreamReader error;
  126.         internal bool pendingOutputRead;
  127.         internal bool pendingErrorRead;
  128.        
  129.        
  130.         private static SafeFileHandle InvalidPipeHandle = new SafeFileHandle(IntPtr.Zero, false);
  131.         #if DEBUG
  132.         static internal TraceSwitch processTracing = new TraceSwitch("processTracing", "Controls debug output from Process component");
  133.         #else
  134.         static internal TraceSwitch processTracing = null;
  135.         #endif
  136.        
  137.         //
  138.         // CONSTRUCTORS
  139.         //
  140.        
  141.         /// <devdoc>
  142.         /// <para>
  143.         /// Initializes a new instance of the <see cref='System.Diagnostics.Process'/> class.
  144.         /// </para>
  145.         /// </devdoc>
  146.         public Process()
  147.         {
  148.             machineName = ".";
  149.             outputStreamReadMode = StreamReadMode.undefined;
  150.             errorStreamReadMode = StreamReadMode.undefined;
  151.         }
  152.        
  153.         Process(string machineName, bool isRemoteMachine, int processId, ProcessInfo processInfo) : base()
  154.         {
  155.             Debug.Assert(SyntaxCheck.CheckMachineName(machineName), "The machine name should be valid!");
  156.             this.processInfo = processInfo;
  157.             this.machineName = machineName;
  158.             this.isRemoteMachine = isRemoteMachine;
  159.             this.processId = processId;
  160.             this.haveProcessId = true;
  161.             outputStreamReadMode = StreamReadMode.undefined;
  162.             errorStreamReadMode = StreamReadMode.undefined;
  163.         }
  164.        
  165.         //
  166.         // PROPERTIES
  167.         //
  168.        
  169.         /// <devdoc>
  170.         /// Returns whether this process component is associated with a real process.
  171.         /// </devdoc>
  172.         /// <internalonly/>
  173.         [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessAssociated)]
  174.         bool Associated {
  175.             get { return haveProcessId || haveProcessHandle; }
  176.         }
  177.        
  178.        
  179.         /// <devdoc>
  180.         /// <para>
  181.         /// Gets
  182.         /// the
  183.         /// value that was specified by the associated process when it was terminated.
  184.         /// </para>
  185.         /// </devdoc>
  186.         [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessExitCode)]
  187.         public int ExitCode {
  188.             get {
  189.                 EnsureState(State.Exited);
  190.                 return exitCode;
  191.             }
  192.         }
  193.        
  194.         /// <devdoc>
  195.         /// <para>
  196.         /// Gets a
  197.         /// value indicating whether the associated process has been terminated.
  198.         /// </para>
  199.         /// </devdoc>
  200.         [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessTerminated)]
  201.         public bool HasExited {
  202.             get {
  203.                 if (!exited) {
  204.                     EnsureState(State.Associated);
  205.                     SafeProcessHandle handle = null;
  206.                     try {
  207.                         handle = GetProcessHandle(NativeMethods.PROCESS_QUERY_INFORMATION | NativeMethods.SYNCHRONIZE, false);
  208.                         if (handle.IsInvalid) {
  209.                             exited = true;
  210.                         }
  211.                         else {
  212.                             int exitCode;
  213.                            
  214.                             if (NativeMethods.GetExitCodeProcess(handle, out exitCode) && exitCode != NativeMethods.STILL_ACTIVE) {
  215.                                 this.exited = true;
  216.                                 this.exitCode = exitCode;
  217.                             }
  218.                             else {
  219.                                
  220.                                 // The best check for exit is that the kernel process object handle is invalid,
  221.                                 // or that it is valid and signaled. Checking if the exit code != STILL_ACTIVE
  222.                                 // does not guarantee the process is closed,
  223.                                 // since some process could return an actual STILL_ACTIVE exit code (259).
  224.                                 // if we just came from WaitForExit, don't repeat
  225.                                 if (!signaled) {
  226.                                     ProcessWaitHandle wh = null;
  227.                                     try {
  228.                                         wh = new ProcessWaitHandle(handle);
  229.                                         this.signaled = wh.WaitOne(0, false);
  230.                                     }
  231.                                     finally {
  232.                                        
  233.                                         if (wh != null)
  234.                                             wh.Close();
  235.                                     }
  236.                                 }
  237.                                 if (signaled) {
  238.                                     if (!NativeMethods.GetExitCodeProcess(handle, out exitCode))
  239.                                         throw new Win32Exception();
  240.                                    
  241.                                     this.exited = true;
  242.                                     this.exitCode = exitCode;
  243.                                 }
  244.                             }
  245.                         }
  246.                     }
  247.                     finally {
  248.                         ReleaseProcessHandle(handle);
  249.                     }
  250.                    
  251.                     if (exited) {
  252.                         RaiseOnExited();
  253.                     }
  254.                 }
  255.                 return exited;
  256.             }
  257.         }
  258.        
  259.         private ProcessThreadTimes GetProcessTimes()
  260.         {
  261.             ProcessThreadTimes processTimes = new ProcessThreadTimes();
  262.             SafeProcessHandle handle = null;
  263.             try {
  264.                 handle = GetProcessHandle(NativeMethods.PROCESS_QUERY_INFORMATION, false);
  265.                 if (handle.IsInvalid) {
  266.                     // On OS older than XP, we will not be able to get the handle for a process
  267.                     // after it terminates.
  268.                     // On Windows XP and newer OS, the information about a process will stay longer.
  269.                     throw new InvalidOperationException(SR.GetString(SR.ProcessHasExited, processId.ToString(CultureInfo.CurrentCulture)));
  270.                 }
  271.                
  272.                 if (!NativeMethods.GetProcessTimes(handle, out processTimes.create, out processTimes.exit, out processTimes.kernel, out processTimes.user)) {
  273.                     throw new Win32Exception();
  274.                 }
  275.                
  276.             }
  277.             finally {
  278.                 ReleaseProcessHandle(handle);
  279.             }
  280.             return processTimes;
  281.         }
  282.        
  283.        
  284.         /// <devdoc>
  285.         /// <para>
  286.         /// Returns the native handle for the associated process. The handle is only available
  287.         /// if this component started the process.
  288.         /// </para>
  289.         /// </devdoc>
  290.         [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessHandle)]
  291.         public IntPtr Handle {
  292.             [ResourceExposure(ResourceScope.Machine)]
  293.             [ResourceConsumption(ResourceScope.Machine)]
  294.             get {
  295.                 EnsureState(State.Associated);
  296.                 return OpenProcessHandle().DangerousGetHandle();
  297.             }
  298.         }
  299.        
  300.        
  301.         /// <devdoc>
  302.         /// <para>
  303.         /// Gets
  304.         /// the unique identifier for the associated process.
  305.         /// </para>
  306.         /// </devdoc>
  307.         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessId)]
  308.         public int Id {
  309.             get {
  310.                 EnsureState(State.HaveId);
  311.                 return processId;
  312.             }
  313.         }
  314.        
  315.         /// <devdoc>
  316.         /// <para>
  317.         /// Gets
  318.         /// the name of the computer on which the associated process is running.
  319.         /// </para>
  320.         /// </devdoc>
  321.         [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessMachineName)]
  322.         public string MachineName {
  323.             get {
  324.                 EnsureState(State.Associated);
  325.                 return machineName;
  326.             }
  327.         }
  328.        
  329.        
  330.         /// <devdoc>
  331.         /// <para>
  332.         /// Gets
  333.         /// the friendly name of the process.
  334.         /// </para>
  335.         /// </devdoc>
  336.         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessProcessName)]
  337.         public string ProcessName {
  338.             get { return "ProcessName not implemented for PAL"; }
  339.         }
  340.        
  341.        
  342.         /// <devdoc>
  343.         /// <para>
  344.         /// Gets or sets the properties to pass into the <see cref='System.Diagnostics.Process.Start'/> method for the <see cref='System.Diagnostics.Process'/>
  345.         /// .
  346.         /// </para>
  347.         /// </devdoc>
  348.         [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), MonitoringDescription(SR.ProcessStartInfo)]
  349.         public ProcessStartInfo StartInfo {
  350.             get {
  351.                 if (startInfo == null) {
  352.                     startInfo = new ProcessStartInfo(this);
  353.                 }
  354.                 return startInfo;
  355.             }
  356.             set {
  357.                 if (value == null) {
  358.                     throw new ArgumentNullException("value");
  359.                 }
  360.                 startInfo = value;
  361.             }
  362.         }
  363.        
  364.        
  365.         /// <devdoc>
  366.         /// Represents the object used to marshal the event handler
  367.         /// calls issued as a result of a Process exit. Normally
  368.         /// this property will be set when the component is placed
  369.         /// inside a control or a from, since those components are
  370.         /// bound to a specific thread.
  371.         /// </devdoc>
  372.         [Browsable(false), DefaultValue(null), MonitoringDescription(SR.ProcessSynchronizingObject)]
  373.         public ISynchronizeInvoke SynchronizingObject {
  374.             get {
  375.                 if (this.synchronizingObject == null && DesignMode) {
  376.                     IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
  377.                     if (host != null) {
  378.                         object baseComponent = host.RootComponent;
  379.                         if (baseComponent != null && baseComponent is ISynchronizeInvoke)
  380.                             this.synchronizingObject = (ISynchronizeInvoke)baseComponent;
  381.                     }
  382.                 }
  383.                
  384.                 return this.synchronizingObject;
  385.             }
  386.            
  387.             set { this.synchronizingObject = value; }
  388.         }
  389.        
  390.        
  391.         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessVirtualMemorySize)]
  392.         [System.Runtime.InteropServices.ComVisible(false)]
  393.         public long VirtualMemorySize64 {
  394.             get {
  395.                 EnsureState(State.HaveNtProcessInfo);
  396.                 return processInfo.virtualBytes;
  397.             }
  398.         }
  399.        
  400.         /// <devdoc>
  401.         /// <para>
  402.         /// Gets or sets whether the <see cref='System.Diagnostics.Process.Exited'/>
  403.         /// event is fired
  404.         /// when the process terminates.
  405.         /// </para>
  406.         /// </devdoc>
  407.         [Browsable(false), DefaultValue(false), MonitoringDescription(SR.ProcessEnableRaisingEvents)]
  408.         public bool EnableRaisingEvents {
  409.             get { return watchForExit; }
  410.             set {
  411.                 if (value != watchForExit) {
  412.                     if (Associated) {
  413.                         if (value) {
  414.                             OpenProcessHandle();
  415.                             EnsureWatchingForExit();
  416.                         }
  417.                         else {
  418.                             StopWatchingForExit();
  419.                         }
  420.                     }
  421.                     watchForExit = value;
  422.                 }
  423.             }
  424.         }
  425.        
  426.        
  427.         /// <devdoc>
  428.         /// <para>[To be supplied.]</para>
  429.         /// </devdoc>
  430.         [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessStandardInput)]
  431.         public StreamWriter StandardInput {
  432.             get {
  433.                 if (standardInput == null) {
  434.                     throw new InvalidOperationException(SR.GetString(SR.CantGetStandardIn));
  435.                 }
  436.                
  437.                 return standardInput;
  438.             }
  439.         }
  440.        
  441.         /// <devdoc>
  442.         /// <para>[To be supplied.]</para>
  443.         /// </devdoc>
  444.         [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessStandardOutput)]
  445.         public StreamReader StandardOutput {
  446.             get {
  447.                 if (standardOutput == null) {
  448.                     throw new InvalidOperationException(SR.GetString(SR.CantGetStandardOut));
  449.                 }
  450.                
  451.                 if (outputStreamReadMode == StreamReadMode.undefined) {
  452.                     outputStreamReadMode = StreamReadMode.syncMode;
  453.                 }
  454.                 else if (outputStreamReadMode != StreamReadMode.syncMode) {
  455.                     throw new InvalidOperationException(SR.GetString(SR.CantMixSyncAsyncOperation));
  456.                 }
  457.                
  458.                 return standardOutput;
  459.             }
  460.         }
  461.        
  462.         /// <devdoc>
  463.         /// <para>[To be supplied.]</para>
  464.         /// </devdoc>
  465.         [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessStandardError)]
  466.         public StreamReader StandardError {
  467.             get {
  468.                 if (standardError == null) {
  469.                     throw new InvalidOperationException(SR.GetString(SR.CantGetStandardError));
  470.                 }
  471.                
  472.                 if (errorStreamReadMode == StreamReadMode.undefined) {
  473.                     errorStreamReadMode = StreamReadMode.syncMode;
  474.                 }
  475.                 else if (errorStreamReadMode != StreamReadMode.syncMode) {
  476.                     throw new InvalidOperationException(SR.GetString(SR.CantMixSyncAsyncOperation));
  477.                 }
  478.                
  479.                 return standardError;
  480.             }
  481.         }
  482.        
  483.        
  484.         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessWorkingSet)]
  485.         [System.Runtime.InteropServices.ComVisible(false)]
  486.         public long WorkingSet64 {
  487.             get {
  488.                 EnsureState(State.HaveNtProcessInfo);
  489.                 return processInfo.workingSet;
  490.             }
  491.         }
  492.        
  493.         [Category("Behavior"), MonitoringDescription(SR.ProcessExited)]
  494.         public event EventHandler Exited {
  495.             add { onExited += value; }
  496.             remove { onExited -= value; }
  497.         }
  498.        
  499.        
  500.         /// <devdoc>
  501.         /// Release the temporary handle we used to get process information.
  502.         /// If we used the process handle stored in the process object (we have all access to the handle,) don't release it.
  503.         /// </devdoc>
  504.         /// <internalonly/>
  505.         void ReleaseProcessHandle(SafeProcessHandle handle)
  506.         {
  507.             if (handle == null) {
  508.                 return;
  509.             }
  510.            
  511.             if (haveProcessHandle && handle == m_processHandle) {
  512.                 return;
  513.             }
  514.             Debug.WriteLineIf(processTracing.TraceVerbose, "Process - CloseHandle(process)");
  515.             handle.Close();
  516.         }
  517.        
  518.         /// <devdoc>
  519.         /// This is called from the threadpool when a proces exits.
  520.         /// </devdoc>
  521.         /// <internalonly/>
  522.         private void CompletionCallback(object context, bool wasSignaled)
  523.         {
  524.             StopWatchingForExit();
  525.             RaiseOnExited();
  526.         }
  527.        
  528.         /// <internalonly/>
  529.         /// <devdoc>
  530.         /// <para>
  531.         /// Free any resources associated with this component.
  532.         /// </para>
  533.         /// </devdoc>
  534.         protected override void Dispose(bool disposing)
  535.         {
  536.             if (!disposed) {
  537.                 if (disposing) {
  538.                     //Dispose managed and unmanaged resources
  539.                     Close();
  540.                 }
  541.                 this.disposed = true;
  542.                 base.Dispose(disposing);
  543.             }
  544.         }
  545.        
  546.         /// <devdoc>
  547.         /// <para>
  548.         /// Frees any resources associated with this component.
  549.         /// </para>
  550.         /// </devdoc>
  551.         public void Close()
  552.         {
  553.             if (Associated) {
  554.                 if (haveProcessHandle) {
  555.                     StopWatchingForExit();
  556.                     Debug.WriteLineIf(processTracing.TraceVerbose, "Process - CloseHandle(process) in Close()");
  557.                     m_processHandle.Close();
  558.                     m_processHandle = null;
  559.                     haveProcessHandle = false;
  560.                 }
  561.                 haveProcessId = false;
  562.                 isRemoteMachine = false;
  563.                 machineName = ".";
  564.                 raisedOnExited = false;
  565.                
  566.                 //Don't call close on the Readers and writers
  567.                 //since they might be referenced by somebody else while the
  568.                 //process is still alive but this method called.
  569.                 standardOutput = null;
  570.                 standardInput = null;
  571.                 standardError = null;
  572.                
  573.                
  574.                 Refresh();
  575.             }
  576.         }
  577.        
  578.         /// <devdoc>
  579.         /// Helper method for checking preconditions when accessing properties.
  580.         /// </devdoc>
  581.         /// <internalonly/>
  582.         void EnsureState(State state)
  583.         {
  584.             if ((state & State.IsWin2k) != (State)0) {
  585.                 throw new PlatformNotSupportedException(SR.GetString(SR.Win2kRequired));
  586.             }
  587.            
  588.             if ((state & State.IsNt) != (State)0) {
  589.                 throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequired));
  590.             }
  591.            
  592.             if ((state & State.Associated) != (State)0)
  593.                 if (!Associated)
  594.                     throw new InvalidOperationException(SR.GetString(SR.NoAssociatedProcess));
  595.            
  596.             if ((state & State.HaveId) != (State)0) {
  597.                 if (!haveProcessId) {
  598.                     EnsureState(State.Associated);
  599.                     throw new InvalidOperationException(SR.GetString(SR.ProcessIdRequired));
  600.                 }
  601.             }
  602.            
  603.             if ((state & State.IsLocal) != (State)0 && isRemoteMachine) {
  604.                 throw new NotSupportedException(SR.GetString(SR.NotSupportedRemote));
  605.             }
  606.            
  607.             if ((state & State.HaveProcessInfo) != (State)0) {
  608.                 throw new InvalidOperationException(SR.GetString(SR.NoProcessInfo));
  609.             }
  610.            
  611.             if ((state & State.Exited) != (State)0) {
  612.                 if (!HasExited) {
  613.                     throw new InvalidOperationException(SR.GetString(SR.WaitTillExit));
  614.                 }
  615.                
  616.                 if (!haveProcessHandle) {
  617.                     throw new InvalidOperationException(SR.GetString(SR.NoProcessHandle));
  618.                 }
  619.             }
  620.         }
  621.        
  622.         /// <devdoc>
  623.         /// Make sure we are watching for a process exit.
  624.         /// </devdoc>
  625.         /// <internalonly/>
  626.         void EnsureWatchingForExit()
  627.         {
  628.             if (!watchingForExit) {
  629.                 Debug.Assert(haveProcessHandle, "Process.EnsureWatchingForExit called with no process handle");
  630.                 Debug.Assert(Associated, "Process.EnsureWatchingForExit called with no associated process");
  631.                 watchingForExit = true;
  632.                 try {
  633.                     this.waitHandle = new ProcessWaitHandle(m_processHandle);
  634.                     this.registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(this.waitHandle, new WaitOrTimerCallback(this.CompletionCallback), null, -1, true);
  635.                 }
  636.                 catch {
  637.                     watchingForExit = false;
  638.                     throw;
  639.                 }
  640.             }
  641.         }
  642.        
  643.        
  644.         /// <devdoc>
  645.         /// <para>
  646.         /// Returns a new <see cref='System.Diagnostics.Process'/>
  647.         /// component and associates it with the current active process.
  648.         /// </para>
  649.         /// </devdoc>
  650.         public static Process GetCurrentProcess()
  651.         {
  652.             return new Process(".", false, NativeMethods.GetCurrentProcessId(), null);
  653.         }
  654.        
  655.         /// <devdoc>
  656.         /// <para>
  657.         /// Raises the <see cref='System.Diagnostics.Process.Exited'/> event.
  658.         /// </para>
  659.         /// </devdoc>
  660.         protected void OnExited()
  661.         {
  662.             EventHandler exited = onExited;
  663.             if (exited != null) {
  664.                 if (this.SynchronizingObject != null && this.SynchronizingObject.InvokeRequired)
  665.                     this.SynchronizingObject.BeginInvoke(exited, new object[] {this, EventArgs.Empty});
  666.                 else
  667.                     exited(this, EventArgs.Empty);
  668.             }
  669.         }
  670.        
  671.         /// <devdoc>
  672.         /// Gets a short-term handle to the process, with the given access.
  673.         /// If a handle is stored in current process object, then use it.
  674.         /// Note that the handle we stored in current process object will have all access we need.
  675.         /// </devdoc>
  676.         /// <internalonly/>
  677.         SafeProcessHandle GetProcessHandle(int access, bool throwIfExited)
  678.         {
  679.             Debug.WriteLineIf(processTracing.TraceVerbose, "GetProcessHandle(access = 0x" + access.ToString("X8", CultureInfo.InvariantCulture) + ", throwIfExited = " + throwIfExited + ")");
  680.             #if DEBUG
  681.             if (processTracing.TraceVerbose) {
  682.                 StackFrame calledFrom = new StackTrace(true).GetFrame(0);
  683.                 Debug.WriteLine(" called from " + calledFrom.GetFileName() + ", line " + calledFrom.GetFileLineNumber());
  684.             }
  685.             #endif
  686.             if (haveProcessHandle) {
  687.                 if (throwIfExited) {
  688.                     // Since haveProcessHandle is true, we know we have the process handle
  689.                     // open with at least SYNCHRONIZE access, so we can wait on it with
  690.                     // zero timeout to see if the process has exited.
  691.                     ProcessWaitHandle waitHandle = null;
  692.                     try {
  693.                         waitHandle = new ProcessWaitHandle(m_processHandle);
  694.                         if (waitHandle.WaitOne(0, false)) {
  695.                             if (haveProcessId)
  696.                                 throw new InvalidOperationException(SR.GetString(SR.ProcessHasExited, processId.ToString(CultureInfo.CurrentCulture)));
  697.                             else
  698.                                 throw new InvalidOperationException(SR.GetString(SR.ProcessHasExitedNoId));
  699.                         }
  700.                     }
  701.                     finally {
  702.                         if (waitHandle != null) {
  703.                             waitHandle.Close();
  704.                         }
  705.                     }
  706.                 }
  707.                 return m_processHandle;
  708.             }
  709.             else {
  710.                 EnsureState(State.HaveId | State.IsLocal);
  711.                 SafeProcessHandle handle = SafeProcessHandle.InvalidHandle;
  712.                 IntPtr pseudohandle = NativeMethods.GetCurrentProcess();
  713.                 // Get a real handle
  714.                 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)) {
  715.                     throw new Win32Exception();
  716.                 }
  717.                 if (throwIfExited && (access & NativeMethods.PROCESS_QUERY_INFORMATION) != 0) {
  718.                     if (NativeMethods.GetExitCodeProcess(handle, out exitCode) && exitCode != NativeMethods.STILL_ACTIVE) {
  719.                         throw new InvalidOperationException(SR.GetString(SR.ProcessHasExited, processId.ToString(CultureInfo.CurrentCulture)));
  720.                     }
  721.                 }
  722.                 return handle;
  723.             }
  724.            
  725.         }
  726.        
  727.         /// <devdoc>
  728.         /// Gets a short-term handle to the process, with the given access. If a handle exists,
  729.         /// then it is reused. If the process has exited, it throws an exception.
  730.         /// </devdoc>
  731.         /// <internalonly/>
  732.         SafeProcessHandle GetProcessHandle(int access)
  733.         {
  734.             return GetProcessHandle(access, true);
  735.         }
  736.        
  737.         /// <devdoc>
  738.         /// Opens a long-term handle to the process, with all access. If a handle exists,
  739.         /// then it is reused. If the process has exited, it throws an exception.
  740.         /// </devdoc>
  741.         /// <internalonly/>
  742.         SafeProcessHandle OpenProcessHandle()
  743.         {
  744.             if (!haveProcessHandle) {
  745.                 //Cannot open a new process handle if the object has been disposed, since finalization has been suppressed.
  746.                 if (this.disposed) {
  747.                     throw new ObjectDisposedException(GetType().Name);
  748.                 }
  749.                
  750.                 SetProcessHandle(GetProcessHandle(NativeMethods.PROCESS_ALL_ACCESS));
  751.             }
  752.             return m_processHandle;
  753.         }
  754.        
  755.         /// <devdoc>
  756.         /// Raise the Exited event, but make sure we don't do it more than once.
  757.         /// </devdoc>
  758.         /// <internalonly/>
  759.         void RaiseOnExited()
  760.         {
  761.             if (!raisedOnExited) {
  762.                 lock (this) {
  763.                     if (!raisedOnExited) {
  764.                         raisedOnExited = true;
  765.                         OnExited();
  766.                     }
  767.                 }
  768.             }
  769.         }
  770.        
  771.         /// <devdoc>
  772.         /// <para>
  773.         /// Discards any information about the associated process
  774.         /// that has been cached inside the process component. After <see cref='System.Diagnostics.Process.Refresh'/> is called, the
  775.         /// first request for information for each property causes the process component
  776.         /// to obtain a new value from the associated process.
  777.         /// </para>
  778.         /// </devdoc>
  779.         public void Refresh()
  780.         {
  781.             processInfo = null;
  782.             mainWindowTitle = null;
  783.             exited = false;
  784.             signaled = false;
  785.             haveMainWindow = false;
  786.             haveWorkingSetLimits = false;
  787.             haveProcessorAffinity = false;
  788.             havePriorityClass = false;
  789.             haveExitTime = false;
  790.             haveResponding = false;
  791.             havePriorityBoostEnabled = false;
  792.         }
  793.        
  794.         /// <devdoc>
  795.         /// Helper to associate a process handle with this component.
  796.         /// </devdoc>
  797.         /// <internalonly/>
  798.         void SetProcessHandle(SafeProcessHandle processHandle)
  799.         {
  800.             this.m_processHandle = processHandle;
  801.             this.haveProcessHandle = true;
  802.             if (watchForExit) {
  803.                 EnsureWatchingForExit();
  804.             }
  805.         }
  806.        
  807.         /// <devdoc>
  808.         /// Helper to associate a process id with this component.
  809.         /// </devdoc>
  810.         /// <internalonly/>
  811.         void SetProcessId(int processId)
  812.         {
  813.             this.processId = processId;
  814.             this.haveProcessId = true;
  815.         }
  816.        
  817.        
  818.         /// <devdoc>
  819.         /// <para>
  820.         /// Starts a process specified by the <see cref='System.Diagnostics.Process.StartInfo'/> property of this <see cref='System.Diagnostics.Process'/>
  821.         /// component and associates it with the
  822.         /// <see cref='System.Diagnostics.Process'/> . If a process resource is reused
  823.         /// rather than started, the reused process is associated with this <see cref='System.Diagnostics.Process'/>
  824.         /// component.
  825.         /// </para>
  826.         /// </devdoc>
  827.         public bool Start()
  828.         {
  829.             Close();
  830.             ProcessStartInfo startInfo = StartInfo;
  831.             if (startInfo.FileName.Length == 0)
  832.                 throw new InvalidOperationException(SR.GetString(SR.FileNameMissing));
  833.            
  834.             if (startInfo.UseShellExecute) {
  835.                 throw new InvalidOperationException(SR.GetString(SR.net_perm_invalid_val, "StartInfo.UseShellExecute", true));
  836.             }
  837.             else {
  838.                 return StartWithCreateProcess(startInfo);
  839.             }
  840.         }
  841.        
  842.        
  843.         private static void CreatePipeWithSecurityAttributes(out SafeFileHandle hReadPipe, out SafeFileHandle hWritePipe, NativeMethods.SECURITY_ATTRIBUTES lpPipeAttributes, int nSize)
  844.         {
  845.             bool ret = NativeMethods.CreatePipe(out hReadPipe, out hWritePipe, lpPipeAttributes, nSize);
  846.             if (!ret || hReadPipe.IsInvalid || hWritePipe.IsInvalid) {
  847.                 throw new Win32Exception();
  848.             }
  849.         }
  850.        
  851.         // Using synchronous Anonymous pipes for process input/output redirection means we would end up
  852.         // wasting a worker threadpool thread per pipe instance. Overlapped pipe IO is desirable, since
  853.         // it will take advantage of the NT IO completion port infrastructure. But we can't really use
  854.         // Overlapped I/O for process input/output as it would break Console apps (managed Console class
  855.         // methods such as WriteLine as well as native CRT functions like printf) which are making an
  856.         // assumption that the console standard handles (obtained via GetStdHandle()) are opened
  857.         // for synchronous I/O and hence they can work fine with ReadFile/WriteFile synchrnously!
  858.         private void CreatePipe(out SafeFileHandle parentHandle, out SafeFileHandle childHandle, bool parentInputs)
  859.         {
  860.             NativeMethods.SECURITY_ATTRIBUTES securityAttributesParent = new NativeMethods.SECURITY_ATTRIBUTES();
  861.             securityAttributesParent.bInheritHandle = true;
  862.            
  863.             SafeFileHandle hTmp = null;
  864.             try {
  865.                 if (parentInputs) {
  866.                     CreatePipeWithSecurityAttributes(out childHandle, out hTmp, securityAttributesParent, 0);
  867.                 }
  868.                 else {
  869.                     CreatePipeWithSecurityAttributes(out hTmp, out childHandle, securityAttributesParent, 0);
  870.                 }
  871.                 // Duplicate the parent handle to be non-inheritable so that the child process
  872.                 // doesn't have access. This is done for correctness sake, exact reason is unclear.
  873.                 // One potential theory is that child process can do something brain dead like
  874.                 // closing the parent end of the pipe and there by getting into a blocking situation
  875.                 // as parent will not be draining the pipe at the other end anymore.
  876.                 if (!NativeMethods.DuplicateHandle(new HandleRef(this, NativeMethods.GetCurrentProcess()), hTmp, new HandleRef(this, NativeMethods.GetCurrentProcess()), out parentHandle, 0, false, NativeMethods.DUPLICATE_SAME_ACCESS)) {
  877.                     throw new Win32Exception();
  878.                 }
  879.             }
  880.             finally {
  881.                 if (hTmp != null && !hTmp.IsInvalid) {
  882.                     hTmp.Close();
  883.                 }
  884.             }
  885.         }
  886.        
  887.         private static StringBuilder BuildCommandLine(string executableFileName, string arguments)
  888.         {
  889.             // Construct a StringBuilder with the appropriate command line
  890.             // to pass to CreateProcess. If the filename isn't already
  891.             // in quotes, we quote it here. This prevents some security
  892.             // problems (it specifies exactly which part of the string
  893.             // is the file to execute).
  894.             StringBuilder commandLine = new StringBuilder();
  895.             string fileName = executableFileName.Trim();
  896.             bool fileNameIsQuoted = (fileName.StartsWith("\"", StringComparison.Ordinal) && fileName.EndsWith("\"", StringComparison.Ordinal));
  897.             if (!fileNameIsQuoted) {
  898.                 commandLine.Append("\"");
  899.             }
  900.            
  901.             commandLine.Append(fileName);
  902.            
  903.             if (!fileNameIsQuoted) {
  904.                 commandLine.Append("\"");
  905.             }
  906.            
  907.             if (!String.IsNullOrEmpty(arguments)) {
  908.                 commandLine.Append(" ");
  909.                 commandLine.Append(arguments);
  910.             }
  911.            
  912.             return commandLine;
  913.         }
  914.        
  915.         private bool StartWithCreateProcess(ProcessStartInfo startInfo)
  916.         {
  917.             if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput) {
  918.                 throw new InvalidOperationException(SR.GetString(SR.StandardOutputEncodingNotAllowed));
  919.             }
  920.            
  921.             if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError) {
  922.                 throw new InvalidOperationException(SR.GetString(SR.StandardErrorEncodingNotAllowed));
  923.             }
  924.            
  925.             // See knowledge base article Q190351 for an explanation of the following code. Noteworthy tricky points:
  926.             // * The handles are duplicated as non-inheritable before they are passed to CreateProcess so
  927.             // that the child process can not close them
  928.             // * CreateProcess allows you to redirect all or none of the standard IO handles, so we use
  929.             // GetStdHandle for the handles that are not being redirected
  930.            
  931.             //Cannot start a new process and store its handle if the object has been disposed, since finalization has been suppressed.
  932.             if (this.disposed) {
  933.                 throw new ObjectDisposedException(GetType().Name);
  934.             }
  935.            
  936.             StringBuilder commandLine = BuildCommandLine(startInfo.FileName, startInfo.Arguments);
  937.            
  938.             NativeMethods.STARTUPINFO startupInfo = new NativeMethods.STARTUPINFO();
  939.             SafeNativeMethods.PROCESS_INFORMATION processInfo = new SafeNativeMethods.PROCESS_INFORMATION();
  940.             SafeProcessHandle procSH = new SafeProcessHandle();
  941.             SafeThreadHandle threadSH = new SafeThreadHandle();
  942.             bool retVal;
  943.             int errorCode = 0;
  944.             // handles used in parent process
  945.             SafeFileHandle standardInputWritePipeHandle = null;
  946.             SafeFileHandle standardOutputReadPipeHandle = null;
  947.             SafeFileHandle standardErrorReadPipeHandle = null;
  948.            
  949.             GCHandle environmentHandle = new GCHandle();
  950.             try {
  951.                 // set up the streams
  952.                 if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError) {
  953.                     if (startInfo.RedirectStandardInput) {
  954.                         CreatePipe(out standardInputWritePipeHandle, out startupInfo.hStdInput, true);
  955.                     }
  956.                     else {
  957.                         startupInfo.hStdInput = new SafeFileHandle(NativeMethods.GetStdHandle(NativeMethods.STD_INPUT_HANDLE), false);
  958.                     }
  959.                    
  960.                     if (startInfo.RedirectStandardOutput) {
  961.                         CreatePipe(out standardOutputReadPipeHandle, out startupInfo.hStdOutput, false);
  962.                     }
  963.                     else {
  964.                         startupInfo.hStdOutput = new SafeFileHandle(NativeMethods.GetStdHandle(NativeMethods.STD_OUTPUT_HANDLE), false);
  965.                     }
  966.                    
  967.                     if (startInfo.RedirectStandardError) {
  968.                         CreatePipe(out standardErrorReadPipeHandle, out startupInfo.hStdError, false);
  969.                     }
  970.                     else {
  971.                         startupInfo.hStdError = new SafeFileHandle(NativeMethods.GetStdHandle(NativeMethods.STD_ERROR_HANDLE), false);
  972.                     }
  973.                    
  974.                     startupInfo.dwFlags = NativeMethods.STARTF_USESTDHANDLES;
  975.                 }
  976.                
  977.                 // set up the creation flags paramater
  978.                 int creationFlags = 0;
  979.                
  980.                 // set up the environment block parameter
  981.                 IntPtr environmentPtr = (IntPtr)0;
  982.                 if (startInfo.environmentVariables != null) {
  983.                     bool unicode = false;
  984.                    
  985.                     byte[] environmentBytes = EnvironmentBlock.ToByteArray(startInfo.environmentVariables, unicode);
  986.                     environmentHandle = GCHandle.Alloc(environmentBytes, GCHandleType.Pinned);
  987.                     environmentPtr = environmentHandle.AddrOfPinnedObject();
  988.                 }
  989.                
  990.                 string workingDirectory = startInfo.WorkingDirectory;
  991.                 if (workingDirectory == string.Empty)
  992.                     workingDirectory = Environment.CurrentDirectory;
  993.                
  994.                 RuntimeHelpers.PrepareConstrainedRegions();
  995.                 try {
  996.                 }
  997.                 finally {
  998.                     retVal = NativeMethods.CreateProcess(null, commandLine, null, null, true, creationFlags, environmentPtr, workingDirectory, startupInfo, processInfo
  999.                         // we don't need this since all the info is in commandLine
  1000.                         // pointer to the command line string
  1001.                         // pointer to process security attributes, we don't need to inheriat the handle
  1002.                         // pointer to thread security attributes
  1003.                         // handle inheritance flag
  1004.                         // creation flags
  1005.                         // pointer to new environment block
  1006.                         // pointer to current directory name
  1007.                         // pointer to STARTUPINFO
  1008.                         // pointer to PROCESS_INFORMATION
  1009.                     );
  1010.                     if (!retVal)
  1011.                         errorCode = Marshal.GetLastWin32Error();
  1012.                     if (processInfo.hProcess != (IntPtr)0 && processInfo.hProcess != (IntPtr)NativeMethods.INVALID_HANDLE_VALUE)
  1013.                         procSH.InitialSetHandle(processInfo.hProcess);
  1014.                     if (processInfo.hThread != (IntPtr)0 && processInfo.hThread != (IntPtr)NativeMethods.INVALID_HANDLE_VALUE)
  1015.                         threadSH.InitialSetHandle(processInfo.hThread);
  1016.                 }
  1017.                 if (!retVal) {
  1018.                     if (errorCode == NativeMethods.ERROR_BAD_EXE_FORMAT) {
  1019.                         throw new Win32Exception(errorCode, SR.GetString(SR.InvalidApplication));
  1020.                     }
  1021.                     throw new Win32Exception(errorCode);
  1022.                 }
  1023.             }
  1024.             finally {
  1025.                 // free environment block
  1026.                 if (environmentHandle.IsAllocated) {
  1027.                     environmentHandle.Free();
  1028.                 }
  1029.                
  1030.                 startupInfo.Dispose();
  1031.             }
  1032.            
  1033.             if (startInfo.RedirectStandardInput) {
  1034.                 standardInput = new StreamWriter(new FileStream(standardInputWritePipeHandle, FileAccess.Write, 4096, false), Encoding.GetEncoding(NativeMethods.GetConsoleCP()), 4096);
  1035.                 standardInput.AutoFlush = true;
  1036.             }
  1037.             if (startInfo.RedirectStandardOutput) {
  1038.                 Encoding enc = (startInfo.StandardOutputEncoding != null) ? startInfo.StandardOutputEncoding : Encoding.GetEncoding(NativeMethods.GetConsoleOutputCP());
  1039.                 standardOutput = new StreamReader(new FileStream(standardOutputReadPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096);
  1040.             }
  1041.             if (startInfo.RedirectStandardError) {
  1042.                 Encoding enc = (startInfo.StandardErrorEncoding != null) ? startInfo.StandardErrorEncoding : Encoding.GetEncoding(NativeMethods.GetConsoleOutputCP());
  1043.                 standardError = new StreamReader(new FileStream(standardErrorReadPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096);
  1044.             }
  1045.            
  1046.             bool ret = false;
  1047.             if (!procSH.IsInvalid) {
  1048.                 SetProcessHandle(procSH);
  1049.                 SetProcessId(processInfo.dwProcessId);
  1050.                 threadSH.Close();
  1051.                 ret = true;
  1052.             }
  1053.            
  1054.             return ret;
  1055.            
  1056.         }
  1057.        
  1058.        
  1059.         /// <devdoc>
  1060.         /// <para>
  1061.         /// Starts a process resource by specifying the name of a
  1062.         /// document or application file. Associates the process resource with a new <see cref='System.Diagnostics.Process'/>
  1063.         /// component.
  1064.         /// </para>
  1065.         /// </devdoc>
  1066.         public static Process Start(string fileName)
  1067.         {
  1068.             return Start(new ProcessStartInfo(fileName));
  1069.         }
  1070.        
  1071.         /// <devdoc>
  1072.         /// <para>
  1073.         /// Starts a process resource by specifying the name of an
  1074.         /// application and a set of command line arguments. Associates the process resource
  1075.         /// with a new <see cref='System.Diagnostics.Process'/>
  1076.         /// component.
  1077.         /// </para>
  1078.         /// </devdoc>
  1079.         public static Process Start(string fileName, string arguments)
  1080.         {
  1081.             return Start(new ProcessStartInfo(fileName, arguments));
  1082.         }
  1083.        
  1084.         /// <devdoc>
  1085.         /// <para>
  1086.         /// Starts a process resource specified by the process start
  1087.         /// information passed in, for example the file name of the process to start.
  1088.         /// Associates the process resource with a new <see cref='System.Diagnostics.Process'/>
  1089.         /// component.
  1090.         /// </para>
  1091.         /// </devdoc>
  1092.         public static Process Start(ProcessStartInfo startInfo)
  1093.         {
  1094.             Process process = new Process();
  1095.             if (startInfo == null)
  1096.                 throw new ArgumentNullException("startInfo");
  1097.             process.StartInfo = startInfo;
  1098.             if (process.Start()) {
  1099.                 return process;
  1100.             }
  1101.             return null;
  1102.         }
  1103.        
  1104.         /// <devdoc>
  1105.         /// <para>
  1106.         /// Stops the
  1107.         /// associated process immediately.
  1108.         /// </para>
  1109.         /// </devdoc>
  1110.         public void Kill()
  1111.         {
  1112.             SafeProcessHandle handle = null;
  1113.             try {
  1114.                 handle = GetProcessHandle(NativeMethods.PROCESS_TERMINATE);
  1115.                 if (!NativeMethods.TerminateProcess(handle, -1))
  1116.                     throw new Win32Exception();
  1117.             }
  1118.             finally {
  1119.                 ReleaseProcessHandle(handle);
  1120.             }
  1121.         }
  1122.        
  1123.         /// <devdoc>
  1124.         /// Make sure we are not watching for process exit.
  1125.         /// </devdoc>
  1126.         /// <internalonly/>
  1127.         void StopWatchingForExit()
  1128.         {
  1129.             if (watchingForExit) {
  1130.                 lock (this) {
  1131.                     if (watchingForExit) {
  1132.                         watchingForExit = false;
  1133.                         registeredWaitHandle.Unregister(null);
  1134.                         waitHandle = null;
  1135.                         registeredWaitHandle = null;
  1136.                     }
  1137.                 }
  1138.             }
  1139.         }
  1140.        
  1141.         public override string ToString()
  1142.         {
  1143.             return base.ToString();
  1144.         }
  1145.        
  1146.         /// <devdoc>
  1147.         /// <para>
  1148.         /// Instructs the <see cref='System.Diagnostics.Process'/> component to wait the specified number of milliseconds for the associated process to exit.
  1149.         /// </para>
  1150.         /// </devdoc>
  1151.         public bool WaitForExit(int milliseconds)
  1152.         {
  1153.             SafeProcessHandle handle = null;
  1154.             bool exited;
  1155.             ProcessWaitHandle processWaitHandle = null;
  1156.             try {
  1157.                 handle = GetProcessHandle(NativeMethods.SYNCHRONIZE, false);
  1158.                 if (handle.IsInvalid) {
  1159.                     exited = true;
  1160.                 }
  1161.                 else {
  1162.                     processWaitHandle = new ProcessWaitHandle(handle);
  1163.                     if (processWaitHandle.WaitOne(milliseconds, false)) {
  1164.                         exited = true;
  1165.                         signaled = true;
  1166.                     }
  1167.                     else {
  1168.                         exited = false;
  1169.                         signaled = false;
  1170.                     }
  1171.                 }
  1172.             }
  1173.             finally {
  1174.                 if (processWaitHandle != null) {
  1175.                     processWaitHandle.Close();
  1176.                 }
  1177.                
  1178.                 // If we have a hard timeout, we cannot wait for the streams
  1179.                 if (output != null && milliseconds == Int32.MaxValue) {
  1180.                     output.WaitUtilEOF();
  1181.                 }
  1182.                
  1183.                 if (error != null && milliseconds == Int32.MaxValue) {
  1184.                     error.WaitUtilEOF();
  1185.                 }
  1186.                
  1187.                 ReleaseProcessHandle(handle);
  1188.                
  1189.             }
  1190.            
  1191.             if (exited && watchForExit) {
  1192.                 RaiseOnExited();
  1193.             }
  1194.            
  1195.             return exited;
  1196.         }
  1197.        
  1198.         /// <devdoc>
  1199.         /// <para>
  1200.         /// Instructs the <see cref='System.Diagnostics.Process'/> component to wait
  1201.         /// indefinitely for the associated process to exit.
  1202.         /// </para>
  1203.         /// </devdoc>
  1204.         public void WaitForExit()
  1205.         {
  1206.             WaitForExit(Int32.MaxValue);
  1207.         }
  1208.        
  1209.        
  1210.         // Support for working asynchronously with streams
  1211.         /// <devdoc>
  1212.         /// <para>
  1213.         /// Instructs the <see cref='System.Diagnostics.Process'/> component to start
  1214.         /// reading the StandardOutput stream asynchronously. The user can register a callback
  1215.         /// 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
  1216.         /// then the remaining information is returned. The user can add an event handler to OutputDataReceived.
  1217.         /// </para>
  1218.         /// </devdoc>
  1219.         [System.Runtime.InteropServices.ComVisible(false)]
  1220.         public void BeginOutputReadLine()
  1221.         {
  1222.            
  1223.             if (outputStreamReadMode == StreamReadMode.undefined) {
  1224.                 outputStreamReadMode = StreamReadMode.asyncMode;
  1225.             }
  1226.             else if (outputStreamReadMode != StreamReadMode.asyncMode) {
  1227.                 throw new InvalidOperationException(SR.GetString(SR.CantMixSyncAsyncOperation));
  1228.             }
  1229.            
  1230.             if (pendingOutputRead)
  1231.                 throw new InvalidOperationException(SR.GetString(SR.PendingAsyncOperation));
  1232.            
  1233.             pendingOutputRead = true;
  1234.             // We can't detect if there's a pending sychronous read, tream also doesn't.
  1235.             if (output == null) {
  1236.                 if (standardOutput == null) {
  1237.                     throw new InvalidOperationException(SR.GetString(SR.CantGetStandardOut));
  1238.                 }
  1239.                
  1240.                 Stream s = standardOutput.BaseStream;
  1241.                 output = new AsyncStreamReader(this, s, new UserCallBack(this.OutputReadNotifyUser), standardOutput.CurrentEncoding);
  1242.             }
  1243.             output.BeginReadLine();
  1244.         }
  1245.        
  1246.        
  1247.         /// <devdoc>
  1248.         /// <para>
  1249.         /// Instructs the <see cref='System.Diagnostics.Process'/> component to start
  1250.         /// reading the StandardError stream asynchronously. The user can register a callback
  1251.         /// 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
  1252.         /// then the remaining information is returned. The user can add an event handler to ErrorDataReceived.
  1253.         /// </para>
  1254.         /// </devdoc>
  1255.         [System.Runtime.InteropServices.ComVisible(false)]
  1256.         public void BeginErrorReadLine()
  1257.         {
  1258.            
  1259.             if (errorStreamReadMode == StreamReadMode.undefined) {
  1260.                 errorStreamReadMode = StreamReadMode.asyncMode;
  1261.             }
  1262.             else if (errorStreamReadMode != StreamReadMode.asyncMode) {
  1263.                 throw new InvalidOperationException(SR.GetString(SR.CantMixSyncAsyncOperation));
  1264.             }
  1265.            
  1266.             if (pendingErrorRead) {
  1267.                 throw new InvalidOperationException(SR.GetString(SR.PendingAsyncOperation));
  1268.             }
  1269.            
  1270.             pendingErrorRead = true;
  1271.             // We can't detect if there's a pending sychronous read, stream also doesn't.
  1272.             if (error == null) {
  1273.                 if (standardError == null) {
  1274.                     throw new InvalidOperationException(SR.GetString(SR.CantGetStandardError));
  1275.                 }
  1276.                
  1277.                 Stream s = standardError.BaseStream;
  1278.                 error = new AsyncStreamReader(this, s, new UserCallBack(this.ErrorReadNotifyUser), standardError.CurrentEncoding);
  1279.             }
  1280.             error.BeginReadLine();
  1281.         }
  1282.        
  1283.         /// <devdoc>
  1284.         /// <para>
  1285.         /// Instructs the <see cref='System.Diagnostics.Process'/> component to cancel the asynchronous operation
  1286.         /// specified by BeginOutputReadLine().
  1287.         /// </para>
  1288.         /// </devdoc>
  1289.         [System.Runtime.InteropServices.ComVisible(false)]
  1290.         public void CancelOutputRead()
  1291.         {
  1292.             if (output != null) {
  1293.                 output.CancelOperation();
  1294.             }
  1295.             else {
  1296.                 throw new InvalidOperationException(SR.GetString(SR.NoAsyncOperation));
  1297.             }
  1298.            
  1299.             pendingOutputRead = false;
  1300.         }
  1301.        
  1302.         /// <devdoc>
  1303.         /// <para>
  1304.         /// Instructs the <see cref='System.Diagnostics.Process'/> component to cancel the asynchronous operation
  1305.         /// specified by BeginErrorReadLine().
  1306.         /// </para>
  1307.         /// </devdoc>
  1308.         [System.Runtime.InteropServices.ComVisible(false)]
  1309.         public void CancelErrorRead()
  1310.         {
  1311.             if (error != null) {
  1312.                 error.CancelOperation();
  1313.             }
  1314.             else {
  1315.                 throw new InvalidOperationException(SR.GetString(SR.NoAsyncOperation));
  1316.             }
  1317.            
  1318.             pendingErrorRead = false;
  1319.         }
  1320.        
  1321.         internal void OutputReadNotifyUser(string data)
  1322.         {
  1323.             // To avoid race between remove handler and raising the event
  1324.             DataReceivedEventHandler outputDataReceived = OutputDataReceived;
  1325.             if (outputDataReceived != null) {
  1326.                 DataReceivedEventArgs e = new DataReceivedEventArgs(data);
  1327.                 if (SynchronizingObject != null && SynchronizingObject.InvokeRequired) {
  1328.                     SynchronizingObject.Invoke(outputDataReceived, new object[] {this, e});
  1329.                 }
  1330.                 else {
  1331.                     outputDataReceived(this, e);
  1332.                     // Call back to user informing data is available.
  1333.                 }
  1334.             }
  1335.         }
  1336.        
  1337.         internal void ErrorReadNotifyUser(string data)
  1338.         {
  1339.             // To avoid race between remove handler and raising the event
  1340.             DataReceivedEventHandler errorDataReceived = ErrorDataReceived;
  1341.             if (errorDataReceived != null) {
  1342.                 DataReceivedEventArgs e = new DataReceivedEventArgs(data);
  1343.                 if (SynchronizingObject != null && SynchronizingObject.InvokeRequired) {
  1344.                     SynchronizingObject.Invoke(errorDataReceived, new object[] {this, e});
  1345.                 }
  1346.                 else {
  1347.                     errorDataReceived(this, e);
  1348.                     // Call back to user informing data is available.
  1349.                 }
  1350.             }
  1351.         }
  1352.        
  1353.         /// <summary>
  1354.         /// A desired internal state.
  1355.         /// </summary>
  1356.         /// <internalonly/>
  1357.         enum State
  1358.         {
  1359.             HaveId = 1,
  1360.             IsLocal = 2,
  1361.             IsNt = 4,
  1362.             HaveProcessInfo = 8,
  1363.             Exited = 16,
  1364.             Associated = 32,
  1365.             IsWin2k = 64,
  1366.             HaveNtProcessInfo = HaveProcessInfo | IsNt
  1367.         }
  1368.     }
  1369.    
  1370.     /// <devdoc>
  1371.     /// This data structure contains information about a process that is collected
  1372.     /// in bulk by querying the operating system. The reason to make this a separate
  1373.     /// structure from the process component is so that we can throw it away all at once
  1374.     /// when Refresh is called on the component.
  1375.     /// </devdoc>
  1376.     /// <internalonly/>
  1377.     internal class ProcessInfo
  1378.     {
  1379.         public ArrayList threadInfoList = new ArrayList();
  1380.         public int basePriority;
  1381.         public string processName;
  1382.         public int processId;
  1383.         public int handleCount;
  1384.         public long poolPagedBytes;
  1385.         public long poolNonpagedBytes;
  1386.         public long virtualBytes;
  1387.         public long virtualBytesPeak;
  1388.         public long workingSetPeak;
  1389.         public long workingSet;
  1390.         public long pageFileBytesPeak;
  1391.         public long pageFileBytes;
  1392.         public long privateBytes;
  1393.         public int mainModuleId;
  1394.         // used only for win9x - id is only for use with CreateToolHelp32
  1395.         public int sessionId;
  1396.     }
  1397.    
  1398.     /// <devdoc>
  1399.     /// This data structure contains information about a thread in a process that
  1400.     /// is collected in bulk by querying the operating system. The reason to
  1401.     /// make this a separate structure from the ProcessThread component is so that we
  1402.     /// can throw it away all at once when Refresh is called on the component.
  1403.     /// </devdoc>
  1404.     /// <internalonly/>
  1405.     internal class ThreadInfo
  1406.     {
  1407.         public int threadId;
  1408.         public int processId;
  1409.         public int basePriority;
  1410.         public int currentPriority;
  1411.         public IntPtr startAddress;
  1412.         public ThreadState threadState;
  1413.     }
  1414.    
  1415.     /// <devdoc>
  1416.     /// This data structure contains information about a module in a process that
  1417.     /// is collected in bulk by querying the operating system. The reason to
  1418.     /// make this a separate structure from the ProcessModule component is so that we
  1419.     /// can throw it away all at once when Refresh is called on the component.
  1420.     /// </devdoc>
  1421.     /// <internalonly/>
  1422.     internal class ModuleInfo
  1423.     {
  1424.         public string baseName;
  1425.         public string fileName;
  1426.         public IntPtr baseOfDll;
  1427.         public IntPtr entryPoint;
  1428.         public int sizeOfImage;
  1429.         public int Id;
  1430.         // used only on win9x - for matching up with ProcessInfo.mainModuleId
  1431.     }
  1432.    
  1433.     static internal class EnvironmentBlock
  1434.     {
  1435.         public static byte[] ToByteArray(StringDictionary sd, bool unicode)
  1436.         {
  1437.             // get the keys
  1438.             string[] keys = new string[sd.Count];
  1439.             byte[] envBlock = null;
  1440.             sd.Keys.CopyTo(keys, 0);
  1441.            
  1442.             // get the values
  1443.             string[] values = new string[sd.Count];
  1444.             sd.Values.CopyTo(values, 0);
  1445.            
  1446.             // sort both by the keys
  1447.             // Windows 2000 requires the environment block to be sorted by the key
  1448.             // It will first converting the case the strings and do ordinal comparison.
  1449.             Array.Sort(keys, values, OrdinalCaseInsensitiveComparer.Default);
  1450.            
  1451.             // create a list of null terminated "key=val" strings
  1452.             StringBuilder stringBuff = new StringBuilder();
  1453.             for (int i = 0; i < sd.Count; ++i) {
  1454.                 stringBuff.Append(keys[i]);
  1455.                 stringBuff.Append('=');
  1456.                 stringBuff.Append(values[i]);
  1457.                 stringBuff.Append('\0');
  1458.             }
  1459.             // an extra null at the end indicates end of list.
  1460.             stringBuff.Append('\0');
  1461.            
  1462.             if (unicode) {
  1463.                 envBlock = Encoding.Unicode.GetBytes(stringBuff.ToString());
  1464.             }
  1465.             else
  1466.                 envBlock = Encoding.Default.GetBytes(stringBuff.ToString());
  1467.            
  1468.             if (envBlock.Length > UInt16.MaxValue)
  1469.                 throw new InvalidOperationException(SR.GetString(SR.EnvironmentBlockTooLong, envBlock.Length));
  1470.            
  1471.             return envBlock;
  1472.         }
  1473.     }
  1474.    
  1475.     internal class OrdinalCaseInsensitiveComparer : IComparer
  1476.     {
  1477.         static internal readonly OrdinalCaseInsensitiveComparer Default = new OrdinalCaseInsensitiveComparer();
  1478.        
  1479.         public int Compare(object a, object b)
  1480.         {
  1481.             string sa = a as string;
  1482.             string sb = b as string;
  1483.             if (sa != null && sb != null) {
  1484.                 return String.CompareOrdinal(sa.ToUpperInvariant(), sb.ToUpperInvariant());
  1485.             }
  1486.             return Comparer.Default.Compare(a, b);
  1487.         }
  1488.     }
  1489.    
  1490.     internal class ProcessThreadTimes
  1491.     {
  1492.         internal long create;
  1493.         internal long exit;
  1494.         internal long kernel;
  1495.         internal long user;
  1496.        
  1497.         public DateTime StartTime {
  1498.             get { return DateTime.FromFileTime(create); }
  1499.         }
  1500.        
  1501.         public DateTime ExitTime {
  1502.             get { return DateTime.FromFileTime(exit); }
  1503.         }
  1504.        
  1505.         public TimeSpan PrivilegedProcessorTime {
  1506.             get { return new TimeSpan(kernel); }
  1507.         }
  1508.        
  1509.         public TimeSpan UserProcessorTime {
  1510.             get { return new TimeSpan(user); }
  1511.         }
  1512.        
  1513.         public TimeSpan TotalProcessorTime {
  1514.             get { return new TimeSpan(user + kernel); }
  1515.         }
  1516.     }
  1517.    
  1518.    
  1519. }

Developer Fusion