自定义插入没有在c#中初始化时设置

时间:2016-04-01 07:56:58

标签: c# richtextbox caret

我(痛苦地)编写了一个稳定的控制台控件,但是在启动对象时遇到一个很小的问题,Caret没有设置为我的自定义控件,直到我在窗体上的控件内部单击或按下一个键键盘。我可以看到我已成功聚焦作为默认(非常微弱的线条)Caret显示闪烁没有任何问题,即使我不断尝试摧毁小虫子。 (抱歉收缩了一些代码。限制为30,000个字符)

这是我的源代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;

public partial class Console : RichTextBox {
    public Console() {
        InitializeComponent();
        this.ShowDebug=false;
        this.ShowErrors=true;
        process=new Process();
        this.WorkingDirectory=Environment.GetFolderPath( Environment.SpecialFolder.MyDocuments );
        this.stripCommand="";
        startinfo=new ProcessStartInfo() {
            RedirectStandardError=true,
            RedirectStandardInput=true,
            RedirectStandardOutput=true,
            StandardErrorEncoding=System.Text.Encoding.GetEncoding( 437 ),
            StandardOutputEncoding=System.Text.Encoding.GetEncoding( 437 ),
            UseShellExecute=false,
            ErrorDialog=false,
            CreateNoWindow=true,
            WorkingDirectory=this.WorkingDirectory
            //WindowStyle=System.Diagnostics.ProcessWindowStyle.Normal
        };
        this.inputStart=0;
        base.BackColor=Color.DimGray;
        base.ForeColor=Color.GhostWhite;
        base.AcceptsTab=true;
        base.ReadOnly=true;
        this.AllowCommands = true;
        this.CaretVisible = true;
        base.Anchor=AnchorStyles.Bottom|AnchorStyles.Left|AnchorStyles.Right|AnchorStyles.Top;
        base.Font=new Font( "Lucida Console", (float)11.25 );
        using ( Graphics g=base.CreateGraphics() ) {
            base.Size=new Size( Convert.ToInt32( g.MeasureString( "A", base.Font ).Width*80 ), Convert.ToInt32( g.MeasureString( "A", base.Font ).Height*25 ) );
        }
        this.ErrorColor=Color.LightPink;
        this.DebugColor=Color.Yellow;

        //  Configure the output worker.
        outputWorker.WorkerReportsProgress=true;
        outputWorker.WorkerSupportsCancellation=true;
        outputWorker.DoWork+=outputWorker_DoWork;
        outputWorker.ProgressChanged+=outputWorker_ProgressChanged;
        outputWorker.RunWorkerCompleted+=outputWorker_RunWorkerCompleted;

        //  Configure the error worker.
        errorWorker.WorkerReportsProgress=true;
        errorWorker.WorkerSupportsCancellation=true;
        errorWorker.DoWork+=errorWorker_DoWork;
        errorWorker.ProgressChanged+=errorWorker_ProgressChanged;
        errorWorker.RunWorkerCompleted+=errorWorker_RunWorkerCompleted;

        //  Map 'tab'.
        keyMappings.Add( new KeyMapping( false, false, false, Keys.Tab, "{TAB}", "\t" ) );

        //  Map 'Ctrl-C'.
        keyMappings.Add( new KeyMapping( true, false, false, Keys.C, "^(c)", "\x03\r\n" ) );

    }

    #region methods
    /// <summary>
    /// Change the output encoding
    /// </summary>
    /// <param name="encoding"><see cref="System.Text.Encoding"/></param>
    public void SetOutputEncoding( System.Text.Encoding encoding ) {
        if ( Running&&ShowDebug ) {
            Write( "Encoding change will take effect when restarting the process", DebugColor );
        }
        startinfo.StandardErrorEncoding=encoding;
        startinfo.StandardOutputEncoding=encoding;
    }

    public async void SendCommand( string value ) {
        if ( Running==false&&ShowErrors ) {
            Write( startinfo.FileName+"` is not running. Command `"+value+"` failed", DebugColor );
            return;
        }
        stripCommand=value;
        await inputWriter.WriteLineAsync( value );
        inputWriter.Flush();
    }

    public void Write( string value, Color color ) {
        // Ensure that text is purged from the top of the textbox
        // if the amount of text in the box is approaching the
        // MaxLength property of the control
        if ( base.Text.Length+value.Length>base.MaxLength ) {
            int cr=base.Text.IndexOf( "\r\n" );
            if ( cr>0 ) {
                base.Select( 0, cr+1 );
                base.SelectedText=string.Empty;
            } else {
                base.Select( 0, value.Length );
            }
        }

        string v="";
        base.SelectionColor=color;
        if ( color==ErrorColor ) {
            v="- ERROR: ";
        } else if ( color==DebugColor ) {
            v="- DEBUG: ";
        }
        if ( v.Length>0 ) {
            if ( value.Trim()=="" ) { return; }
            if ( base.Text.EndsWith( "\r\n" )==false&&base.Text.EndsWith( "\n" )==false&&base.Text.Length>0 ) { v="\n"+v; }
            base.SelectionFont=new Font( base.Font.FontFamily, base.Font.Size, FontStyle.Bold );
            base.SelectedText+=v;
            base.SelectionFont=new Font( base.Font.FontFamily, base.Font.Size, FontStyle.Regular );
            value+="\n";
        }

        base.SelectedText+=value;
        inputStart=base.SelectionStart;
        base.SelectionStart=base.Text.Length+1;
        base.ScrollToCaret();
        base.SelectionStart=base.Text.Length+1;
        if ( AllowCommands==true ) {
            DrawCaret();
            if ( this.Focused==false ) {
                this.Focus();
            }
        }
    }

    /// <summary>
    /// Start a process
    /// </summary>
    /// <param name="command">The command to run ( example:  "cmd.exe" )</param>
    /// <param name="arguments">Any arguments you wish to pass with the command</param>
    public void Start( string command, string arguments="" ) {
        if ( Running&&ShowDebug ) {
            Write( "A process is already running."+startinfo.FileName+"` started", ErrorColor );
            return;
        }
        if ( ThreadsStillRunning&&ShowDebug ) {
            Write( "The process has ended, but threads are still pending cancellation. Try again in a few moments", ErrorColor );
            return;
        }

        startinfo.WorkingDirectory = this.WorkingDirectory;
        startinfo.Arguments=arguments;
        startinfo.FileName=command;
        process=new Process {
            StartInfo=startinfo
        };
        process.EnableRaisingEvents=true;
        process.Exited+=process_Exited;
        //  Start the process.
        try {
            base.SelectionStart = base.TextLength;
            process.Start();
            DestroyCaret();
            if ( AllowCommands ) {
                base.ReadOnly = false;
                DrawCaret();
                if ( this.Focused==false ) {
                    this.Focus();
                }
            }
            if ( base.Text.Length>0&&base.Text.EndsWith( "\n" )==false ) {
                base.AppendText("\n");
                base.SelectionStart=base.TextLength;
            }
            if ( Running&&ShowDebug ) {
                Write( startinfo.FileName+"` started", DebugColor );
            }
        } catch ( Exception e ) {
            //  Trace the exception.
            string error=( arguments=="" )?"Failed to start process "+command:"Failed to start process "+command+" with arguments '"+arguments+"'";
            Trace.WriteLine( "ERROR: "+error );
            Trace.WriteLine( e.ToString() );
            if ( ShowErrors ) {
                Write( error, ErrorColor );
            }
            return;
        }

        //  Create the readers and writers.
        inputWriter=process.StandardInput;
        outputReader=TextReader.Synchronized( process.StandardOutput );
        errorReader=TextReader.Synchronized( process.StandardError );

        //  Run the workers that read output and error.
        if ( outputWorker.IsBusy==false ) { outputWorker.RunWorkerAsync(); }
        if ( errorWorker.IsBusy==false ) { errorWorker.RunWorkerAsync(); }

    }

    /// <summary>
    /// Stop the current process
    /// </summary>
    public void Stop() {
        if ( ShowDebug ) {
            Write( "Requesting termination of command", DebugColor );
        }

        //  Handle the trivial case.
        if ( Running==false ) {
            if ( ShowErrors ) {
                Write( "Process is not running. Terminate failed.", DebugColor );
            }
            return;

        }

        //  Kill the process.
        process.Kill();
        process.WaitForExit();
    }
    #endregion
    #region settings
    /// <summary>
    /// Set the console background color
    /// </summary>
    [DefaultValue( typeof( Color ), "DimGray" )]
    public override Color BackColor {
        get {
            return base.BackColor;
        }
        set {
            base.BackColor=value;
        }
    }

    /// <summary>
    /// Set the console font color
    /// </summary>
    [DefaultValue( typeof( Color ), "GhostWhite" )]
    public override Color ForeColor {
        get {
            return base.ForeColor;
        }
        set {
            base.ForeColor=value;
        }
    }

    /// <summary>
    /// Toggle visibility of debug messages
    /// </summary>
    [DefaultValue( false )]
    public bool ShowDebug { get; set; }

    /// <summary>
    /// Toggle visibility of error messages
    /// </summary>
    [DefaultValue( true )]
    public bool ShowErrors { get; set; }

    /// <summary>
    /// Send commands from the console to be processed. ( Does not impact SendCommand() )
    /// </summary>
    [DefaultValue( true )]
    public bool AllowCommands {
        get { return pAllowCommands; }
        set {
            pAllowCommands=value;
            if ( value==false ) {
                DestroyCaret();
            }
        }
    }
    private bool pAllowCommands;

    /// <summary>
    /// Set the color for debug messages
    /// </summary>
    [DefaultValue( typeof( Color ), "Yellow" )]
    public Color DebugColor { get; set; }

    /// <summary>
    /// Set the color for error messages
    /// </summary>
    [DefaultValue( typeof( Color ), "LightPink" )]
    public Color ErrorColor { get; set; }

    /// <summary>
    /// Returns true if process is running
    /// </summary>
    public bool Running {
        get {
            try {
                return ( process!=null&&process.HasExited==false );
            } catch {
                return false;
            }
        }
    }

    /// <summary>
    /// Returns if stream threads are still running
    /// </summary>
    public bool ThreadsStillRunning {
        get {
            if ( errorWorker.IsBusy||outputWorker.IsBusy ) {
                return true;
            } else {
                return false;
            }
        }
    }

    /// <summary>
    /// Working directory to use for startup
    /// </summary>
    public string WorkingDirectory { get; set; }
    #endregion
    #region carat
    [DllImport( "user32.dll", CharSet=CharSet.Auto )]
    private extern static void CreateCaret( IntPtr hWnd, IntPtr hBitmap, int nWidth, int nHeight );

    [DllImport( "user32.dll", CharSet=CharSet.Auto )]
    private extern static void ShowCaret( IntPtr hWnd );

    [DllImport( "user32.dll" )]
    static extern bool DestroyCaret();

    [DllImport( "user32.dll" )]
    static extern bool SetCaretPos( int X, int Y );

    [DllImport( "user32.dll" )]
    static extern bool HideCaret( IntPtr hWnd );

    protected override void OnKeyUp( KeyEventArgs e ) {
        DrawCaret();
        base.OnKeyUp( e );
    }

    /// <summary>
    /// Set the Caret color (not implemented yet)
    /// </summary>
    public Color CaretColor { get; set; }

    /// <summary>
    /// Set the Caret size (not implemented yet)
    /// </summary>
    public Size CaretSize { get; set; }

    /// <summary>
    /// Define if the Caret should be visible or not
    /// </summary>
    [DefaultValue( true )]
    public bool CaretVisible { get; set; }

    /// <summary>
    /// Draw the caret
    /// </summary>
    internal void DrawCaret() {
        if ( base.ReadOnly==true||AllowCommands==false||CaretVisible==false ) { DestroyCaret(); return; }
        int nHeight=0;
        int nWidth=5;
        bool mInsertKeyState=false;

        if ( this.SelectionFont!=null ) {
            nHeight=Convert.ToInt32( base.SelectionFont.Height*base.ZoomFactor );
        } else {
            nHeight=Convert.ToInt32( ( base.Font.Height*base.ZoomFactor/3 ) );
        }

        if ( !mInsertKeyState&&base.SelectionStart<base.TextLength ) {
            Point p1=base.GetPositionFromCharIndex( base.SelectionStart );
            Point p2=base.GetPositionFromCharIndex( base.SelectionStart+1 );

            nWidth=p2.X-p1.X;
        }

        Color invertedCaretColor=Color.FromArgb( CaretColor.ToArgb()^0xffffff );

        if ( nWidth>0&&nHeight>0 ) {
            using ( Bitmap bmp=new Bitmap( nWidth, nHeight ) ) {
                using ( Graphics gfx=Graphics.FromImage( bmp ) ) {
                    nWidth=Convert.ToInt32( gfx.MeasureString( "Z", base.Font ).Width*.66 );
                    //nHeight=Convert.ToInt32( gfx.MeasureString( "Z", base.Font ).Height / 3 );
                    using ( SolidBrush brush=new SolidBrush( invertedCaretColor ) ) {
                        gfx.FillRectangle( brush, 1, 1, nWidth, nHeight );
                        using ( Bitmap bmp2=new Bitmap( nWidth, nHeight, gfx ) ) {
                            CreateCaret( base.Handle, bmp2.GetHbitmap(), nWidth, nHeight );
                            ShowCaret( base.Handle );
                        }
                    }
                }
            }
        }

    }

    /// <summary>
    /// internal method to wait for thread to exit
    /// </summary>
    /// <returns></returns>
    private async Task<bool> waitOnThreadExit() {
        await System.Threading.Tasks.Task.Run( () => {
            while ( ThreadsStillRunning==true ) {
                System.Threading.Thread.Sleep( 500 );
            }
        } );
        return true;
    }

    #endregion
    #region userprocessing
    /// <summary>
    /// Handle when this object recieves focus
    /// </summary>
    /// <param name="e"></param>
    protected override void OnGotFocus( EventArgs e ) {
        if ( AllowCommands==true ) {
            base.SelectionStart=base.TextLength;
            DrawCaret();
        } else {
            DestroyCaret();
        }
        base.OnGotFocus( e );
    }

    /// <summary>
    /// Handle keypress (keydown) event
    /// </summary>
    /// <param name="e"></param>
    protected override void OnKeyDown( KeyEventArgs e ) {
        if ( base.ReadOnly ) {
            e.SuppressKeyPress=true;
            base.OnKeyDown( e );
            return;
        }
        if ( AllowCommands&&Running&&base.ReadOnly==false ) {
            //  Get key mappings for this key event?
            var mappings=from k in keyMappings
                         where
                         ( k.KeyCode==e.KeyCode&&
                         k.IsAltPressed==e.Alt&&
                         k.IsControlPressed==e.Control&&
                         k.IsShiftPressed==e.Shift )
                         select k;

            //  Go through each mapping, send the message.
            foreach ( var mapping in mappings ) {
                //SendKeysEx.SendKeys(CurrentProcessHwnd, mapping.SendKeysMapping);
                //inputWriter.WriteLine(mapping.StreamMapping);
                //WriteInput("\x3", Color.White, false);
            }

            //  If we handled a mapping, we're done here.
            if ( mappings.Any() ) {
                e.SuppressKeyPress=true;
                base.OnKeyDown( e );
                return;
            }
        }

        //  If we're at the input point and it's backspace, bail.
        if ( ( base.SelectionStart<=inputStart )&&e.KeyCode==Keys.Back )
            e.SuppressKeyPress=true;

        //  Are we in the read-only zone?
        if ( base.SelectionStart<inputStart ) {
            //  Allow arrows and Ctrl-C.
            if ( !( e.KeyCode==Keys.Left||
                e.KeyCode==Keys.Right||
                e.KeyCode==Keys.Up||
                e.KeyCode==Keys.Down||
                ( e.KeyCode==Keys.C&&e.Control ) ) ) {
                e.SuppressKeyPress=true;
            }
        }

        //  Is it the return key?
        if ( e.KeyCode==Keys.Return&&base.ReadOnly==false&&AllowCommands==true ) {
            //  Get the input.
            try {
                string input=base.Text.Substring( inputStart, ( base.SelectionStart )-inputStart );
                stripCommand=input;
                Invoke( (Action)( () => {
                    SendCommand( input );
                } ) );
            } catch ( Exception ex ) {

            } finally {
                DrawCaret();
            }
        } else if ( base.ReadOnly==true||AllowCommands==false ) {
            e.SuppressKeyPress=true;
        }
        base.OnKeyDown( e );
    }


    /// <summary>
    /// handle mouse up event
    /// </summary>
    /// <param name="mevent"></param>
    protected override void OnMouseUp( MouseEventArgs mevent ) {
        if ( AllowCommands==true ) {
            DrawCaret();
        } else {
            DestroyCaret();
        }
        base.OnMouseUp( mevent );
    }

    /// <summary>
    /// store current input start location. used to deny editing of any prior data.
    /// </summary>
    private int inputStart { get; set; }

    /// <summary>
    /// store last command to strip from incoming data so it doesn't end up being displayed twice
    /// </summary>
    private string stripCommand { get; set; }
    public delegate void ConsoleEventHandler( object sender, ConsoleEventArgs args );

    /// <summary>
    /// The ProcessEventArgs are arguments for a console event.
    /// </summary>
    public class ConsoleEventArgs : EventArgs {
        /// <summary>
        /// Initializes a new instance of the <see cref="ProcessEventArgs"/> class.
        /// </summary>
        public ConsoleEventArgs() {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ProcessEventArgs"/> class.
        /// </summary>
        /// <param name="content">The content.</param>
        public ConsoleEventArgs( string content ) {
            //  Set the content and code.
            Content=content;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ProcessEventArgs"/> class.
        /// </summary>
        /// <param name="code">The code.</param>
        public ConsoleEventArgs( int code ) {
            //  Set the content and code.
            Code=code;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ProcessEventArgs"/> class.
        /// </summary>
        /// <param name="content">The content.</param>
        /// <param name="code">The code.</param>
        public ConsoleEventArgs( string content, int code ) {
            //  Set the content and code.
            Content=content;
            Code=code;
        }

        /// <summary>
        /// Gets the content.
        /// </summary>
        public string Content { get; private set; }

        /// <summary>
        /// Gets or sets the code.
        /// </summary>
        /// <value>
        /// The code.
        /// </value>
        public int? Code { get; private set; }
    }

    /// <summary>
    /// The type of signal to be generated.
    /// </summary>
    internal enum CTRL_EVENT : uint {
        /// <summary>
        /// Generates a CTRL+C signal. This signal cannot be generated for process groups. If dwProcessGroupId is nonzero, this function will succeed, but the CTRL+C signal will not be received by processes within the specified process group.
        /// </summary>
        CTRL_C_EVENT=0,

        /// <summary>
        /// Generates a CTRL+BREAK signal.
        /// </summary>
        CTRL_BREAK_EVENT=1
    }

    /// <summary>
    /// The key mappings.
    /// </summary>
    private List<KeyMapping> keyMappings=new List<KeyMapping>();

    /// <summary>
    /// Keyboard handling imports
    /// </summary>
    internal static class Imports {
        /// <summary>
        /// Sends a specified signal to a console process group that shares the console associated with the calling process.
        /// </summary>
        /// <param name="dwCtrlEvent">The type of signal to be generated.</param>
        /// <param name="dwProcessGroupId">The identifier of the process group to receive the signal. A process group is created when the CREATE_NEW_PROCESS_GROUP flag is specified in a call to the CreateProcess function. The process identifier of the new process is also the process group identifier of a new process group. The process group includes all processes that are descendants of the root process. Only those processes in the group that share the same console as the calling process receive the signal. In other words, if a process in the group creates a new console, that process does not receive the signal, nor do its descendants.
        /// If this parameter is zero, the signal is generated in all processes that share the console of the calling process.</param>
        /// <returns>If the function succeeds, the return value is nonzero.
        /// If the function fails, the return value is zero. To get extended error information, call GetLastError.</returns>
        [DllImport( "Kernel32.dll" )]
        public static extern bool GenerateConsoleCtrlEvent( CTRL_EVENT dwCtrlEvent, UInt32 dwProcessGroupId );
    }

    // Internal KeyMapping Class
    /// <summary>
    /// A KeyMapping defines how a key combination should
    /// be mapped to a SendKeys message.
    /// </summary>
    internal class KeyMapping {
        /// <summary>
        /// Initializes a new instance of the <see cref="KeyMapping"/> class.
        /// </summary>
        public KeyMapping() {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="KeyMapping"/> class.
        /// </summary>
        /// <param name="control">if set to <c>true</c> [control].</param>
        /// <param name="alt">if set to <c>true</c> [alt].</param>
        /// <param name="shift">if set to <c>true</c> [shift].</param>
        /// <param name="keyCode">The key code.</param>
        /// <param name="sendKeysMapping">The send keys mapping.</param>
        /// <param name="streamMapping">The stream mapping.</param>
        public KeyMapping( bool control, bool alt, bool shift, Keys keyCode, string sendKeysMapping, string streamMapping ) {
            //  Set the member variables.
            IsControlPressed=control;
            IsAltPressed=alt;
            IsShiftPressed=shift;
            KeyCode=keyCode;
            SendKeysMapping=sendKeysMapping;
            StreamMapping=streamMapping;
        }

        /// <summary>
        /// Gets or sets a value indicating whether this instance is control pressed.
        /// </summary>
        /// <value>
        ///     <c>true</c> if this instance is control pressed; otherwise, <c>false</c>.
        /// </value>
        public bool IsControlPressed {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets a value indicating whether alt is pressed.
        /// </summary>
        /// <value>
        ///     <c>true</c> if this instance is alt pressed; otherwise, <c>false</c>.
        /// </value>
        public bool IsAltPressed {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets a value indicating whether this instance is shift pressed.
        /// </summary>
        /// <value>
        ///     <c>true</c> if this instance is shift pressed; otherwise, <c>false</c>.
        /// </value>
        public bool IsShiftPressed {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the key code.
        /// </summary>
        /// <value>
        /// The key code.
        /// </value>
        public Keys KeyCode {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the send keys mapping.
        /// </summary>
        /// <value>
        /// The send keys mapping.
        /// </value>
        public string SendKeysMapping {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the stream mapping.
        /// </summary>
        /// <value>
        /// The stream mapping.
        /// </value>
        public string StreamMapping {
            get;
            set;
        }
    }
    #endregion




    /***********************************************************************
     *                THREAD HANDLING
     * ********************************************************************/
    #region thread
    /// <summary>
    /// Occurs when process output is produced.
    /// </summary>
    public event ConsoleEventHandler OnProcessOutput;

    /// <summary>
    /// Occurs when process error output is produced.
    /// </summary>
    public event ConsoleEventHandler OnProcessError;

    /// <summary>
    /// Occurs when process input is produced.
    /// </summary>
    public event ConsoleEventHandler OnProcessInput;

    /// <summary>
    /// Occurs when the process ends.
    /// </summary>
    public event ConsoleEventHandler OnProcessExit;

    /// <summary>
    /// The input writer.
    /// </summary>
    private StreamWriter inputWriter;

    /// <summary>
    /// The output reader.
    /// </summary>
    private TextReader outputReader;

    /// <summary>
    /// The error reader.
    /// </summary>
    private TextReader errorReader;

    /// <summary>
    /// The output worker.
    /// </summary>
    private BackgroundWorker outputWorker=new BackgroundWorker();

    /// <summary>
    /// The error worker.
    /// </summary>
    private BackgroundWorker errorWorker=new BackgroundWorker();

    /// <summary>
    /// property to hold System.Diagnostics.Process instance
    /// </summary>
    private Process process { get; set; }

    /// <summary>
    /// property to hold System.Diagnostics.ProcessStartInfo for initializing process
    /// </summary>
    private ProcessStartInfo startinfo { get; set; }

    /// <summary>
    /// Handles the ProgressChanged event of the outputWorker control.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.ComponentModel.ProgressChangedEventArgs"/> instance containing the event data.</param>
    void outputWorker_ProgressChanged( object sender, ProgressChangedEventArgs e ) {
        //  We must be passed a string in the user state.
        if ( e.UserState is string ) {
            //  Fire the output event.
            FireProcessOutputEvent( e.UserState as string );
        }
    }

    /// <summary>
    /// Handles the DoWork event of the outputWorker control.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.ComponentModel.DoWorkEventArgs"/> instance containing the event data.</param>
    void outputWorker_DoWork( object sender, DoWorkEventArgs e ) {
        while ( outputWorker.CancellationPending==false ) {
            //  Any lines to read?
            if ( outputWorker.CancellationPending ) { return; }
            int count;
            var buffer=new char[1024];
            do {
                if ( outputWorker.CancellationPending ) { return; }
                var builder=new StringBuilder();
                count=outputReader.Read( buffer, 0, 1024 );
                builder.Append( buffer, 0, count );
                if ( stripCommand.Length>0 ) {
                    if ( builder.ToString().StartsWith( stripCommand ) ) {
                        builder.Remove( 0, stripCommand.Length );
                        stripCommand="";
                    }
                }
                outputWorker.ReportProgress( 0, builder.ToString() );
            } while ( count>0 );

            System.Threading.Thread.Sleep( 200 );
        }
    }

    /// <summary>
    /// Notification of outputWorker completion
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void outputWorker_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e ) {
        if ( ShowDebug ) {
            Write( "Output Thread Cancellation Completed.", DebugColor );
        }
    }


    /// <summary>
    /// Handles the ProgressChanged event of the errorWorker control.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.ComponentModel.ProgressChangedEventArgs"/> instance containing the event data.</param>
    void errorWorker_ProgressChanged( object sender, ProgressChangedEventArgs e ) {
        //  The userstate must be a string.
        if ( e.UserState is string ) {
            //  Fire the error event.
            FireProcessErrorEvent( e.UserState as string );
        }
    }

    /// <summary>
    /// Notification of errorWorker completion
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void errorWorker_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e ) {
        if ( ShowDebug ) {
            Write( "Error Thread Cancellation Completed.", DebugColor );
        }
    }


    /// <summary>
    /// Handles the DoWork event of the errorWorker control.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.ComponentModel.DoWorkEventArgs"/> instance containing the event data.</param>
    void errorWorker_DoWork( object sender, DoWorkEventArgs e ) {
        while ( errorWorker.CancellationPending==false ) {
            //  Any lines to read?
            int count;
            var buffer=new char[1024];
            do {
                var builder=new StringBuilder();
                count=errorReader.Read( buffer, 0, 1024 );
                builder.Append( buffer, 0, count );
                errorWorker.ReportProgress( 0, builder.ToString() );
            } while ( count>0 );

            System.Threading.Thread.Sleep( 200 );
        }
    }

    /// <summary>
    /// Fires the process output event.
    /// </summary>
    /// <param name="content">The content.</param>
    private void FireProcessOutputEvent( string content ) {
        //  Get the event and fire it.
        var theEvent=OnProcessOutput;
        Write( content, ForeColor );
        if ( theEvent!=null )
            theEvent( this, new ConsoleEventArgs( content ) );
    }

    /// <summary>
    /// Fires the process error output event.
    /// </summary>
    /// <param name="content">The content.</param>
    private void FireProcessErrorEvent( string content ) {
        //  Get the event and fire it.
        var theEvent=OnProcessError;
        if ( ShowErrors ) {
            Write( content, ErrorColor );
        }
        if ( theEvent!=null )
            theEvent( this, new ConsoleEventArgs( content ) );
    }

    /// <summary>
    /// Fires the process input event.
    /// </summary>
    /// <param name="content">The content.</param>
    private void FireProcessInputEvent( string content ) {
        //  Get the event and fire it.
        var theEvent=OnProcessInput;
        if ( theEvent!=null )
            theEvent( this, new ConsoleEventArgs( content ) );
    }

    /// <summary>
    /// Fires the process exit event.
    /// </summary>
    /// <param name="code">The code.</param>
    private void FireProcessExitEvent( int code ) {
        //  Get the event and fire it.
        var theEvent=OnProcessExit;
        if ( ShowDebug ) {
            Invoke( (Action)( () => {
                Write( startinfo.FileName+" terminated", DebugColor );
            } ) );
        }
        if ( theEvent!=null )
            theEvent( this, new ConsoleEventArgs( code ) );
    }

    /// <summary>
    /// Cleanup threads after process has exited.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    async void process_Exited( object sender, EventArgs e ) {
        Invoke( (Action)( () => {
            base.ReadOnly=true;
        } ) );

        try {
            //  Disable the threads.
            outputWorker.CancelAsync();
            errorWorker.CancelAsync();
            await waitOnThreadExit();
        } catch ( Exception ex ) {

        } finally {
            //  Fire process exited.
            FireProcessExitEvent( process.ExitCode );

            //  Disable the threads.
            inputWriter=null;
            outputReader=null;
            errorReader=null;
            process=null;
        }
    }

    #endregion

}

以下是init上问题的图片:

e

应该是这样的:

enter image description here

0 个答案:

没有答案