An Interactive Console I/O Wrapper/Interceptor in C# - What is the issue?
I was trying to put together an interactive Console interceptor/wrapper in C# over the weekend,开发者_StackOverflow中文版 by re-mixing few code samples I've found in SO and other sites.
With what I've as of now, I'm unable to read back from the console reliably. Any quick pointers?
public class ConsoleInterceptor
{
Process _interProc;
public event Action<string> OutputReceivedEvent;
public ConsoleInterceptor()
{
_interProc = new Process();
_interProc.StartInfo = new ProcessStartInfo("cmd");
InitializeInterpreter();
}
public ConsoleInterceptor(string command)
{
_interProc = new Process();
_interProc.StartInfo = new ProcessStartInfo(command);
InitializeInterpreter();
}
public Process InterProc
{
get
{
return _interProc;
}
}
private void InitializeInterpreter()
{
InterProc.StartInfo.RedirectStandardInput = true;
InterProc.StartInfo.RedirectStandardOutput = true;
InterProc.StartInfo.RedirectStandardError = true;
InterProc.StartInfo.CreateNoWindow = true;
InterProc.StartInfo.UseShellExecute = false;
InterProc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
bool started = InterProc.Start();
Redirect(InterProc.StandardOutput);
Redirect(InterProc.StandardError);
}
private void Redirect(StreamReader input)
{
new Thread((a) =>
{
var buffer = new char[1];
while (true)
{
if (input.Read(buffer, 0, 1) > 0)
OutputReceived(new string(buffer));
};
}).Start();
}
private void OutputReceived(string text)
{
if (OutputReceivedEvent != null)
OutputReceivedEvent(text);
}
public void Input(string input)
{
InterProc.StandardInput.WriteLine(input);
InterProc.StandardInput.Flush();
}
}
What I'm trying to accomplish? Here is a minial use case. Assume that I have two textboxes.
//Create my interceptor
ConsoleInterceptor interc = new ConsoleInterceptor("cmd");
//Show the output in a textbox
interc.OutputReceivedEvent += (data) =>
{
this.Invoke(new Action<string>((s)=> this.textBoxOut.Text += s) ,data);
};
//Capture user input and pass that to the above interceptor
private void textInput_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
interc.Input(textInput.Text);
}
}
Instead of using another thread looping over the output stream, you can attach a handler to the Process.OutputDataReceived Event, which, after you've called BeginOutputReadLine, is raised when the process writes a line to the redirected StandardOutput stream (which you've already done).
There's a full example in the link which should hopefully help.
In order to fully be compatible with any console process, you need three separate threads: one writing to stdin, one reading from stdout, and one reading from stderr. These are in addition to your main thread. Your example code only has one of the three threads required (stdout).
精彩评论