File: services\monitoring\system\diagnosticts\Process.cs
Project: ndp\fx\src\System.csproj (System)
//------------------------------------------------------------------------------
// <copyright file="Process.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
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),
    // Disabling partial trust scenarios
    PermissionSet(SecurityAction.LinkDemand, Name="FullTrust"),
    PermissionSet(SecurityAction.InheritanceDemand, Name="FullTrust"),
    HostProtection(SharedState=true, Synchronization=true, ExternalProcessMgmt=true, SelfAffectingProcessMgmt=true)
    ]
    public class Process : Component {
        //
        // FIELDS
        //
 
        bool haveProcessId;
        int processId;
        bool haveProcessHandle;
        SafeProcessHandle m_processHandle;
        bool isRemoteMachine;
        string machineName;
        ProcessInfo processInfo;
        Int32 m_processAccess;
 
#if !FEATURE_PAL        
        ProcessThreadCollection threads;
        ProcessModuleCollection modules;
#endif // !FEATURE_PAL        
 
        bool haveMainWindow;
        IntPtr mainWindowHandle;  // no need to use SafeHandle for window        
        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;
        
        static object s_CreateProcessLock = new object();
        
        // This enum defines the operation mode for redirected process stream.
        // We don't support switching between synchronous mode and asynchronous mode.
        private enum StreamReadMode 
        {
            undefined, 
            syncMode, 
            asyncMode
        }
        
        StreamReadMode outputStreamReadMode;
        StreamReadMode errorStreamReadMode;
        
       
        // Support for asynchrously reading streams
        [Browsable(true), MonitoringDescription(SR.ProcessAssociated)]
        //[System.Runtime.InteropServices.ComVisible(false)]        
        public event DataReceivedEventHandler OutputDataReceived;
        [Browsable(true), MonitoringDescription(SR.ProcessAssociated)]
        //[System.Runtime.InteropServices.ComVisible(false)]        
        public event DataReceivedEventHandler ErrorDataReceived;
        // Abstract the stream details
        internal AsyncStreamReader output;
        internal AsyncStreamReader error;
        internal bool pendingOutputRead;
        internal bool pendingErrorRead;
 
 
        private static SafeFileHandle InvalidPipeHandle = new SafeFileHandle(IntPtr.Zero, false);
#if DEBUG
        internal static TraceSwitch processTracing = new TraceSwitch("processTracing", "Controls debug output from Process component");
#else
        internal static TraceSwitch processTracing = null;
#endif
 
        //
        // CONSTRUCTORS
        //
 
        /// <devdoc>
        ///    <para>
        ///       Initializes a new instance of the <see cref='System.Diagnostics.Process'/> class.
        ///    </para>
        /// </devdoc>
        public Process() {
            this.machineName = ".";
            this.outputStreamReadMode = StreamReadMode.undefined;
            this.errorStreamReadMode = StreamReadMode.undefined;            
            this.m_processAccess = NativeMethods.PROCESS_ALL_ACCESS;
        }        
        
        [ResourceExposure(ResourceScope.Machine)]
        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;
            this.outputStreamReadMode = StreamReadMode.undefined;
            this.errorStreamReadMode = StreamReadMode.undefined;
            this.m_processAccess = NativeMethods.PROCESS_ALL_ACCESS;
        }
 
        //
        // PROPERTIES
        //
 
        /// <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;
            }
        }
 
 #if !FEATURE_PAL
        /// <devdoc>
        ///    <para>
        ///       Gets the base priority of
        ///       the associated process.
        ///    </para>
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessBasePriority)]
        public int BasePriority {
            get {
                EnsureState(State.HaveProcessInfo);
                return processInfo.basePriority;
            }
        }
#endif // FEATURE_PAL
 
        /// <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;
                            
                            // Although this is the wrong way to check whether the process has exited,
                            // it was historically the way we checked for it, and a lot of code then took a dependency on
                            // the fact that this would always be set before the pipes were closed, so they would read
                            // the exit code out after calling ReadToEnd() or standard output or standard error. In order
                            // to allow 259 to function as a valid exit code and to break as few people as possible that
                            // took the ReadToEnd dependency, we check for an exit code before doing the more correct
                            // check to see if we have been signalled.
                            if (NativeMethods.GetExitCodeProcess(handle, out exitCode) && exitCode != NativeMethods.STILL_ACTIVE) {
                                this.exited = true;
                                this.exitCode = exitCode;                                
                            }
                            else {                                                        
 
                                // The best check for exit is that the kernel process object handle is invalid, 
                                // or that it is valid and signaled.  Checking if the exit code != STILL_ACTIVE 
                                // does not guarantee the process is closed,
                                // since some process could return an actual STILL_ACTIVE exit code (259).
                                if (!signaled) // if we just came from WaitForExit, don't repeat
                                {
                                    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 {
                int access = NativeMethods.PROCESS_QUERY_INFORMATION;
 
                if (EnvironmentHelpers.IsWindowsVistaOrAbove()) 
                    access = NativeMethods.PROCESS_QUERY_LIMITED_INFORMATION;
 
                handle = GetProcessHandle(access, false);
                if( handle.IsInvalid) {
                    // On OS older than XP, we will not be able to get the handle for a process
                    // after it terminates. 
                    // On Windows XP and newer OS, the information about a process will stay longer. 
                    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;
        }
 
 #if !FEATURE_PAL
        /// <devdoc>
        ///    <para>
        ///       Gets the time that the associated process exited.
        ///    </para>
        /// </devdoc>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessExitTime)]
        public DateTime ExitTime {
            get {
                if (!haveExitTime) {
                    EnsureState(State.IsNt | State.Exited);
                    exitTime = GetProcessTimes().ExitTime;
                    haveExitTime = true;
                }
                return exitTime;
            }
        }
#endif // !FEATURE_PAL
 
        /// <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(this.m_processAccess).DangerousGetHandle();
            }
        }
 
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]  
        public SafeProcessHandle SafeHandle {
            get {
                EnsureState(State.Associated);
                return OpenProcessHandle(this.m_processAccess);
            }
        }
 
#if !FEATURE_PAL
        /// <devdoc>
        ///    <para>
        ///       Gets the number of handles that are associated
        ///       with the process.
        ///    </para>
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessHandleCount)]
        public int HandleCount {
            get {
                EnsureState(State.HaveProcessInfo);
                return processInfo.handleCount;
            }
        }
#endif // !FEATURE_PAL
 
        /// <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;
            }
        }
 
 #if !FEATURE_PAL
 
        /// <devdoc>
        ///    <para>
        ///       Returns the window handle of the main window of the associated process.
        ///    </para>
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessMainWindowHandle)]
        public IntPtr MainWindowHandle {
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            get {
                if (!haveMainWindow) {
                    EnsureState(State.IsLocal | State.HaveId);
                    mainWindowHandle = ProcessManager.GetMainWindowHandle(processId);
 
                    if (mainWindowHandle != (IntPtr)0) {
                        haveMainWindow = true;
                    } else {
                        // We do the following only for the side-effect that it will throw when if the process no longer exists on the system.  In Whidbey
                        // we always did this check but have now changed it to just require a ProcessId. In the case where someone has called Refresh() 
                        // and the process has exited this call will throw an exception where as the above code would return 0 as the handle.
                        EnsureState(State.HaveProcessInfo);
                    }
                }
                return mainWindowHandle;
            }
        }
 
        /// <devdoc>
        ///    <para>
        ///       Returns the caption of the <see cref='System.Diagnostics.Process.MainWindowHandle'/> of
        ///       the process. If the handle is zero (0), then an empty string is returned.
        ///    </para>
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessMainWindowTitle)]
        public string MainWindowTitle {
            [ResourceExposure(ResourceScope.None)]
            [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
            get {
                if (mainWindowTitle == null) {
                    IntPtr handle = MainWindowHandle;
                    if (handle == (IntPtr)0) {
                        mainWindowTitle = String.Empty;
                    }
                    else {
                        int length = NativeMethods.GetWindowTextLength(new HandleRef(this, handle)) * 2;
                        StringBuilder builder = new StringBuilder(length);
                        NativeMethods.GetWindowText(new HandleRef(this, handle), builder, builder.Capacity);
                        mainWindowTitle = builder.ToString();
                    }
                }
                return mainWindowTitle;
            }
        }
 
 
 
        /// <devdoc>
        ///    <para>
        ///       Gets
        ///       the main module for the associated process.
        ///    </para>
        /// </devdoc>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessMainModule)]
        public ProcessModule MainModule {
            [ResourceExposure(ResourceScope.Process)]
            [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
            get {
                // We only return null if we couldn't find a main module.
                // This could be because
                //      1. The process hasn't finished loading the main module (most likely)
                //      2. There are no modules loaded (possible for certain OS processes)
                //      3. Possibly other?
                
                if (OperatingSystem.Platform == PlatformID.Win32NT) {
                    EnsureState(State.HaveId | State.IsLocal);
                    // on NT the first module is the main module                    
                    ModuleInfo module = NtProcessManager.GetFirstModuleInfo(processId);
                    return new ProcessModule(module);
                }
                else {
                    ProcessModuleCollection moduleCollection = Modules;                        
                    // on 9x we have to do a little more work
                    EnsureState(State.HaveProcessInfo);
                    foreach (ProcessModule pm in moduleCollection) {
                        if (pm.moduleInfo.Id == processInfo.mainModuleId) {
                            return pm;
                        }
                    }
                    return null;
                }
            }
        }
 
        /// <devdoc>
        ///    <para>
        ///       Gets or sets the maximum allowable working set for the associated
        ///       process.
        ///    </para>
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessMaxWorkingSet)]
        public IntPtr MaxWorkingSet {
            get {
                EnsureWorkingSetLimits();
                return maxWorkingSet;
            }
            [ResourceExposure(ResourceScope.Process)]
            [ResourceConsumption(ResourceScope.Process)]
            set {
                SetWorkingSetLimits(null, value);
            }
        }
 
        /// <devdoc>
        ///    <para>
        ///       Gets or sets the minimum allowable working set for the associated
        ///       process.
        ///    </para>
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessMinWorkingSet)]
        public IntPtr MinWorkingSet {
            get {
                EnsureWorkingSetLimits();
                return minWorkingSet;
            }
            [ResourceExposure(ResourceScope.Process)]
            [ResourceConsumption(ResourceScope.Process)]
            set {
                SetWorkingSetLimits(value, null);
            }
        }
 
        /// <devdoc>
        ///    <para>
        ///       Gets
        ///       the modules that have been loaded by the associated process.
        ///    </para>
        /// </devdoc>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessModules)]
        public ProcessModuleCollection Modules {
            [ResourceExposure(ResourceScope.None)]
            [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
            get {
                if (modules == null) {
                    EnsureState(State.HaveId | State.IsLocal);
                    ModuleInfo[] moduleInfos = ProcessManager.GetModuleInfos(processId);
                    ProcessModule[] newModulesArray = new ProcessModule[moduleInfos.Length];
                    for (int i = 0; i < moduleInfos.Length; i++) {
                        newModulesArray[i] = new ProcessModule(moduleInfos[i]);
                    }
                    ProcessModuleCollection newModules = new ProcessModuleCollection(newModulesArray);
                    modules = newModules;
                }
                return modules;
            }
        }
 
        /// <devdoc>
        ///     Returns the amount of memory that the system has allocated on behalf of the
        ///     associated process that can not be written to the virtual memory paging file.
        /// </devdoc>
        [Obsolete("This property has been deprecated.  Please use System.Diagnostics.Process.NonpagedSystemMemorySize64 instead.  http://go.microsoft.com/fwlink/?linkid=14202")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessNonpagedSystemMemorySize)]
        public int NonpagedSystemMemorySize {
            get {
                EnsureState(State.HaveNtProcessInfo);
                return unchecked((int)processInfo.poolNonpagedBytes);
            }
        }
 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessNonpagedSystemMemorySize)]
        [System.Runtime.InteropServices.ComVisible(false)]            
        public long NonpagedSystemMemorySize64 {
            get {
                EnsureState(State.HaveNtProcessInfo);
                return processInfo.poolNonpagedBytes;
            }
        }
 
        /// <devdoc>
        ///     Returns the amount of memory that the associated process has allocated
        ///     that can be written to the virtual memory paging file.
        /// </devdoc>
        [Obsolete("This property has been deprecated.  Please use System.Diagnostics.Process.PagedMemorySize64 instead.  http://go.microsoft.com/fwlink/?linkid=14202")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessPagedMemorySize)]
        public int PagedMemorySize {
            get {
                EnsureState(State.HaveNtProcessInfo);
                return unchecked((int)processInfo.pageFileBytes);
            }
        }
 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessPagedMemorySize)]
        [System.Runtime.InteropServices.ComVisible(false)]
        public long PagedMemorySize64 {
            get {
                EnsureState(State.HaveNtProcessInfo);
                return processInfo.pageFileBytes;
            }
        }
 
 
        /// <devdoc>
        ///     Returns the amount of memory that the system has allocated on behalf of the
        ///     associated process that can be written to the virtual memory paging file.
        /// </devdoc>
        [Obsolete("This property has been deprecated.  Please use System.Diagnostics.Process.PagedSystemMemorySize64 instead.  http://go.microsoft.com/fwlink/?linkid=14202")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessPagedSystemMemorySize)]
        public int PagedSystemMemorySize {
            get {
                EnsureState(State.HaveNtProcessInfo);
                return unchecked((int)processInfo.poolPagedBytes);
            }
        }
 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessPagedSystemMemorySize)]
        [System.Runtime.InteropServices.ComVisible(false)]
        public long PagedSystemMemorySize64 {
            get {
                EnsureState(State.HaveNtProcessInfo);
                return processInfo.poolPagedBytes;
            }
        }
 
 
        /// <devdoc>
        ///    <para>
        ///       Returns the maximum amount of memory that the associated process has
        ///       allocated that could be written to the virtual memory paging file.
        ///    </para>
        /// </devdoc>
        [Obsolete("This property has been deprecated.  Please use System.Diagnostics.Process.PeakPagedMemorySize64 instead.  http://go.microsoft.com/fwlink/?linkid=14202")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessPeakPagedMemorySize)]
        public int PeakPagedMemorySize {
            get {
                EnsureState(State.HaveNtProcessInfo);
                return unchecked((int)processInfo.pageFileBytesPeak);
            }
        }
 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessPeakPagedMemorySize)]
        [System.Runtime.InteropServices.ComVisible(false)]
        public long PeakPagedMemorySize64 {
            get {
                EnsureState(State.HaveNtProcessInfo);
                return processInfo.pageFileBytesPeak;
            }
        }
        
        /// <devdoc>
        ///    <para>
        ///       Returns the maximum amount of physical memory that the associated
        ///       process required at once.
        ///    </para>
        /// </devdoc>
        [Obsolete("This property has been deprecated.  Please use System.Diagnostics.Process.PeakWorkingSet64 instead.  http://go.microsoft.com/fwlink/?linkid=14202")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessPeakWorkingSet)]
        public int PeakWorkingSet {
            get {
                EnsureState(State.HaveNtProcessInfo);
                return unchecked((int)processInfo.workingSetPeak);
            }
        }
 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessPeakWorkingSet)]
        [System.Runtime.InteropServices.ComVisible(false)]
        public long PeakWorkingSet64 {
            get {
                EnsureState(State.HaveNtProcessInfo);
                return processInfo.workingSetPeak;
            }
        }
 
        /// <devdoc>
        ///     Returns the maximum amount of virtual memory that the associated
        ///     process has requested.
        /// </devdoc>
        [Obsolete("This property has been deprecated.  Please use System.Diagnostics.Process.PeakVirtualMemorySize64 instead.  http://go.microsoft.com/fwlink/?linkid=14202")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessPeakVirtualMemorySize)]
        public int PeakVirtualMemorySize {
            get {
                EnsureState(State.HaveNtProcessInfo);
                return unchecked((int)processInfo.virtualBytesPeak);
            }
        }
 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessPeakVirtualMemorySize)]
        [System.Runtime.InteropServices.ComVisible(false)]
        public long PeakVirtualMemorySize64 {
            get {
                EnsureState(State.HaveNtProcessInfo);
                return processInfo.virtualBytesPeak;
            }
        }
 
        private OperatingSystem OperatingSystem {
            get {
                if (operatingSystem == null) {
                    operatingSystem = Environment.OSVersion;
                }                
                return operatingSystem;
            }
        }
 
        /// <devdoc>
        ///    <para>
        ///       Gets or sets a value indicating whether the associated process priority
        ///       should be temporarily boosted by the operating system when the main window
        ///       has focus.
        ///    </para>
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessPriorityBoostEnabled)]
        public bool PriorityBoostEnabled {
            get {
                EnsureState(State.IsNt);
                if (!havePriorityBoostEnabled) {
                    SafeProcessHandle handle = null;
                    try {
                        handle = GetProcessHandle(NativeMethods.PROCESS_QUERY_INFORMATION);
                        bool disabled = false;
                        if (!NativeMethods.GetProcessPriorityBoost(handle, out disabled)) {
                            throw new Win32Exception();
                        }
                        priorityBoostEnabled = !disabled;
                        havePriorityBoostEnabled = true;
                    }
                    finally {
                        ReleaseProcessHandle(handle);
                    }
                }
                return priorityBoostEnabled;
            }
            set {
                EnsureState(State.IsNt);
                SafeProcessHandle handle = null;
                try {
                    handle = GetProcessHandle(NativeMethods.PROCESS_SET_INFORMATION);
                    if (!NativeMethods.SetProcessPriorityBoost(handle, !value))
                        throw new Win32Exception();
                    priorityBoostEnabled = value;
                    havePriorityBoostEnabled = true;
                }
                finally {
                    ReleaseProcessHandle(handle);
                }
            }
        }
 
        /// <devdoc>
        ///    <para>
        ///       Gets or sets the overall priority category for the
        ///       associated process.
        ///    </para>
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessPriorityClass)]
        public ProcessPriorityClass PriorityClass {
            get {
                if (!havePriorityClass) {
                    SafeProcessHandle handle = null;
                    try {
                        handle = GetProcessHandle(NativeMethods.PROCESS_QUERY_INFORMATION);
                        int value = NativeMethods.GetPriorityClass(handle);
                        if (value == 0) {
                            throw new Win32Exception();
                        }
                        priorityClass = (ProcessPriorityClass)value;
                        havePriorityClass = true;
                    }
                    finally {
                        ReleaseProcessHandle(handle);
                    }
                }
                return priorityClass;
            }
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            set {
                if (!Enum.IsDefined(typeof(ProcessPriorityClass), value)) { 
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(ProcessPriorityClass));
                }
 
                // BelowNormal and AboveNormal are only available on Win2k and greater.
                if (((value & (ProcessPriorityClass.BelowNormal | ProcessPriorityClass.AboveNormal)) != 0)   && 
                    (OperatingSystem.Platform != PlatformID.Win32NT || OperatingSystem.Version.Major < 5)) {
                    throw new PlatformNotSupportedException(SR.GetString(SR.PriorityClassNotSupported), null);
                }                
                                    
                SafeProcessHandle handle = null;
 
                try {
                    handle = GetProcessHandle(NativeMethods.PROCESS_SET_INFORMATION);
                    if (!NativeMethods.SetPriorityClass(handle, (int)value)) {
                        throw new Win32Exception();
                    }
                    priorityClass = value;
                    havePriorityClass = true;
                }
                finally {
                    ReleaseProcessHandle(handle);
                }
            }
        }
 
        /// <devdoc>
        ///     Returns the number of bytes that the associated process has allocated that cannot
        ///     be shared with other processes.
        /// </devdoc>
        [Obsolete("This property has been deprecated.  Please use System.Diagnostics.Process.PrivateMemorySize64 instead.  http://go.microsoft.com/fwlink/?linkid=14202")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessPrivateMemorySize)]
        public int PrivateMemorySize {
            get {
                EnsureState(State.HaveNtProcessInfo);
                return unchecked((int)processInfo.privateBytes);
            }
        }
 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessPrivateMemorySize)]
        [System.Runtime.InteropServices.ComVisible(false)]            
        public long PrivateMemorySize64 {
            get {
                EnsureState(State.HaveNtProcessInfo);
                return processInfo.privateBytes;
            }
        }
 
        /// <devdoc>
        ///     Returns the amount of time the process has spent running code inside the operating
        ///     system core.
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessPrivilegedProcessorTime)]
        public TimeSpan PrivilegedProcessorTime {
            get {
                EnsureState(State.IsNt);
                return GetProcessTimes().PrivilegedProcessorTime;
            }
        }
 
        /// <devdoc>
        ///    <para>
        ///       Gets
        ///       the friendly name of the process.
        ///    </para>
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessProcessName)]
        public string ProcessName {
            [ResourceExposure(ResourceScope.None)]
            [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
            get {
                EnsureState(State.HaveProcessInfo);
                String processName =  processInfo.processName;
                //
                // On some old NT-based OS like win2000, the process name from NTQuerySystemInformation is up to 15 characters.
                // Processes executing notepad_1234567.exe and notepad_12345678.exe will have the same process name.
                // GetProcessByNames will not be able find the process for notepad_12345678.exe.
                // So we will try to replace the name of the process by its main module name if the name is 15 characters.
                // However we can't always get the module name:
                //     (1) Normal user will not be able to get module information about processes. 
                //     (2) We can't get module information about remoting process.
                // We can't get module name for a remote process
                // 
                if (processName.Length == 15 && ProcessManager.IsNt && ProcessManager.IsOSOlderThanXP && !isRemoteMachine) { 
                    try {
                        String mainModuleName = MainModule.ModuleName;
                        if (mainModuleName != null) {
                            processInfo.processName = Path.ChangeExtension(Path.GetFileName(mainModuleName), null);
                        }
                    }
                    catch(Exception) {
                        // If we can't access the module information, we can still use the might-be-truncated name. 
                        // We could fail for a few reasons:
                        // (1) We don't enough privilege to get module information.
                        // (2) The process could have terminated.
                    }
                }
                
                return processInfo.processName;
            }
        }
 
        /// <devdoc>
        ///    <para>
        ///       Gets
        ///       or sets which processors the threads in this process can be scheduled to run on.
        ///    </para>
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessProcessorAffinity)]
        public IntPtr ProcessorAffinity {
            get {
                if (!haveProcessorAffinity) {
                    SafeProcessHandle handle = null;
                    try {
                        handle = GetProcessHandle(NativeMethods.PROCESS_QUERY_INFORMATION);
                        IntPtr processAffinity;
                        IntPtr systemAffinity;
                        if (!NativeMethods.GetProcessAffinityMask(handle, out processAffinity, out systemAffinity))
                            throw new Win32Exception();
                        processorAffinity = processAffinity;
                    }
                    finally {
                        ReleaseProcessHandle(handle);
                    }
                    haveProcessorAffinity = true;
                }
                return processorAffinity;
            }
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            set {
                SafeProcessHandle handle = null;
                try {
                    handle = GetProcessHandle(NativeMethods.PROCESS_SET_INFORMATION);
                    if (!NativeMethods.SetProcessAffinityMask(handle, value)) 
                        throw new Win32Exception();
                        
                    processorAffinity = value;
                    haveProcessorAffinity = true;
                }
                finally {
                    ReleaseProcessHandle(handle);
                }
            }
        }
 
        /// <devdoc>
        ///    <para>
        ///       Gets a value indicating whether or not the user
        ///       interface of the process is responding.
        ///    </para>
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessResponding)]
        public bool Responding {
            [ResourceExposure(ResourceScope.None)]
            [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
            get {
                if (!haveResponding) {
                    IntPtr mainWindow = MainWindowHandle;
                    if (mainWindow == (IntPtr)0) {
                        responding = true;
                    }
                    else {
                        IntPtr result;
                        responding = NativeMethods.SendMessageTimeout(new HandleRef(this, mainWindow), NativeMethods.WM_NULL, IntPtr.Zero, IntPtr.Zero, NativeMethods.SMTO_ABORTIFHUNG, 5000, out result) != (IntPtr)0;
                    }
                }
                return responding;
            }
        }
 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessSessionId)]
        public int SessionId {
            get {
                EnsureState(State.HaveNtProcessInfo);
                return processInfo.sessionId;                
            }
        }
 
#endif // !FEATURE_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;
            }
            [ResourceExposure(ResourceScope.Machine)]
            set {
                if (value == null) { 
                    throw new ArgumentNullException("value");
                }
                startInfo = value;
            }
        }
 
#if !FEATURE_PAL        
        /// <devdoc>
        ///     Returns the time the associated process was started.
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessStartTime)]
        public DateTime StartTime {
            get {
                EnsureState(State.IsNt);
                return GetProcessTimes().StartTime;
            }
        }
#endif // !FEATURE_PAL
 
        /// <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;
            }
        }
 
#if !FEATURE_PAL        
        
        /// <devdoc>
        ///    <para>
        ///       Gets the set of threads that are running in the associated
        ///       process.
        ///    </para>
        /// </devdoc>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessThreads)]
        public ProcessThreadCollection Threads {
            [ResourceExposure(ResourceScope.Process)]
            [ResourceConsumption(ResourceScope.Process)]
            get {
                if (threads == null) {
                    EnsureState(State.HaveProcessInfo);
                    int count = processInfo.threadInfoList.Count;
                    ProcessThread[] newThreadsArray = new ProcessThread[count];
                    for (int i = 0; i < count; i++) {
                        newThreadsArray[i] = new ProcessThread(isRemoteMachine, (ThreadInfo)processInfo.threadInfoList[i]);
                    }
                    ProcessThreadCollection newThreads = new ProcessThreadCollection(newThreadsArray);
                    threads = newThreads;
                }
                return threads;
            }
        }
 
        /// <devdoc>
        ///     Returns the amount of time the associated process has spent utilizing the CPU.
        ///     It is the sum of the <see cref='System.Diagnostics.Process.UserProcessorTime'/> and
        ///     <see cref='System.Diagnostics.Process.PrivilegedProcessorTime'/>.
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessTotalProcessorTime)]
        public TimeSpan TotalProcessorTime {
            get {
                EnsureState(State.IsNt);
                return GetProcessTimes().TotalProcessorTime;
            }
        }
 
        /// <devdoc>
        ///     Returns the amount of time the associated process has spent running code
        ///     inside the application portion of the process (not the operating system core).
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessUserProcessorTime)]
        public TimeSpan UserProcessorTime {
            get {
                EnsureState(State.IsNt);
                return GetProcessTimes().UserProcessorTime;
            }
        }
 
        /// <devdoc>
        ///     Returns the amount of virtual memory that the associated process has requested.
        /// </devdoc>
        [Obsolete("This property has been deprecated.  Please use System.Diagnostics.Process.VirtualMemorySize64 instead.  http://go.microsoft.com/fwlink/?linkid=14202")]        
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessVirtualMemorySize)]
        public int VirtualMemorySize {
            get {
                EnsureState(State.HaveNtProcessInfo);
                return unchecked((int)processInfo.virtualBytes);
            }
        }
#endif // !FEATURE_PAL
 
        [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;
            }
        }
 
#if !FEATURE_PAL  
        /// <devdoc>
        ///     Returns the total amount of physical memory the associated process.
        /// </devdoc>
        [Obsolete("This property has been deprecated.  Please use System.Diagnostics.Process.WorkingSet64 instead.  http://go.microsoft.com/fwlink/?linkid=14202")]        
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessWorkingSet)]
        public int WorkingSet {
            get {
                EnsureState(State.HaveNtProcessInfo);
                return unchecked((int)processInfo.workingSet);
            }
        }
#endif // !FEATURE_PAL
 
        [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;
            }
        }
 
#if !FEATURE_PAL
    
        /// <devdoc>
        ///    <para>
        ///       Closes a process that has a user interface by sending a close message
        ///       to its main window.
        ///    </para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Machine)]  // Review usages of this.
        [ResourceConsumption(ResourceScope.Machine)]
        public bool CloseMainWindow() {
            IntPtr mainWindowHandle = MainWindowHandle;
            if (mainWindowHandle == (IntPtr)0) return false;
            int style = NativeMethods.GetWindowLong(new HandleRef(this, mainWindowHandle), NativeMethods.GWL_STYLE);
            if ((style & NativeMethods.WS_DISABLED) != 0) return false;
            NativeMethods.PostMessage(new HandleRef(this, mainWindowHandle), NativeMethods.WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
            return true;
        }
 
#endif // !FEATURE_PAL
 
        /// <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) {
                    //Dispose managed and unmanaged resources
                    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;
 
                //Don't call close on the Readers and writers
                //since they might be referenced by somebody else while the 
                //process is still alive but this method called.
                standardOutput = null;
                standardInput = null;
                standardError = null;
 
                output = null;
                error = null;
	
 
                Refresh();
            }
        }
 
        /// <devdoc>
        ///     Helper method for checking preconditions when accessing properties.
        /// </devdoc>
        /// <internalonly/>
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        void EnsureState(State state) {
 
            if ((state & State.IsWin2k) != (State)0) {
#if !FEATURE_PAL
                if (OperatingSystem.Platform != PlatformID.Win32NT || OperatingSystem.Version.Major < 5)
#endif // !FEATURE_PAL
                    throw new PlatformNotSupportedException(SR.GetString(SR.Win2kRequired));
            }
 
            if ((state & State.IsNt) != (State)0) {
#if !FEATURE_PAL
                if (OperatingSystem.Platform != PlatformID.Win32NT)
#endif // !FEATURE_PAL                    
                    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) {
#if !FEATURE_PAL                    
                    if (haveProcessHandle) {
                        SetProcessId(ProcessManager.GetProcessIdFromHandle(m_processHandle));
                     }
                    else {                     
                        EnsureState(State.Associated);
                        throw new InvalidOperationException(SR.GetString(SR.ProcessIdRequired));
                    }
#else
                    EnsureState(State.Associated);
                    throw new InvalidOperationException(SR.GetString(SR.ProcessIdRequired));
#endif // !FEATURE_PAL
                }
            }
 
            if ((state & State.IsLocal) != (State)0 && isRemoteMachine) {
                    throw new NotSupportedException(SR.GetString(SR.NotSupportedRemote));
            }
            
            if ((state & State.HaveProcessInfo) != (State)0) {
#if !FEATURE_PAL                
                if (processInfo == null) {
                    if ((state & State.HaveId) == (State)0) EnsureState(State.HaveId);
                    processInfo = ProcessManager.GetProcessInfo(processId, machineName);
                    if (processInfo == null) {
                        throw new InvalidOperationException(SR.GetString(SR.NoProcessInfo));
                    }
                }
#else
                throw new InvalidOperationException(SR.GetString(SR.NoProcessInfo));
#endif // !FEATURE_PAL
            }
 
            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) {
                lock (this) {
                    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;
                        }
                    }
                }
            }
        }
 
#if !FEATURE_PAL    
 
        /// <devdoc>
        ///     Make sure we have obtained the min and max working set limits.
        /// </devdoc>
        /// <internalonly/>
        void EnsureWorkingSetLimits() {
            EnsureState(State.IsNt);
            if (!haveWorkingSetLimits) {
                SafeProcessHandle handle = null;
                try {
                    handle = GetProcessHandle(NativeMethods.PROCESS_QUERY_INFORMATION);
                    IntPtr min;
                    IntPtr max;
                    if (!NativeMethods.GetProcessWorkingSetSize(handle, out min, out max)) {
                        throw new Win32Exception();
                    }
                    minWorkingSet = min;
                    maxWorkingSet = max;
                    haveWorkingSetLimits = true;
                }
                finally {
                    ReleaseProcessHandle(handle);
                }
            }
        }
 
        public static void EnterDebugMode() {
            if (ProcessManager.IsNt) {
                SetPrivilege("SeDebugPrivilege", NativeMethods.SE_PRIVILEGE_ENABLED);
            }
        }
 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
        private static void SetPrivilege(string privilegeName, int attrib) {
            IntPtr hToken = (IntPtr)0;
            NativeMethods.LUID debugValue = new NativeMethods.LUID();
 
            // this is only a "pseudo handle" to the current process - no need to close it later
            IntPtr processHandle = NativeMethods.GetCurrentProcess();
 
            // get the process token so we can adjust the privilege on it.  We DO need to
            // close the token when we're done with it.
            if (!NativeMethods.OpenProcessToken(new HandleRef(null, processHandle), NativeMethods.TOKEN_ADJUST_PRIVILEGES, out hToken)) {
                throw new Win32Exception();
            }
 
            try {
                if (!NativeMethods.LookupPrivilegeValue(null, privilegeName, out debugValue)) {
                    throw new Win32Exception();
                }
                
                NativeMethods.TokenPrivileges tkp = new NativeMethods.TokenPrivileges();
                tkp.Luid = debugValue;
                tkp.Attributes = attrib;
    
                NativeMethods.AdjustTokenPrivileges(new HandleRef(null, hToken), false, tkp, 0, IntPtr.Zero, IntPtr.Zero);
    
                // AdjustTokenPrivileges can return true even if it failed to
                // set the privilege, so we need to use GetLastError
                if (Marshal.GetLastWin32Error() != NativeMethods.ERROR_SUCCESS) {
                    throw new Win32Exception();
                }
            }
            finally {
                Debug.WriteLineIf(processTracing.TraceVerbose, "Process - CloseHandle(processToken)");
                SafeNativeMethods.CloseHandle(hToken);
            }
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public static void LeaveDebugMode() {
            if (ProcessManager.IsNt) {
                SetPrivilege("SeDebugPrivilege", 0);
            }
        }     
 
        /// <devdoc>
        ///    <para>
        ///       Returns a new <see cref='System.Diagnostics.Process'/> component given a process identifier and
        ///       the name of a computer in the network.
        ///    </para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static Process GetProcessById(int processId, string machineName) {
            if (!ProcessManager.IsProcessRunning(processId, machineName)) {
                throw new ArgumentException(SR.GetString(SR.MissingProccess, processId.ToString(CultureInfo.CurrentCulture)));
            }
            
            return new Process(machineName, ProcessManager.IsRemoteMachine(machineName), processId, null);
        }
 
        /// <devdoc>
        ///    <para>
        ///       Returns a new <see cref='System.Diagnostics.Process'/> component given the
        ///       identifier of a process on the local computer.
        ///    </para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static Process GetProcessById(int processId) {
            return GetProcessById(processId, ".");
        }
 
        /// <devdoc>
        ///    <para>
        ///       Creates an array of <see cref='System.Diagnostics.Process'/> components that are
        ///       associated
        ///       with process resources on the
        ///       local computer. These process resources share the specified process name.
        ///    </para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static Process[] GetProcessesByName(string processName) {
            return GetProcessesByName(processName, ".");
        }
 
        /// <devdoc>
        ///    <para>
        ///       Creates an array of <see cref='System.Diagnostics.Process'/> components that are associated with process resources on a
        ///       remote computer. These process resources share the specified process name.
        ///    </para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static Process[] GetProcessesByName(string processName, string machineName) {
            if (processName == null) processName = String.Empty;
            Process[] procs = GetProcesses(machineName);
            ArrayList list = new ArrayList();
 
            for(int i = 0; i < procs.Length; i++) {                
                if( String.Equals(processName, procs[i].ProcessName, StringComparison.OrdinalIgnoreCase)) {
                    list.Add( procs[i]);                    
                } else {
                    procs[i].Dispose();
                }
            }
            
            Process[] temp = new Process[list.Count];
            list.CopyTo(temp, 0);
            return temp;
        }
 
        /// <devdoc>
        ///    <para>
        ///       Creates a new <see cref='System.Diagnostics.Process'/>
        ///       component for each process resource on the local computer.
        ///    </para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static Process[] GetProcesses() {
            return GetProcesses(".");
        }
 
        /// <devdoc>
        ///    <para>
        ///       Creates a new <see cref='System.Diagnostics.Process'/>
        ///       component for each
        ///       process resource on the specified computer.
        ///    </para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static Process[] GetProcesses(string machineName) {
            bool isRemoteMachine = ProcessManager.IsRemoteMachine(machineName);
            ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(machineName);
            Process[] processes = new Process[processInfos.Length];
            for (int i = 0; i < processInfos.Length; i++) {
                ProcessInfo processInfo = processInfos[i];
                processes[i] = new Process(machineName, isRemoteMachine, processInfo.processId, processInfo);
            }
            Debug.WriteLineIf(processTracing.TraceVerbose, "Process.GetProcesses(" + machineName + ")");
#if DEBUG
            if (processTracing.TraceVerbose) {
                Debug.Indent();
                for (int i = 0; i < processInfos.Length; i++) {
                    Debug.WriteLine(processes[i].Id + ": " + processes[i].ProcessName);
                }
                Debug.Unindent();
            }
#endif
            return processes;
        }
 
#endif // !FEATURE_PAL        
 
        /// <devdoc>
        ///    <para>
        ///       Returns a new <see cref='System.Diagnostics.Process'/>
        ///       component and associates it with the current active process.
        ///    </para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Process)]
        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/>
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        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) {
                    // Since haveProcessHandle is true, we know we have the process handle
                    // open with at least SYNCHRONIZE access, so we can wait on it with 
                    // zero timeout to see if the process has exited.
                    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;
#if !FEATURE_PAL                
                handle = ProcessManager.OpenProcess(processId, access, throwIfExited);
#else
                IntPtr pseudohandle = NativeMethods.GetCurrentProcess();
                // Get a real handle
                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();
                }
#endif // !FEATURE_PAL
                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() {
            return OpenProcessHandle(NativeMethods.PROCESS_ALL_ACCESS);
        }
 
        SafeProcessHandle OpenProcessHandle(Int32 access) {
            if (!haveProcessHandle) {
                //Cannot open a new process handle if the object has been disposed, since finalization has been suppressed.            
                if (this.disposed) {
                    throw new ObjectDisposedException(GetType().Name);
                }
                        
                SetProcessHandle(GetProcessHandle(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;
#if !FEATURE_PAL            
            threads = null;
            modules = null;
#endif // !FEATURE_PAL            
            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;
            if (watchForExit) {
                EnsureWatchingForExit();
            }
        }
 
        /// <devdoc>
        ///     Helper to associate a process id with this component.
        /// </devdoc>
        /// <internalonly/>
        [ResourceExposure(ResourceScope.Machine)]
        void SetProcessId(int processId) {
            this.processId = processId;
            this.haveProcessId = true;
        }
 
#if !FEATURE_PAL        
 
        /// <devdoc>
        ///     Helper to set minimum or maximum working set limits.
        /// </devdoc>
        /// <internalonly/>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        void SetWorkingSetLimits(object newMin, object newMax) {
            EnsureState(State.IsNt);
 
            SafeProcessHandle handle = null;
            try {
                handle = GetProcessHandle(NativeMethods.PROCESS_QUERY_INFORMATION | NativeMethods.PROCESS_SET_QUOTA);
                IntPtr min;
                IntPtr max;
                if (!NativeMethods.GetProcessWorkingSetSize(handle, out min, out max)) {
                    throw new Win32Exception();
                }
                
                if (newMin != null) {
                    min = (IntPtr)newMin;
                }
                
                if (newMax != null) { 
                    max = (IntPtr)newMax;
                }
                
                if ((long)min > (long)max) {
                    if (newMin != null) {
                        throw new ArgumentException(SR.GetString(SR.BadMinWorkset));
                    }
                    else {
                        throw new ArgumentException(SR.GetString(SR.BadMaxWorkset));
                    }
                }
                
                if (!NativeMethods.SetProcessWorkingSetSize(handle, min, max)) {
                    throw new Win32Exception();
                }
                
                // The value may be rounded/changed by the OS, so go get it
                if (!NativeMethods.GetProcessWorkingSetSize(handle, out min, out max)) {
                    throw new Win32Exception();
                }
                minWorkingSet = min;
                maxWorkingSet = max;
                haveWorkingSetLimits = true;
            }
            finally {
                ReleaseProcessHandle(handle);
            }
        }
 
#endif // !FEATURE_PAL
 
        /// <devdoc>
        ///    <para>
        ///       Starts a process specified by the <see cref='System.Diagnostics.Process.StartInfo'/> property of this <see cref='System.Diagnostics.Process'/>
        ///       component and associates it with the
        ///    <see cref='System.Diagnostics.Process'/> . If a process resource is reused 
        ///       rather than started, the reused process is associated with this <see cref='System.Diagnostics.Process'/>
        ///       component.
        ///    </para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        public bool Start() {
            Close();
            ProcessStartInfo startInfo = StartInfo;
            if (startInfo.FileName.Length == 0) 
                throw new InvalidOperationException(SR.GetString(SR.FileNameMissing));
 
            if (startInfo.UseShellExecute) {
#if !FEATURE_PAL                
                return StartWithShellExecuteEx(startInfo);
#else
                throw new InvalidOperationException(SR.GetString(SR.net_perm_invalid_val, "StartInfo.UseShellExecute", true));
#endif // !FEATURE_PAL
            } else {
                return StartWithCreateProcess(startInfo);
            }
        }
 
 
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        private static void CreatePipeWithSecurityAttributes(out SafeFileHandle hReadPipe, out SafeFileHandle hWritePipe, NativeMethods.SECURITY_ATTRIBUTES lpPipeAttributes, int nSize) {
            bool ret = NativeMethods.CreatePipe(out hReadPipe, out hWritePipe, lpPipeAttributes, nSize);
            if (!ret || hReadPipe.IsInvalid || hWritePipe.IsInvalid) {
                throw new Win32Exception();
            }
        }
 
        // Using synchronous Anonymous pipes for process input/output redirection means we would end up 
        // wasting a worker threadpool thread per pipe instance. Overlapped pipe IO is desirable, since 
        // it will take advantage of the NT IO completion port infrastructure. But we can't really use 
        // Overlapped I/O for process input/output as it would break Console apps (managed Console class 
        // methods such as WriteLine as well as native CRT functions like printf) which are making an
        // assumption that the console standard handles (obtained via GetStdHandle()) are opened
        // for synchronous I/O and hence they can work fine with ReadFile/WriteFile synchrnously!
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        private void CreatePipe(out SafeFileHandle parentHandle, out SafeFileHandle childHandle, bool parentInputs) {
            NativeMethods.SECURITY_ATTRIBUTES securityAttributesParent = new NativeMethods.SECURITY_ATTRIBUTES();
            securityAttributesParent.bInheritHandle = true;
            
            SafeFileHandle hTmp = null;
            try {
                if (parentInputs) {
                    CreatePipeWithSecurityAttributes(out childHandle, out hTmp, securityAttributesParent, 0);                                                          
                } 
                else {
                    CreatePipeWithSecurityAttributes(out hTmp, 
                                                          out childHandle, 
                                                          securityAttributesParent, 
                                                          0);                                                                              
                }
                // Duplicate the parent handle to be non-inheritable so that the child process 
                // doesn't have access. This is done for correctness sake, exact reason is unclear.
                // One potential theory is that child process can do something brain dead like 
                // closing the parent end of the pipe and there by getting into a blocking situation
                // as parent will not be draining the pipe at the other end anymore. 
                if (!NativeMethods.DuplicateHandle(new HandleRef(this, NativeMethods.GetCurrentProcess()), 
                                                                   hTmp,
                                                                   new HandleRef(this, NativeMethods.GetCurrentProcess()), 
                                                                   out parentHandle,
                                                                   0, 
                                                                   false, 
                                                                   NativeMethods.DUPLICATE_SAME_ACCESS)) {                                                                       
                    throw new Win32Exception();
                }
            }
            finally {
                if( hTmp != null && !hTmp.IsInvalid) {
                    hTmp.Close();
                }
            }
        }            
 
        private static StringBuilder BuildCommandLine(string executableFileName, string arguments) {
            // Construct a StringBuilder with the appropriate command line
            // to pass to CreateProcess.  If the filename isn't already 
            // in quotes, we quote it here.  This prevents some security
            // problems (it specifies exactly which part of the string
            // is the file to execute).
            StringBuilder commandLine = new StringBuilder();
            string fileName = executableFileName.Trim();
            bool fileNameIsQuoted = (fileName.StartsWith("\"", StringComparison.Ordinal) && fileName.EndsWith("\"", StringComparison.Ordinal));
            if (!fileNameIsQuoted) { 
                commandLine.Append("\"");
            }
            
            commandLine.Append(fileName);
            
            if (!fileNameIsQuoted) {
                commandLine.Append("\"");
            }
            
            if (!String.IsNullOrEmpty(arguments)) {
                commandLine.Append(" ");
                commandLine.Append(arguments);                
            }                        
 
            return commandLine;
        }
        
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        private bool StartWithCreateProcess(ProcessStartInfo startInfo) {
            if( startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput) {
                throw new InvalidOperationException(SR.GetString(SR.StandardOutputEncodingNotAllowed));
            }
 
            if( startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError) {
                throw new InvalidOperationException(SR.GetString(SR.StandardErrorEncodingNotAllowed));
            }            
            
            // See knowledge base article Q190351 for an explanation of the following code.  Noteworthy tricky points:
            //    * The handles are duplicated as non-inheritable before they are passed to CreateProcess so
            //      that the child process can not close them
            //    * CreateProcess allows you to redirect all or none of the standard IO handles, so we use
            //      GetStdHandle for the handles that are not being redirected
 
            //Cannot start a new process and store its handle if the object has been disposed, since finalization has been suppressed.            
            if (this.disposed) {
                throw new ObjectDisposedException(GetType().Name);
            }
 
            StringBuilder commandLine = BuildCommandLine(startInfo.FileName, startInfo.Arguments);
 
            NativeMethods.STARTUPINFO startupInfo = new NativeMethods.STARTUPINFO();
            SafeNativeMethods.PROCESS_INFORMATION processInfo = new SafeNativeMethods.PROCESS_INFORMATION();
            SafeProcessHandle procSH = new SafeProcessHandle();
            SafeThreadHandle threadSH = new SafeThreadHandle();
            bool retVal;
            int errorCode = 0;
            // handles used in parent process
            SafeFileHandle standardInputWritePipeHandle = null;
            SafeFileHandle standardOutputReadPipeHandle = null;
            SafeFileHandle standardErrorReadPipeHandle = null;
            GCHandle environmentHandle = new GCHandle();            
            lock (s_CreateProcessLock) {
            try {
                // set up the streams
                if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError) {                        
                    if (startInfo.RedirectStandardInput) {
                        CreatePipe(out standardInputWritePipeHandle, out startupInfo.hStdInput, true);
                        } else {
                        startupInfo.hStdInput  =  new SafeFileHandle(NativeMethods.GetStdHandle(NativeMethods.STD_INPUT_HANDLE), false);
                    }
    
                    if (startInfo.RedirectStandardOutput) {                        
                        CreatePipe(out standardOutputReadPipeHandle, out startupInfo.hStdOutput, false);
                        } else {
                        startupInfo.hStdOutput = new SafeFileHandle(NativeMethods.GetStdHandle(NativeMethods.STD_OUTPUT_HANDLE), false);
                    }
    
                    if (startInfo.RedirectStandardError) {
                        CreatePipe(out standardErrorReadPipeHandle, out startupInfo.hStdError, false);
                        } else {
                        startupInfo.hStdError = new SafeFileHandle(NativeMethods.GetStdHandle(NativeMethods.STD_ERROR_HANDLE), false);
                    }
    
                    startupInfo.dwFlags = NativeMethods.STARTF_USESTDHANDLES;
                }
    
                // set up the creation flags paramater
                int creationFlags = 0;
#if !FEATURE_PAL                
                if (startInfo.CreateNoWindow)  creationFlags |= NativeMethods.CREATE_NO_WINDOW;               
#endif // !FEATURE_PAL                
 
                // set up the environment block parameter
                IntPtr environmentPtr = (IntPtr)0;
                if (startInfo.environmentVariables != null) {
                    bool unicode = false;
#if !FEATURE_PAL                    
                    if (ProcessManager.IsNt) {
                        creationFlags |= NativeMethods.CREATE_UNICODE_ENVIRONMENT;                
                        unicode = true;
                    }
#endif // !FEATURE_PAL
                    
                    byte[] environmentBytes = EnvironmentBlock.ToByteArray(startInfo.environmentVariables, unicode);
                    environmentHandle = GCHandle.Alloc(environmentBytes, GCHandleType.Pinned);
                    environmentPtr = environmentHandle.AddrOfPinnedObject();
                }
 
                string workingDirectory = startInfo.WorkingDirectory;
                if (workingDirectory == string.Empty)
                    workingDirectory = Environment.CurrentDirectory;
 
#if !FEATURE_PAL                    
                if (startInfo.UserName.Length != 0) {                              
                    if (startInfo.Password != null && startInfo.PasswordInClearText != null)
                            throw new ArgumentException(SR.GetString(SR.CantSetDuplicatePassword));
 
                    NativeMethods.LogonFlags logonFlags = (NativeMethods.LogonFlags)0;                    
                    if( startInfo.LoadUserProfile) {
                        logonFlags = NativeMethods.LogonFlags.LOGON_WITH_PROFILE;
                    }
 
                    IntPtr password = IntPtr.Zero;
                    try {
                        if( startInfo.Password != null) {
                            password = Marshal.SecureStringToCoTaskMemUnicode(startInfo.Password);
                        } else if( startInfo.PasswordInClearText != null) {
                            password = Marshal.StringToCoTaskMemUni(startInfo.PasswordInClearText);
                        } else {
                            password = Marshal.StringToCoTaskMemUni(String.Empty);
                        }
 
                        RuntimeHelpers.PrepareConstrainedRegions();
                        try {} finally {
                           retVal = NativeMethods.CreateProcessWithLogonW(
                                   startInfo.UserName,
                                   startInfo.Domain,
                                   password,
                                   logonFlags,
                                   null,            // we don't need this since all the info is in commandLine
                                   commandLine,
                                   creationFlags,
                                   environmentPtr,
                                   workingDirectory,
                                   startupInfo,        // pointer to STARTUPINFO
                                   processInfo         // pointer to PROCESS_INFORMATION
                               ); 
                           if (!retVal)                            
                              errorCode = Marshal.GetLastWin32Error();
                           if ( processInfo.hProcess!= (IntPtr)0 && processInfo.hProcess!= (IntPtr)NativeMethods.INVALID_HANDLE_VALUE)
                              procSH.InitialSetHandle(processInfo.hProcess);  
                           if ( processInfo.hThread != (IntPtr)0 && processInfo.hThread != (IntPtr)NativeMethods.INVALID_HANDLE_VALUE)
                              threadSH.InitialSetHandle(processInfo.hThread);            
                        }
                        if (!retVal){                            
                                if (errorCode == NativeMethods.ERROR_BAD_EXE_FORMAT || errorCode == NativeMethods.ERROR_EXE_MACHINE_TYPE_MISMATCH) {
                                throw new Win32Exception(errorCode, SR.GetString(SR.InvalidApplication));
                            }
 
                            throw new Win32Exception(errorCode);
                        }
                        } finally {
                        if( password != IntPtr.Zero) {
                            Marshal.ZeroFreeCoTaskMemUnicode(password);
                        }
                    }
                    } else {
#endif // !FEATURE_PAL
                    RuntimeHelpers.PrepareConstrainedRegions();
                    try {} finally {
                       retVal = NativeMethods.CreateProcess (
                               null,               // we don't need this since all the info is in commandLine
                               commandLine,        // pointer to the command line string
                               null,               // pointer to process security attributes, we don't need to inheriat the handle
                               null,               // pointer to thread security attributes
                               true,               // handle inheritance flag
                               creationFlags,      // creation flags
                               environmentPtr,     // pointer to new environment block
                               workingDirectory,   // pointer to current directory name
                               startupInfo,        // pointer to STARTUPINFO
                               processInfo         // pointer to PROCESS_INFORMATION
                           );
                       if (!retVal)                            
                              errorCode = Marshal.GetLastWin32Error();
                       if ( processInfo.hProcess!= (IntPtr)0 && processInfo.hProcess!= (IntPtr)NativeMethods.INVALID_HANDLE_VALUE)
                           procSH.InitialSetHandle(processInfo.hProcess);  
                       if ( processInfo.hThread != (IntPtr)0 && processInfo.hThread != (IntPtr)NativeMethods.INVALID_HANDLE_VALUE)
                          threadSH.InitialSetHandle(processInfo.hThread);                    
                    }
                    if (!retVal) {
                            if (errorCode == NativeMethods.ERROR_BAD_EXE_FORMAT || errorCode == NativeMethods.ERROR_EXE_MACHINE_TYPE_MISMATCH) {
                          throw new Win32Exception(errorCode, SR.GetString(SR.InvalidApplication));
                       }
                        throw new Win32Exception(errorCode);
                    }
#if !FEATURE_PAL                    
                }
#endif
                } finally {
                // free environment block
                if (environmentHandle.IsAllocated) {
                    environmentHandle.Free();   
                }
 
                startupInfo.Dispose();
            }
            }
 
            if (startInfo.RedirectStandardInput) {
                standardInput = new StreamWriter(new FileStream(standardInputWritePipeHandle, FileAccess.Write, 4096, false), Console.InputEncoding, 4096);
                standardInput.AutoFlush = true;
            }
            if (startInfo.RedirectStandardOutput) {
                Encoding enc = (startInfo.StandardOutputEncoding != null) ? startInfo.StandardOutputEncoding : Console.OutputEncoding;
                standardOutput = new StreamReader(new FileStream(standardOutputReadPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096);
            }
            if (startInfo.RedirectStandardError) {
                Encoding enc = (startInfo.StandardErrorEncoding != null) ? startInfo.StandardErrorEncoding : Console.OutputEncoding;
                standardError = new StreamReader(new FileStream(standardErrorReadPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096);
            }
            
            bool ret = false;
            if (!procSH.IsInvalid) {
                SetProcessHandle(procSH);
                SetProcessId(processInfo.dwProcessId);
                threadSH.Close();
                ret = true;
            }
 
            return ret;
 
        }
 
#if !FEATURE_PAL
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        private bool StartWithShellExecuteEx(ProcessStartInfo startInfo) {                        
            //Cannot start a new process and store its handle if the object has been disposed, since finalization has been suppressed.            
            if (this.disposed)
                throw new ObjectDisposedException(GetType().Name);
 
            if( !String.IsNullOrEmpty(startInfo.UserName) || (startInfo.Password != null) ) {
                throw new InvalidOperationException(SR.GetString(SR.CantStartAsUser));                
            }
            
            if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError) {
                throw new InvalidOperationException(SR.GetString(SR.CantRedirectStreams));
            }
 
            if (startInfo.StandardErrorEncoding != null) {
                throw new InvalidOperationException(SR.GetString(SR.StandardErrorEncodingNotAllowed));
            }
 
            if (startInfo.StandardOutputEncoding != null) {
                throw new InvalidOperationException(SR.GetString(SR.StandardOutputEncodingNotAllowed));
            }
 
            // can't set env vars with ShellExecuteEx...
            if (startInfo.environmentVariables != null) {
                throw new InvalidOperationException(SR.GetString(SR.CantUseEnvVars));
            }
 
            NativeMethods.ShellExecuteInfo shellExecuteInfo = new NativeMethods.ShellExecuteInfo();
            shellExecuteInfo.fMask = NativeMethods.SEE_MASK_NOCLOSEPROCESS;
            if (startInfo.ErrorDialog) {
                shellExecuteInfo.hwnd = startInfo.ErrorDialogParentHandle;
            }
            else {
                shellExecuteInfo.fMask |= NativeMethods.SEE_MASK_FLAG_NO_UI;
            }
 
            switch (startInfo.WindowStyle) {
                case ProcessWindowStyle.Hidden:
                    shellExecuteInfo.nShow = NativeMethods.SW_HIDE;
                    break;
                case ProcessWindowStyle.Minimized:
                    shellExecuteInfo.nShow = NativeMethods.SW_SHOWMINIMIZED;
                    break;
                case ProcessWindowStyle.Maximized:
                    shellExecuteInfo.nShow = NativeMethods.SW_SHOWMAXIMIZED;
                    break;
                default:
                    shellExecuteInfo.nShow = NativeMethods.SW_SHOWNORMAL;
                    break;
            }
 
            
            try {
                if (startInfo.FileName.Length != 0)
                    shellExecuteInfo.lpFile = Marshal.StringToHGlobalAuto(startInfo.FileName);
                if (startInfo.Verb.Length != 0)
                    shellExecuteInfo.lpVerb = Marshal.StringToHGlobalAuto(startInfo.Verb);
                if (startInfo.Arguments.Length != 0)
                    shellExecuteInfo.lpParameters = Marshal.StringToHGlobalAuto(startInfo.Arguments);
                if (startInfo.WorkingDirectory.Length != 0)
                    shellExecuteInfo.lpDirectory = Marshal.StringToHGlobalAuto(startInfo.WorkingDirectory);
 
                shellExecuteInfo.fMask |= NativeMethods.SEE_MASK_FLAG_DDEWAIT;
 
                ShellExecuteHelper executeHelper = new ShellExecuteHelper(shellExecuteInfo);
                if (!executeHelper.ShellExecuteOnSTAThread()) {
                    int error = executeHelper.ErrorCode;
                    if (error == 0) {
                        switch ((long)shellExecuteInfo.hInstApp) {
                            case NativeMethods.SE_ERR_FNF: error = NativeMethods.ERROR_FILE_NOT_FOUND; break;
                            case NativeMethods.SE_ERR_PNF: error = NativeMethods.ERROR_PATH_NOT_FOUND; break;
                            case NativeMethods.SE_ERR_ACCESSDENIED: error = NativeMethods.ERROR_ACCESS_DENIED; break;
                            case NativeMethods.SE_ERR_OOM: error = NativeMethods.ERROR_NOT_ENOUGH_MEMORY; break;
                            case NativeMethods.SE_ERR_DDEFAIL:
                            case NativeMethods.SE_ERR_DDEBUSY:
                            case NativeMethods.SE_ERR_DDETIMEOUT: error = NativeMethods.ERROR_DDE_FAIL; break;
                            case NativeMethods.SE_ERR_SHARE: error = NativeMethods.ERROR_SHARING_VIOLATION; break;
                            case NativeMethods.SE_ERR_NOASSOC: error = NativeMethods.ERROR_NO_ASSOCIATION; break;
                            case NativeMethods.SE_ERR_DLLNOTFOUND: error = NativeMethods.ERROR_DLL_NOT_FOUND; break;
                            default: error = (int)shellExecuteInfo.hInstApp; break;
                        }
                    }
                    if( error == NativeMethods.ERROR_BAD_EXE_FORMAT || error == NativeMethods.ERROR_EXE_MACHINE_TYPE_MISMATCH) {
                        throw new Win32Exception(error, SR.GetString(SR.InvalidApplication));
                    }
                    throw new Win32Exception(error);
                }
            
            }
            finally {                
                if (shellExecuteInfo.lpFile != (IntPtr)0) Marshal.FreeHGlobal(shellExecuteInfo.lpFile);
                if (shellExecuteInfo.lpVerb != (IntPtr)0) Marshal.FreeHGlobal(shellExecuteInfo.lpVerb);
                if (shellExecuteInfo.lpParameters != (IntPtr)0) Marshal.FreeHGlobal(shellExecuteInfo.lpParameters);
                if (shellExecuteInfo.lpDirectory != (IntPtr)0) Marshal.FreeHGlobal(shellExecuteInfo.lpDirectory);
            }
 
            if (shellExecuteInfo.hProcess != (IntPtr)0) {                
                SafeProcessHandle handle = new SafeProcessHandle(shellExecuteInfo.hProcess);
                SetProcessHandle(handle);
                return true;
            }
            
            return false;            
        }
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static Process Start( string fileName, string userName, SecureString password, string domain ) {
            ProcessStartInfo startInfo = new ProcessStartInfo(fileName);            
            startInfo.UserName = userName;
            startInfo.Password = password;
            startInfo.Domain = domain;
            startInfo.UseShellExecute = false;
            return Start(startInfo);
        }
        
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static Process Start( string fileName, string arguments, string userName, SecureString password, string domain ) {
            ProcessStartInfo startInfo = new ProcessStartInfo(fileName, arguments);                        
            startInfo.UserName = userName;
            startInfo.Password = password;
            startInfo.Domain = domain;
            startInfo.UseShellExecute = false;            
            return Start(startInfo);            
        }
 
 
#endif // !FEATURE_PAL
 
        /// <devdoc>
        ///    <para>
        ///       Starts a process resource by specifying the name of a
        ///       document or application file. Associates the process resource with a new <see cref='System.Diagnostics.Process'/>
        ///       component.
        ///    </para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static Process Start(string fileName) {
            return Start(new ProcessStartInfo(fileName));
        }
 
        /// <devdoc>
        ///    <para>
        ///       Starts a process resource by specifying the name of an
        ///       application and a set of command line arguments. Associates the process resource
        ///       with a new <see cref='System.Diagnostics.Process'/>
        ///       component.
        ///    </para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static Process Start(string fileName, string arguments) {
            return Start(new ProcessStartInfo(fileName, arguments));
        }
 
        /// <devdoc>
        ///    <para>
        ///       Starts a process resource specified by the process start
        ///       information passed in, for example the file name of the process to start.
        ///       Associates the process resource with a new <see cref='System.Diagnostics.Process'/>
        ///       component.
        ///    </para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static Process Start(ProcessStartInfo startInfo) {
            Process process = new Process();
            if (startInfo == null) throw new ArgumentNullException("startInfo");
            process.StartInfo = startInfo;
            if (process.Start()) {
                return process;
            }
            return null;
        }
 
        /// <devdoc>
        ///    <para>
        ///       Stops the
        ///       associated process immediately.
        ///    </para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public void Kill() {
            SafeProcessHandle handle = null;
            try {
                handle = GetProcessHandle(NativeMethods.PROCESS_TERMINATE);
                if (!NativeMethods.TerminateProcess(handle, -1))
                    throw new Win32Exception();
            }
            finally {
                ReleaseProcessHandle(handle);
            }
        }
 
        /// <devdoc>
        ///     Make sure we are not watching for process exit.
        /// </devdoc>
        /// <internalonly/>
        void StopWatchingForExit() {
            if (watchingForExit) {
                lock (this) {
                    if (watchingForExit) {
                        watchingForExit = false;
                        registeredWaitHandle.Unregister(null);
                        waitHandle.Close();
                        waitHandle = null;
                        registeredWaitHandle = null;
                    }
                }
            }
        }
 
        public override string ToString() {
#if !FEATURE_PAL        
            if (Associated) {
                string processName  =  String.Empty;  
                //
                // On windows 9x, we can't map a handle to an id.
                // So ProcessName will throw. We shouldn't throw in Process.ToString though.
                // Process.GetProcesses should be used to get all the processes on the machine.
                // The processes returned from it will have a nice name.
                //
                try {
                    processName = this.ProcessName;
                }    
                catch(PlatformNotSupportedException) {
                }
                if( processName.Length != 0) { 
                    return String.Format(CultureInfo.CurrentCulture, "{0} ({1})", base.ToString(), processName);
                }
                return base.ToString();
            }    
            else
#endif // !FEATURE_PAL                
                return base.ToString();
        }
 
        /// <devdoc>
        ///    <para>
        ///       Instructs the <see cref='System.Diagnostics.Process'/> component to wait the specified number of milliseconds for the associated process to exit.
        ///    </para>
        /// </devdoc>
        public bool WaitForExit(int milliseconds) {
            SafeProcessHandle handle = null;
	     bool exited;
            ProcessWaitHandle processWaitHandle = null;
            try {
                handle = GetProcessHandle(NativeMethods.SYNCHRONIZE, false);                
                if (handle.IsInvalid) {
                    exited = true;
                }
                else {
                    processWaitHandle = new ProcessWaitHandle(handle);
                    if( processWaitHandle.WaitOne(milliseconds, false)) {
                        exited = true;
                        signaled = true;
                    }
                    else {
                        exited = false;
                        signaled = false;
                    }
                }
            }
            finally {
                if( processWaitHandle != null) {
                    processWaitHandle.Close();
                }
 
                // If we have a hard timeout, we cannot wait for the streams
                if( output != null && milliseconds == -1) {
                    output.WaitUtilEOF();
                }
 
                if( error != null && milliseconds == -1) {
                    error.WaitUtilEOF();
                }
 
                ReleaseProcessHandle(handle);
 
            }
            
            if (exited && watchForExit) {
                RaiseOnExited();
            }
			
            return exited;
        }
 
        /// <devdoc>
        ///    <para>
        ///       Instructs the <see cref='System.Diagnostics.Process'/> component to wait
        ///       indefinitely for the associated process to exit.
        ///    </para>
        /// </devdoc>
        public void WaitForExit() {
            WaitForExit(-1);
        }
 
#if !FEATURE_PAL        
 
        /// <devdoc>
        ///    <para>
        ///       Causes the <see cref='System.Diagnostics.Process'/> component to wait the
        ///       specified number of milliseconds for the associated process to enter an
        ///       idle state.
        ///       This is only applicable for processes with a user interface,
        ///       therefore a message loop.
        ///    </para>
        /// </devdoc>
        public bool WaitForInputIdle(int milliseconds) {
            SafeProcessHandle handle = null;
            bool idle;
            try {
                handle = GetProcessHandle(NativeMethods.SYNCHRONIZE | NativeMethods.PROCESS_QUERY_INFORMATION);
                int ret = NativeMethods.WaitForInputIdle(handle, milliseconds);
                switch (ret) {
                    case NativeMethods.WAIT_OBJECT_0:
                        idle = true;
                        break;
                    case NativeMethods.WAIT_TIMEOUT:
                        idle = false;
                        break;
                    case NativeMethods.WAIT_FAILED:
                    default:
                        throw new InvalidOperationException(SR.GetString(SR.InputIdleUnkownError));
                }
            }
            finally {
                ReleaseProcessHandle(handle);
            }
            return idle;
        }
 
        /// <devdoc>
        ///    <para>
        ///       Instructs the <see cref='System.Diagnostics.Process'/> component to wait
        ///       indefinitely for the associated process to enter an idle state. This
        ///       is only applicable for processes with a user interface, therefore a message loop.
        ///    </para>
        /// </devdoc>
        public bool WaitForInputIdle() {
            return WaitForInputIdle(Int32.MaxValue);
        }
 
#endif // !FEATURE_PAL        
 
        // Support for working asynchronously with streams
        /// <devdoc>
        /// <para>
        /// Instructs the <see cref='System.Diagnostics.Process'/> component to start
        /// reading the StandardOutput stream asynchronously. The user can register a callback
        /// 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
        /// then the remaining information is returned. The user can add an event handler to OutputDataReceived.
        /// </para>
        /// </devdoc>
        [System.Runtime.InteropServices.ComVisible(false)]        
        public void BeginOutputReadLine() {
 
            if(outputStreamReadMode == StreamReadMode.undefined) {
                outputStreamReadMode = StreamReadMode.asyncMode;
            }
            else if (outputStreamReadMode != StreamReadMode.asyncMode) {
                throw new InvalidOperationException(SR.GetString(SR.CantMixSyncAsyncOperation));                    
            }
            
            if (pendingOutputRead)
                throw new InvalidOperationException(SR.GetString(SR.PendingAsyncOperation));
 
            pendingOutputRead = true;
            // We can't detect if there's a pending sychronous read, tream also doesn't.
            if (output == null) {
                if (standardOutput == null) {
                    throw new InvalidOperationException(SR.GetString(SR.CantGetStandardOut));
                }
 
                Stream s = standardOutput.BaseStream;
                output = new AsyncStreamReader(this, s, new UserCallBack(this.OutputReadNotifyUser), standardOutput.CurrentEncoding);
            }
            output.BeginReadLine();
        }
 
 
        /// <devdoc>
        /// <para>
        /// Instructs the <see cref='System.Diagnostics.Process'/> component to start
        /// reading the StandardError stream asynchronously. The user can register a callback
        /// 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
        /// then the remaining information is returned. The user can add an event handler to ErrorDataReceived.
        /// </para>
        /// </devdoc>
        [System.Runtime.InteropServices.ComVisible(false)]        
        public void BeginErrorReadLine() {
 
            if(errorStreamReadMode == StreamReadMode.undefined) {
                errorStreamReadMode = StreamReadMode.asyncMode;
            }
            else if (errorStreamReadMode != StreamReadMode.asyncMode) {
                throw new InvalidOperationException(SR.GetString(SR.CantMixSyncAsyncOperation));                    
            }
            
            if (pendingErrorRead) {
                throw new InvalidOperationException(SR.GetString(SR.PendingAsyncOperation));
            }
 
            pendingErrorRead = true;
            // We can't detect if there's a pending sychronous read, stream also doesn't.
            if (error == null) {
                if (standardError == null) {
                    throw new InvalidOperationException(SR.GetString(SR.CantGetStandardError));
                }
 
                Stream s = standardError.BaseStream;
                error = new AsyncStreamReader(this, s, new UserCallBack(this.ErrorReadNotifyUser), standardError.CurrentEncoding);
            }
            error.BeginReadLine();
        }
 
        /// <devdoc>
        /// <para>
        /// Instructs the <see cref='System.Diagnostics.Process'/> component to cancel the asynchronous operation
        /// specified by BeginOutputReadLine().
        /// </para>
        /// </devdoc>
        [System.Runtime.InteropServices.ComVisible(false)]
        public void CancelOutputRead() {        
            if (output != null) {
                output.CancelOperation();
            }
            else {
                throw new InvalidOperationException(SR.GetString(SR.NoAsyncOperation));
            }
 
            pendingOutputRead = false;
        }
 
        /// <devdoc>
        /// <para>
        /// Instructs the <see cref='System.Diagnostics.Process'/> component to cancel the asynchronous operation
        /// specified by BeginErrorReadLine().
        /// </para>
        /// </devdoc>
        [System.Runtime.InteropServices.ComVisible(false)]        
        public void CancelErrorRead() {
            if (error != null) {
                error.CancelOperation();
            }
            else {
                throw new InvalidOperationException(SR.GetString(SR.NoAsyncOperation));
            }
 
            pendingErrorRead = false;
        }
 
        internal void OutputReadNotifyUser(String data) {
            // To avoid ---- between remove handler and raising the event
            DataReceivedEventHandler outputDataReceived = OutputDataReceived;
            if (outputDataReceived != null) {
                DataReceivedEventArgs e = new DataReceivedEventArgs(data);
                if (SynchronizingObject != null && SynchronizingObject.InvokeRequired) {
                    SynchronizingObject.Invoke(outputDataReceived, new object[] {this, e});
                }
                else {
                    outputDataReceived(this,e);  // Call back to user informing data is available.
                }
            }
        }
 
        internal void ErrorReadNotifyUser(String data) {
            // To avoid ---- between remove handler and raising the event
            DataReceivedEventHandler errorDataReceived = ErrorDataReceived;
            if (errorDataReceived != null) {
                DataReceivedEventArgs e = new DataReceivedEventArgs(data);
                if (SynchronizingObject != null && SynchronizingObject.InvokeRequired) {
                    SynchronizingObject.Invoke(errorDataReceived, new object[] {this, e});
                }
                else {
                    errorDataReceived(this,e); // Call back to user informing data is available.
                }
            }
        }
 
        /// <summary>
        ///     A desired internal state.
        /// </summary>
        /// <internalonly/>
        enum State {
            HaveId = 0x1,
            IsLocal = 0x2,
            IsNt = 0x4,
            HaveProcessInfo = 0x8,
            Exited = 0x10,
            Associated = 0x20,
            IsWin2k = 0x40,
            HaveNtProcessInfo = HaveProcessInfo | IsNt
        }
    }
 
    /// <devdoc>
    ///     This data structure contains information about a process that is collected
    ///     in bulk by querying the operating system.  The reason to make this a separate
    ///     structure from the process component is so that we can throw it away all at once
    ///     when Refresh is called on the component.
    /// </devdoc>
    /// <internalonly/>
    internal class ProcessInfo {
        public ArrayList threadInfoList = new ArrayList();
        public int basePriority;
        public string processName;
        public int processId;
        public int handleCount;
        public long poolPagedBytes;
        public long poolNonpagedBytes;
        public long virtualBytes;
        public long virtualBytesPeak;
        public long workingSetPeak;
        public long workingSet;
        public long pageFileBytesPeak;
        public long pageFileBytes;
        public long privateBytes;
        public int mainModuleId; // used only for win9x - id is only for use with CreateToolHelp32
        public int sessionId; 
    }
 
    /// <devdoc>
    ///     This data structure contains information about a thread in a process that
    ///     is collected in bulk by querying the operating system.  The reason to
    ///     make this a separate structure from the ProcessThread component is so that we
    ///     can throw it away all at once when Refresh is called on the component.
    /// </devdoc>
    /// <internalonly/>
    internal class ThreadInfo {
        public int threadId;
        public int processId;
        public int basePriority;
        public int currentPriority;
        public IntPtr startAddress;
        public ThreadState threadState;
#if !FEATURE_PAL        
        public ThreadWaitReason threadWaitReason;
#endif // !FEATURE_PAL
    }
 
    /// <devdoc>
    ///     This data structure contains information about a module in a process that
    ///     is collected in bulk by querying the operating system.  The reason to
    ///     make this a separate structure from the ProcessModule component is so that we
    ///     can throw it away all at once when Refresh is called on the component.
    /// </devdoc>
    /// <internalonly/>
    internal class ModuleInfo {
        public string baseName;
        public string fileName;
        public IntPtr baseOfDll;
        public IntPtr entryPoint;
        public int sizeOfImage;
        public int Id; // used only on win9x - for matching up with ProcessInfo.mainModuleId
    }
 
    internal static class EnvironmentBlock {
        public static byte[] ToByteArray(StringDictionary sd, bool unicode) {
            // get the keys
            string[] keys = new string[sd.Count];
            byte[] envBlock = null;
            sd.Keys.CopyTo(keys, 0);
            
            // get the values
            string[] values = new string[sd.Count];
            sd.Values.CopyTo(values, 0);
            
            // sort both by the keys
            // Windows 2000 requires the environment block to be sorted by the key
            // It will first converting the case the strings and do ordinal comparison.
            Array.Sort(keys, values, OrdinalCaseInsensitiveComparer.Default);
 
            // create a list of null terminated "key=val" strings
            StringBuilder stringBuff = new StringBuilder();
            for (int i = 0; i < sd.Count; ++ i) {
                stringBuff.Append(keys[i]);
                stringBuff.Append('=');
                stringBuff.Append(values[i]);
                stringBuff.Append('\0');
            }
            // an extra null at the end indicates end of list.
            stringBuff.Append('\0');
                        
            if( unicode) {
                envBlock = Encoding.Unicode.GetBytes(stringBuff.ToString());                        
            }
            else {
                envBlock = Encoding.Default.GetBytes(stringBuff.ToString());
 
                if (envBlock.Length > UInt16.MaxValue)
                    throw new InvalidOperationException(SR.GetString(SR.EnvironmentBlockTooLong, envBlock.Length));
            }
 
            return envBlock;
        }        
    }
 
    internal class OrdinalCaseInsensitiveComparer : IComparer {
        internal static readonly OrdinalCaseInsensitiveComparer Default = new OrdinalCaseInsensitiveComparer();
        
        public int Compare(Object a, Object b) {
            String sa = a as String;
            String sb = b as String;
            if (sa != null && sb != null) {
                return String.Compare(sa, sb, StringComparison.OrdinalIgnoreCase); 
            }
            return Comparer.Default.Compare(a,b);
        }
    }
 
    internal class ProcessThreadTimes {
        internal long create;
        internal long exit; 
        internal long kernel; 
        internal long user;
 
        public DateTime StartTime {   
            get {             
                return DateTime.FromFileTime(create);
            }
        }
 
        public DateTime ExitTime {
            get {
                return DateTime.FromFileTime(exit);
            }
        }
 
        public TimeSpan PrivilegedProcessorTime {
            get {
                return new TimeSpan(kernel);
            }
        }
 
        public TimeSpan UserProcessorTime {
            get {
                return new TimeSpan(user);
            }
        }
        
        public TimeSpan TotalProcessorTime {
            get {
                return new TimeSpan(user + kernel);
            }
        }
    }
 
    internal class ShellExecuteHelper {
        private NativeMethods.ShellExecuteInfo _executeInfo;
        private int _errorCode;
        private bool _succeeded;
        
        public ShellExecuteHelper(NativeMethods.ShellExecuteInfo executeInfo) {
            _executeInfo = executeInfo;            
        }
 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        public void ShellExecuteFunction()    {
            if (!(_succeeded = NativeMethods.ShellExecuteEx(_executeInfo))) {
                _errorCode = Marshal.GetLastWin32Error();
            }
        }
 
        public bool ShellExecuteOnSTAThread() {
            //
            // SHELL API ShellExecute() requires STA in order to work correctly.
            // If current thread is not a STA thread, we need to call ShellExecute on a new thread.
            //
            if( Thread.CurrentThread.GetApartmentState() != ApartmentState.STA) {
                ThreadStart threadStart = new ThreadStart(this.ShellExecuteFunction);
                Thread executionThread = new Thread(threadStart);
                executionThread.SetApartmentState(ApartmentState.STA);    
                executionThread.Start();
                executionThread.Join();
            }    
            else {
                ShellExecuteFunction();
            }
            return _succeeded;
        }        
 
        public int ErrorCode {
            get { 
                return _errorCode; 
            }
        }
    }
}