2010-11-05 2 views
9

Вопрос: Я хочу управлять cmd.exe из winforms.

Я НЕ имею в виду каждую команду в одном процессе с помощью startupinfo, а затем останавливается.

Я имею в виду, например, начать (My) SQL или команды GDB запрос, отправить команду, получить ответ, отправить следующую команду, получить следующий ответ, остановить команду SQL проворного
процесс выхода.

В принципе, я хочу написать графический интерфейс поверх любого консольного приложения.

Я хочу, чтобы выходные данные cmd.exe перенаправлялись в текстовое поле, а входные данные поступали из другого текстового поля (нажмите кнопку ввода/OK).Управление cmd.exe из Winforms

Я не нахожу образцы для этого. Есть ли способ?

ответ

16

Существует хороший пример на CodeProject

Удачи!

-Edit: Я думаю, что это больше похоже на то, что я создал простую форму, 2 текстовых поля и три кнопки. Первый текстовый блок для ввода команды, второй (многострочный), отображает результат.

Первая кнопка выполняет команды, вторая кнопка обновляет результат (поскольку результаты считываются асинхронной)

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). alt text

+0

привет, как я могу написать Ctrl + C в команде? –

2

Для этого вам не требуется взаимодействие. Класс .NET Process дает вам все, что вам нужно, просто перенаправляет стандартный поток ввода и поток вывода, и это делается. Вы можете найти множество примеров, как это сделать в Интернете.

+1

Да, но это не так просто, если вы хотите выпустить несколько команд один за другим в том же процессе, где вторая команда не известна во время компиляции, как сказано. И для этого вы не найдете ничего, что сработает. –

1

Для этого вам не нужно использовать cmd.exe, вы можете напрямую вызвать команды с помощью Process.Start(). Если вы перенаправите StandardInput и StandardOutput, вы сможете управлять процессом.

Я написал пример ответа another question.

Редактировать
Я не полный пример, но вы можете слушать StandardOutput с Process.OutputDataReceived случае, если вы не хотите ждать синхронно. На странице MSDN есть пример.

+0

Это никоим образом не решает проблему. Он закрывает входной поток, чтобы читать вывод, но с этой точки невозможно отправить какие-либо дополнительные команды. –

+0

@ Quandary, я обновил свой ответ ссылкой на событие OutputDataReceived, которое может быть более полезным в вашем случае. –

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 но это получает разбился ошибкой в ​​функции Peek платформы .NET, которая Безразлично 't тайм-аут или выдать ошибку, если вы читаете в конце потока ...

Он работает лучше, поскольку он действительно ловит весь выход, но он далек от совершенства.

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