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 {}
}
}
}