从控制台应用程序发送输入/获取输出(C#/ WinForms)
我有一个包含3个控件的表单:
- 用户输入命令以发送到控制台应用程序的文本框,
- 用于确认要发送的命令的按钮
- 一个只读文本框,用于显示应用程序的输出。
我想要的是让用户在第一个文本框中输入命令,按下按钮以通过第二个文本框输入和接收反馈。
我知道如何使用ProcessStartInfo.RedirectStandardOutput
但是,当我使用StandardOutput.ReadToEnd()
时,应用程序挂起。
我看了一下异步的Process.BeginOutputReadLine()
但是,即使我的应用程序没有挂起,不知何故我在文本框中没有得到任何响应,它什么也没做。
这是我的代码:
public partial class MainForm : Form { private void MainForm_Load(object sender, EventArgs e) { InitializeInterpreter(); } private void InitializeInterpreter() { InterProc.StartInfo.UseShellExecute = false; InterProc.StartInfo.FileName = "app.exe"; InterProc.StartInfo.RedirectStandardInput = true; InterProc.StartInfo.RedirectStandardOutput = true; InterProc.StartInfo.RedirectStandardError = true; InterProc.StartInfo.CreateNoWindow = true; InterProc.OutputDataReceived += new DataReceivedEventHandler(InterProcOutputHandler); InterProc.Start(); } private static void InterProcOutputHandler(object sendingProcess, DataReceivedEventArgs outLine) { if (!String.IsNullOrEmpty(outLine.Data)) { OutputTextBox.Append(Environment.NewLine + outLine.Data); } } private void Enterbutton_Click(object sender, EventArgs e) { InterProc.StandardInput.Write(CommandtextBox.Text); InterProc.BeginOutputReadLine(); } }
有什么办法让我顺利运行吗? 谢谢。
如果你想要一些互动的东西,我得到了这个代码(你的修改,下面修改的细节)
private void InitializeInterpreter() { InterProc.StartInfo.UseShellExecute = false; InterProc.StartInfo.FileName = "Echoer.exe"; InterProc.StartInfo.RedirectStandardInput = true; InterProc.StartInfo.RedirectStandardOutput = true; InterProc.StartInfo.RedirectStandardError = true; InterProc.StartInfo.CreateNoWindow = true; InterProc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; InterProc.OutputDataReceived += new DataReceivedEventHandler(InterProcOutputHandler); bool started = InterProc.Start(); InterProc.BeginOutputReadLine(); } private void AppendTextInBox(TextBox box, string text) { if (this.InvokeRequired) { this.Invoke((Action)AppendTextInBox, OutputTextBox, text); } else { box.Text += text; } } private void InterProcOutputHandler(object sendingProcess, DataReceivedEventArgs outLine) { AppendTextInBox(OutputTextBox, outLine.Data + Environment.NewLine); } private void Enterbutton_Click(object sender, EventArgs e) { InterProc.StandardInput.WriteLine(CommandTextBox.Text); }
因此,我将BeginOutputReadLine移动到进程启动后。 这确保它实际上只被调用一次。 我还做了一个清理线程调用所需的调用。 希望这对你有用。
我发现的最佳解决方案是:
private void Redirect(StreamReader input, TextBox output) { new Thread(a => { var buffer = new char[1]; while (input.Read(buffer, 0, 1) > 0) { output.Dispatcher.Invoke(new Action(delegate { output.Text += new string(buffer); })); }; }).Start(); } private void Window_Loaded(object sender, RoutedEventArgs e) { process = new Process { StartInfo = new ProcessStartInfo { CreateNoWindow = true, FileName = "app.exe", RedirectStandardError = true, RedirectStandardOutput = true, UseShellExecute = false, } }; if (process.Start()) { Redirect(process.StandardError, textBox1); Redirect(process.StandardOutput, textBox1); } }
我使用过这样的代码:
public static void Run(string fileName, string arguments, out string standardOutput, out string standardError, out int exitCode) { Process fileProcess = new Process(); fileProcess.StartInfo = new ProcessStartInfo { FileName = fileName, Arguments = arguments, RedirectStandardError = true, RedirectStandardOutput = true, UseShellExecute = false, WindowStyle = ProcessWindowStyle.Hidden, CreateNoWindow = true, }; bool started = fileProcess.Start(); if (started) { fileProcess.WaitForExit(); } else { throw new Exception("Couldn't start"); } standardOutput = fileProcess.StandardOutput.ReadToEnd(); standardError = fileProcess.StandardError.ReadToEnd(); exitCode = fileProcess.ExitCode; }
但它不是互动的。 但是如果应用程序是交互式的,那么无论如何都需要更多的代码。
你在哪里调用StandardOutput.ReadToEnd()
? 我曾经遇到过类似的问题,因为我在StandardOutput.ReadToEnd()
之前调用了Process.WaitForExit()
StandardOutput.ReadToEnd()
。 我有大量的输入,输出缓冲区在完成之前已满,我的进程被阻止。
您必须在Process.WaitForExit()
之前调用StandardOutput.ReadToEnd()
Process.WaitForExit()
。