从Winforms控制cmd.exe
问题:我想从winforms控制cmd.exe。
我并不是指使用startupinfo在单个进程中的每个命令,然后停止。
我的意思是例如启动(我的)SQL或GDB命令提示符,发送命令,接收答案,发送下一个命令,接收下一个答案,停止SQL命令提示符
退出过程。
基本上我想在任何控制台应用程序之上编写GUI。
我想让cmd.exe的输出重定向到文本字段,输入来自另一个文本字段(按下输入/确定按钮)。
我没有找到任何样品。 有办法吗?
CodeProject上有一个很好的例子
祝好运!
-Edit:我认为这更像是它,我创建了一个简单的表单,2个文本框和3个按钮。 第一个文本框用于命令输入,第二个(多行)显示结果。
第一个按钮执行命令,第二个按钮更新结果(因为结果被读取为异步)
namespace WindowsFormsApplication2 { public partial class Form1 : Form { private static StringBuilder cmdOutput = null; Process cmdProcess; StreamWriter cmdStreamWriter; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { cmdOutput = new StringBuilder(""); cmdProcess = new Process(); cmdProcess.StartInfo.FileName = "cmd.exe"; cmdProcess.StartInfo.UseShellExecute = false; cmdProcess.StartInfo.CreateNoWindow = true; cmdProcess.StartInfo.RedirectStandardOutput = true; cmdProcess.OutputDataReceived += new DataReceivedEventHandler(SortOutputHandler); cmdProcess.StartInfo.RedirectStandardInput = true; cmdProcess.Start(); cmdStreamWriter = cmdProcess.StandardInput; cmdProcess.BeginOutputReadLine(); } private void btnExecute_Click(object sender, EventArgs e) { cmdStreamWriter.WriteLine(textBox2.Text); } private void btnQuit_Click(object sender, EventArgs e) { cmdStreamWriter.Close(); cmdProcess.WaitForExit(); cmdProcess.Close(); } private void btnShowOutput_Click(object sender, EventArgs e) { textBox1.Text = cmdOutput.ToString(); } private static void SortOutputHandler(object sendingProcess, DataReceivedEventArgs outLine) { if (!String.IsNullOrEmpty(outLine.Data)) { cmdOutput.Append(Environment.NewLine + outLine.Data); } } } }
在屏幕截图中,您可以看到我输入了cd \命令来更改目录以及在此目录(dir)中执行的下一个命令。
你不需要互操作。 .NET Process
类为您提供了所需的一切,只需重定向标准输入流和输出流即可完成。 您可以在互联网上找到许多如何执行此操作的示例。
您不需要使用cmd.exe,可以直接使用Process.Start()
调用命令。 如果重定向StandardInput和StandardOutput,则可以控制该过程。
我写了一个例子作为对另一个问题的回答 。
编辑
我没有完整的示例,但如果您不想同步等待,则可以使用Process.OutputDataReceived
事件监听StandardOutput。 MSDN页面上有一个示例。
这是完美的答案:
using System; using System.Windows.Forms; namespace WindowsConsole { public partial class Form1 : Form { System.Diagnostics.Process spdTerminal; System.IO.StreamWriter swInputStream; public delegate void fpTextBoxCallback_t(string strText); public fpTextBoxCallback_t fpTextBoxCallback; public Form1() { fpTextBoxCallback = new fpTextBoxCallback_t(AddTextToOutputTextBox); InitializeComponent(); } // End Constructor public void AddTextToOutputTextBox(string strText) { this.txtOutput.AppendText(strText); } // End Sub AddTextToOutputTextBox private void btnQuit_Click(object sender, EventArgs e) { swInputStream.WriteLine("exit"); swInputStream.Close(); //spdTerminal.WaitForExit(); spdTerminal.Close(); spdTerminal.Dispose(); Application.Exit(); } // End Sub btnQuit_Click private void ConsoleOutputHandler(object sendingProcess, System.Diagnostics.DataReceivedEventArgs outLine) { if (!String.IsNullOrEmpty(outLine.Data)) { //this.Invoke(new fpTextBoxCallback_t(AddTextToOutputTextBox), Environment.NewLine + outLine.Data); if(this.InvokeRequired) this.Invoke(fpTextBoxCallback, Environment.NewLine + outLine.Data); else fpTextBoxCallback(Environment.NewLine + outLine.Data); } // End if (!String.IsNullOrEmpty(outLine.Data)) } // End Sub ConsoleOutputHandler private void btnExecute_Click(object sender, EventArgs e) { if (this.spdTerminal.HasExited) { MessageBox.Show("You idiot, you have terminated the process", "Error"); return; } // End if (this.spdTerminal.HasExited) swInputStream.WriteLine(txtInputCommand.Text); } // End Sub btnExecute_Click public void ProcessExited(object sender, EventArgs e) { MessageBox.Show("You idiot, you terminated the process.", "PBKAC"); } // End Sub ProcessExited private void Form1_Load(object sender, EventArgs e) { spdTerminal = new System.Diagnostics.Process(); if(Environment.OSVersion.Platform == PlatformID.Unix) //spdTerminal.StartInfo.FileName = "/usr/bin/gnome-terminal"; spdTerminal.StartInfo.FileName = "/bin/bash"; else spdTerminal.StartInfo.FileName = "cmd.exe"; AddTextToOutputTextBox("Using this terminal: " + spdTerminal.StartInfo.FileName); spdTerminal.StartInfo.UseShellExecute = false; spdTerminal.StartInfo.CreateNoWindow = true; spdTerminal.StartInfo.RedirectStandardInput = true; spdTerminal.StartInfo.RedirectStandardOutput = true; spdTerminal.StartInfo.RedirectStandardError = true; spdTerminal.EnableRaisingEvents = true; spdTerminal.Exited += new EventHandler(ProcessExited); spdTerminal.ErrorDataReceived += new System.Diagnostics.DataReceivedEventHandler(ConsoleOutputHandler); spdTerminal.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(ConsoleOutputHandler); spdTerminal.Start(); swInputStream = spdTerminal.StandardInput; spdTerminal.BeginOutputReadLine(); spdTerminal.BeginErrorReadLine(); } // End Sub Form1_Load } // End Class Form1 } // End Namespace WindowsConsole
早些时候我尝试使用wile outputstream.Peek()!= -1但是这会被.NET框架Peek函数中的一个错误所破坏,如果你读过流的末尾,它就不会超时或抛出错误…
它的效果更好,因为它真正捕获了所有输出,但它远非完美。
Public Class Form1 ' That's our custom TextWriter class Private _writer As System.IO.TextWriter = Nothing Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing If p IsNot Nothing Then p.Close() p.Dispose() p = Nothing End If End Sub Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load InitProcess() '' Instantiate the writer '_writer = New ConsoleRedirection.TextBoxStreamWriter(Me.txtConsole) '' Redirect the out Console stream 'Console.SetOut(_writer) 'Console.WriteLine("Now redirecting output to the text box1") 'Console.WriteLine("Now redirecting output to the text box2") End Sub Protected p As Process Protected sw As System.IO.StreamWriter Protected sr As System.IO.StreamReader Protected err As System.IO.StreamReader Protected objWriter As System.IO.StreamWriter Protected objWriteNumeric As System.IO.StreamWriter Private Sub InitProcess() p = New Process() Dim psI As New ProcessStartInfo("cmd") psI.UseShellExecute = False psI.RedirectStandardInput = True psI.RedirectStandardOutput = True psI.RedirectStandardError = True psI.CreateNoWindow = True p.StartInfo = psI p.Start() sw = p.StandardInput sr = p.StandardOutput err = p.StandardError sw.AutoFlush = True objWriter = New System.IO.StreamWriter("c:\temp\logmy.txt", True, System.Text.Encoding.ASCII) objWriteNumeric = New System.IO.StreamWriter("c:\temp\lognum.txt", True, System.Text.Encoding.ASCII) Timer1.Enabled = True Timer1.Start() End Sub Private Sub start() If Me.txtinput.Text <> "" Then sw.WriteLine(Me.txtinput.Text) Else 'execute default command sw.WriteLine("dir c:\music") End If sw.Flush() Timer2.Enabled = True End Sub Private Sub start_original() p = New Process() Dim sw As System.IO.StreamWriter Dim sr As System.IO.StreamReader Dim err As System.IO.StreamReader Dim psI As New ProcessStartInfo("cmd") psI.UseShellExecute = False psI.RedirectStandardInput = True psI.RedirectStandardOutput = True psI.RedirectStandardError = True psI.CreateNoWindow = True p.StartInfo = psI p.Start() sw = p.StandardInput sr = p.StandardOutput err = p.StandardError sw.AutoFlush = True Me.txtinput.Text = "help" If Me.txtinput.Text <> "" Then sw.WriteLine(Me.txtinput.Text) Else 'execute default command sw.WriteLine("dir \") End If sw.Close() 'Me.txtConsole.Text = sr.ReadToEnd() 'txtinput.Text = sr.ReadToEnd() 'txtinput.Text += err.ReadToEnd() End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click start() End Sub Protected sb As String = "" Sub ReadOutputStreamIfAvailable() 'cbEndOfStream.Checked = sr.EndOfStream While True objWriteNumeric.WriteLine(sr.Peek().ToString()) objWriteNumeric.Flush() If sr.Peek = -1 Then Exit While End If Dim iCharAsNumber As Integer = sr.Read() Dim cNumberAsChar As Char = Nothing If Not iCharAsNumber = Nothing Then Try cNumberAsChar = Chr(iCharAsNumber) Catch Continue While 'MsgBox(Prompt:=xx.ToString, Title:="Error") 'Exit While End Try End If Dim strCharAsString As String = "" If Not cNumberAsChar = Nothing Then strCharAsString = cNumberAsChar.ToString() End If sb += strCharAsString End While If Not String.IsNullOrEmpty(sb) Then 'MsgBox(sb) MsgBox(sb) Me.txtConsole.Text += sb 'MsgBox(sb) sb = "" End If End Sub Protected er As String = "" Sub ReadErrorStreamIfAvailable() 'cbEndOfStream.Checked = sr.EndOfStream While True objWriteNumeric.WriteLine(sr.Peek().ToString()) objWriteNumeric.Flush() If err.Peek = -1 Then Exit While End If Dim iCharAsNumber As Integer = err.Read() Dim cNumberAsChar As Char = Nothing If Not iCharAsNumber = Nothing Then Try cNumberAsChar = Chr(iCharAsNumber) Catch Continue While 'MsgBox(Prompt:=xx.ToString, Title:="Error") 'Exit While End Try End If Dim strCharAsString As String = "" If Not cNumberAsChar = Nothing Then strCharAsString = cNumberAsChar.ToString() End If er += strCharAsString End While If Not String.IsNullOrEmpty(er) Then 'MsgBox(sb) 'MsgBox(er) Me.txtConsole.Text += er 'MsgBox(sb) er = "" End If End Sub Protected Shared objOutputStreamLocker As Object = New Object Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick Timer1.Enabled = False SyncLock objOutputStreamLocker ReadOutputStreamIfAvailable() 'ReadErrorStreamIfAvailable() End SyncLock Timer1.Enabled = True End Sub Private Sub Timer2_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer2.Tick Try Timer2.Enabled = False sb = Chr(sr.Read()).ToString() '' 'er = Chr(err.Read()).ToString() '' Timer1.Enabled = True Catch ex As Exception MsgBox("You have terminated the process", Title:="You idiot!") End Try End Sub ' http://www.c-sharpcorner.com/UploadFile/edwinlima/SystemDiagnosticProcess12052005035444AM/SystemDiagnosticProcess.aspx Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click End Sub End Class