Controlling cmd.exe from Winforms

前端 未结 4 1755
面向向阳花
面向向阳花 2020-12-08 17:18

Question: I want to control cmd.exe from winforms.

I DO NOT mean every command in a single process, with startupinfo, and then stop.

I mean for example start

相关标签:
4条回答
  • 2020-12-08 17:59

    You don't need to use cmd.exe for this, you can call the commands directly with Process.Start(). If you redirect StandardInput and StandardOutput you can control the process.

    I have written an example as a response to another question.

    Edit
    I don't have a complete example for it, but you could listen to StandardOutput with the Process.OutputDataReceived event if you don't want to wait synchronously. There is an example on the MSDN page.

    0 讨论(0)
  • 2020-12-08 18:04

    You do not need interop for this. The .NET Process class gives you all you need, simply redirect standard input stream and output stream and it is done. You can find lots of examples how to do this on the internet.

    0 讨论(0)
  • 2020-12-08 18:08

    This is the perfect answer:

    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
    

    Earlier on I tried with wile outputstream.Peek() != -1 but this gets crashed by a bug in the .NET framework Peek function, which doesn't timeout or throw an error if you read over the end of stream...

    It works better in that it really catches all output, but it's far from perfect.

    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
    
    0 讨论(0)
  • 2020-12-08 18:13

    There is a nice example on CodeProject

    Good luck!

    -Edit: I think this is more like it, I created a simple form, 2 textboxes and three buttons. First textbox is for command entry, the second (multiline), displays the result.

    The first button executes the command, the second button updates the result (because results are read async)

    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);
                }
            }
        }
    }
    

    In the screenshot you can see that I entered the cd\ command to change directory and the next command executed in this directory (dir).alt text

    0 讨论(0)
提交回复
热议问题