问题:我想从winforms控制cmd.exe。
我不是指使用startupinfo在单个进程中的每个命令,然后停止。
我的意思是例如启动(My)SQL或GDB命令提示符,发送命令,接收答案,发送下一个命令,接收下一个答案,停止SQL命令提示符
退出过程。
基本上我想在任何控制台应用程序之上编写GUI。
我希望将cmd.exe的输出重定向到文本字段,输入来自另一个文本字段(按下输入/确定按钮)。
我没有找到任何样品。 有办法吗?
答案 0 :(得分:18)
- 编辑: 我觉得这更像是它,我创建了一个简单的表单,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)中执行的下一个命令。
答案 1 :(得分:2)
你不需要互操作。 .NET Process
类为您提供了所需的一切,只需重定向标准输入流和输出流即可完成。你可以在互联网上找到很多如何做到这一点的例子。
答案 2 :(得分:1)
您不需要使用cmd.exe,可以直接使用Process.Start()
调用命令。如果重定向StandardInput和StandardOutput,则可以控制该过程。
我写了一个例子作为对another question的回复。
修改强>
我没有完整的示例,但如果您不想同步等待,则可以使用Process.OutputDataReceived
事件收听StandardOutput。 MSDN页面上有一个示例。
答案 3 :(得分:0)
这是一个完美的答案:
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