代码之家  ›  专栏  ›  技术社区  ›  Stefan Steiger

从Winforms控制cmd.exe

  •  10
  • Stefan Steiger  · 技术社区  · 14 年前

    问题:我想从winforms控制cmd.exe。

    我不是说一个进程中的每个命令都有startupinfo,然后停止。

    例如,启动(My)SQL或GDB命令提示符、send command、receive answer、send next command、receive next answer、stop SQL命令提示符
    退出过程。

    基本上我想在任何控制台应用程序之上编写一个GUI。

    我没有找到这个的样品。 有办法吗?

    4 回复  |  直到 6 年前
        1
  •  19
  •   Pieter    14 年前

    有一个很好的例子 CodeProject

    -编辑: 我想这更像是,我创建了一个简单的表单,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);
                }
            }
        }
    }
    

    alt text

        2
  •  2
  •   codymanix    14 年前

    您不需要为此进行互操作。.NET Process 类为您提供所需的一切,只需重定向标准输入流和输出流即可。你可以在网上找到很多这样做的例子。

        3
  •  1
  •   Community Egal    7 年前

    不需要为此使用cmd.exe,可以直接使用 Process.Start()

    我写了一个例子作为对 another question

    编辑
    我没有一个完整的例子,但是您可以用 Process.OutputDataReceived

        4
  •  0
  •   Stefan Steiger    13 年前

    这是一个完美的答案:

    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框架预览函数中的错误而崩溃,如果您在流的末尾读取,它不会超时或抛出错误。。。

    它工作得更好,因为它确实能捕获所有输出,但它远不是完美的。

    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