1 回答
TA贡献1816条经验 获得超6个赞
代码在此示例中执行的操作的简要说明:
shell 命令 ( cmd.exe) 首先运行,start /WAIT用作参数。或多或少与以下功能相同/k:控制台在没有任何特定任务的情况下启动,在发送命令时等待处理命令。
StandardOutput,StandardError并且StandardInput都被重定向,将ProcessStartInfo 的RedirectStandardOutput、RedirectStandardError和RedirectStandardInput属性设置为。true
控制台输出流在写入时将引发OutputDataReceived事件;它的内容可以从DataReceivedEventArgs的e.Data成员中读取。将其ErrorDataReceived事件用于相同目的。 您可以对这两个事件使用单个事件处理程序,但是,经过一些测试后,您可能会意识到这可能不是一个好主意。将它们分开可以避免一些奇怪的重叠,并允许轻松区分错误与正常输出(注意,您可以找到写入错误流而不是输出流的程序)。
StandardError
StandardInput可以重定向,将其分配给StreamWriter流。
每次将字符串写入流时,控制台都会将该输入解释为要执行的命令。
此外,进程被指示在终止时引发它的Exited事件,将其EnableRaisingEvents属性设置为true。
在Exited当该过程被关闭,因为引发事件Exit命令被处理或调用.Close()方法(或最终的.Kill()方法,应仅用于whcich仅当一个进程不响应了,对于一些原因)。
由于我们需要将控制台输出传递给某些 UI 控件(RichTextBoxes在此示例中)并且 Process 事件在 ThreadPool 线程中引发,因此我们必须将此上下文与 UI 同步。
这可以通过使用 Process SynchronizingObject属性、将其设置为父窗体或使用Control.BeginInvoke方法来完成,该方法将在控件句柄所属的线程上执行委托函数。
在这里,代表委托的MethodInvoker用于此目的。
用于实例化 Process 并设置其属性和事件处理程序的核心函数:
using System;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
StreamWriter stdin = null;
public partial class frmCmdInOut : Form
{
Process cmdProcess = null;
StreamWriter stdin = null;
public frmCmdInOut() => InitializeComponent();
private void MainForm_Load(object sender, EventArgs e)
{
rtbStdIn.Multiline = false;
rtbStdIn.SelectionIndent = 20;
}
private void btnStartProcess_Click(object sender, EventArgs e)
{
btnStartProcess.Enabled = false;
StartCmdProcess();
btnEndProcess.Enabled = true;
}
private void btnEndProcess_Click(object sender, EventArgs e)
{
if (stdin.BaseStream.CanWrite) {
stdin.WriteLine("exit");
}
btnEndProcess.Enabled = false;
btnStartProcess.Enabled = true;
cmdProcess?.Close();
}
private void rtbStdIn_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter) {
if (stdin == null) {
rtbStdErr.AppendText("Process not started" + Environment.NewLine);
return;
}
e.Handled = true;
if (stdin.BaseStream.CanWrite) {
stdin.Write(rtbStdIn.Text + Environment.NewLine);
stdin.WriteLine();
// To write to a Console app, just
// stdin.WriteLine(rtbStdIn.Text);
}
rtbStdIn.Clear();
}
}
private void StartCmdProcess()
{
var pStartInfo = new ProcessStartInfo {
FileName = "cmd.exe",
// Batch File Arguments = "/C START /b /WAIT somebatch.bat",
// Test: Arguments = "START /WAIT /K ipconfig /all",
Arguments = "START /WAIT",
WorkingDirectory = Environment.SystemDirectory,
// WorkingDirectory = Application.StartupPath,
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
UseShellExecute = false,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
};
cmdProcess = new Process {
StartInfo = pStartInfo,
EnableRaisingEvents = true,
// Test without and with this
// When SynchronizingObject is set, no need to BeginInvoke()
//SynchronizingObject = this
};
cmdProcess.Start();
cmdProcess.BeginErrorReadLine();
cmdProcess.BeginOutputReadLine();
stdin = cmdProcess.StandardInput;
// stdin.AutoFlush = true; <- already true
cmdProcess.OutputDataReceived += (s, evt) => {
if (evt.Data != null)
{
BeginInvoke(new MethodInvoker(() => {
rtbStdOut.AppendText(evt.Data + Environment.NewLine);
rtbStdOut.ScrollToCaret();
}));
}
};
cmdProcess.ErrorDataReceived += (s, evt) => {
if (evt.Data != null) {
BeginInvoke(new Action(() => {
rtbStdErr.AppendText(evt.Data + Environment.NewLine);
rtbStdErr.ScrollToCaret();
}));
}
};
cmdProcess.Exited += (s, evt) => {
stdin?.Dispose();
cmdProcess?.Dispose();
};
}
}
由于 StandardInput 已被重定向到 StreamWriter:
stdin = cmdProcess.StandardInput;
我们只需写入 Stream 以执行命令:
stdin.WriteLine(["Command Text"]);
示例表单可以从 PasteBin 下载。
- 1 回答
- 0 关注
- 244 浏览
添加回答
举报