Module : cmd 프로그램을 폼에 삽입하기 - escaco95/Charcoal GitHub Wiki

EmbeddedConsole.cs

2019.09.25

using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Windows.Forms;

namespace Charcoal
{
    public class EmbeddedConsole : UserControl, IDisposable
    {
        private volatile string _executableFileName = "cmd";
        private volatile Process _process = null;
        private volatile bool _isRunning = false;
        private volatile bool _isBusy = false;
        private readonly ConcurrentQueue<string> _messages = new ConcurrentQueue<string>();
        public volatile ConcurrentDictionary<string, string> CommandResults = new ConcurrentDictionary<string, string>();

        public bool IsRunning { get { return _isRunning; } }
        public bool IsStopped { get { return !_isRunning; } }
        public bool IsBusy { get { return _isBusy; } }
        public bool IsIdle { get { return !_isBusy; } }

        private RichTextBox Output;
        private Timer Tick;
        private System.ComponentModel.IContainer components;

        public string ExecutableFileName
        {
            get { return _executableFileName; }
            set
            {
                ThrowExceptionIfRunningOrBusy();
                _executableFileName = value;
            }
        }

        public EmbeddedConsole()
        {
            InitializeComponent();
        }
        public void RunAsync()
        {
            ThrowExceptionIfRunningOrBusy();

            _isBusy = true;

            var procStartInfo =
                new ProcessStartInfo(_executableFileName)
                {
                    RedirectStandardOutput = true,
                    RedirectStandardInput = true,
                    RedirectStandardError = true,
                    UseShellExecute = false,
                    CreateNoWindow = true
                };

            _process = new Process();
            _process.OutputDataReceived += (s, e) => {
                string data = e.Data;
                if (!string.IsNullOrWhiteSpace(data))
                    if(!this.IsDisposed)
                    Invoke(new Action(() => _messages.Enqueue(data)));
            };
            _process.ErrorDataReceived += (s, e) =>
            {
                string data = e.Data;
                if (!string.IsNullOrWhiteSpace(data))
                    if (!this.IsDisposed)
                        Invoke(new Action(() => _messages.Enqueue(data)));
            };
            _process.StartInfo = procStartInfo;

            _process.Start();
            _process.BeginOutputReadLine();
            _process.BeginErrorReadLine();

            _isRunning = true;

            Tick.Enabled = true;

            _isBusy = false;
            if (this.ConsoleStateChanged != null)
                ConsoleStateChanged(this, EventArgs.Empty);
        }
        public void Command(string value)
        {
            if (!_isRunning)
                throw new InvalidOperationException("IsRunning 이 False 입니다.");
            if (_isBusy)
                throw new InvalidOperationException("IsBusy 이 True 입니다.");
            _isBusy = true;
            if (this.ConsoleStateChanged != null)
                ConsoleStateChanged(this, EventArgs.Empty);
            _process.StandardInput.WriteLine(value);
            _process.StandardInput.WriteLine("@echo #Done");
        }
        public void Kill()
        {
            if (!_isRunning)
                throw new InvalidOperationException("IsRunning 이 False 입니다.");
            _process.Kill();
            _process = null;
            _isRunning = false;
            _isBusy = false;
            if (this.ConsoleStateChanged != null)
                ConsoleStateChanged(this, EventArgs.Empty);
        }
        public event EventHandler ConsoleStateChanged;
        private void ThrowExceptionIfRunningOrBusy()
        {
            if (_isRunning)
                throw new InvalidOperationException("IsRunning 이 True 입니다.");
            if (_isBusy)
                throw new InvalidOperationException("IsBusy 이 True 입니다.");
        }
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.Output = new System.Windows.Forms.RichTextBox();
            this.Tick = new System.Windows.Forms.Timer(this.components);
            this.SuspendLayout();
            // 
            // Output
            // 
            this.Output.AcceptsTab = true;
            this.Output.AutoWordSelection = true;
            this.Output.BackColor = System.Drawing.Color.Black;
            this.Output.BorderStyle = System.Windows.Forms.BorderStyle.None;
            this.Output.Dock = System.Windows.Forms.DockStyle.Fill;
            this.Output.ForeColor = System.Drawing.Color.White;
            this.Output.Location = new System.Drawing.Point(0, 0);
            this.Output.Name = "Output";
            this.Output.ReadOnly = true;
            this.Output.Size = new System.Drawing.Size(150, 150);
            this.Output.TabIndex = 0;
            this.Output.Text = "";
            this.Output.WordWrap = false;
            // 
            // Tick
            // 
            this.Tick.Tick += new System.EventHandler(this.Tick_Tick);
            // 
            // EmbeddedConsole
            // 
            this.Controls.Add(this.Output);
            this.Name = "EmbeddedConsole";
            this.ResumeLayout(false);

        }
        protected override void Dispose(bool disposing)
        {
            if (_isRunning)
                _process.Dispose();
            Tick.Dispose();
            Output.Dispose();
            components.Dispose();
            base.Dispose(disposing);
        }

        private void Tick_Tick(object sender, EventArgs e)
        {
            try
            {
                var newOutput = string.Empty;
                var output = false;
                while (_messages.TryDequeue(out newOutput))
                {
                    output = true;
                    if (newOutput.StartsWith("<CMDOUTPUT>"))
                    {
                        string[] outputs = newOutput.Split(' ');
                        if (outputs.Length >= 3)
                        {
                            var param = outputs[2];
                            for(var i = 3; i < outputs.Length; i++)
                                param += $" {outputs[i]}";
                            string tmpout = string.Empty;
                            CommandResults.TryRemove(outputs[1], out tmpout);
                            CommandResults.TryAdd(outputs[1], param);
                        }
                        continue;
                    }
                    if (newOutput.EndsWith("#Done"))
                    {
                        if (_isBusy)
                        {
                            _isBusy = false;
                            if (this.ConsoleStateChanged != null)
                                ConsoleStateChanged(this, EventArgs.Empty);
                        }
                        continue;
                    }
                    newOutput += "\r\n";
                    Output.AppendText(newOutput);
                }
                if (!output)
                    return;
                Output.SelectionStart = Output.TextLength;
                Output.ScrollToCaret();
            }
            catch {}
        }
    }
}
⚠️ **GitHub.com Fallback** ⚠️