2010-11-05 18 views
9

Pregunta: Deseo controlar cmd.exe desde winforms.

NO me refiero a todos los comandos en un solo proceso, con startupinfo, y luego me detengo.

Me refiero, por ejemplo, iniciar el (Mi) indicador de SQL o un comando BGF, enviar el comando, recibir respuesta, enviar el próximo comando, recibirá el próximo respuesta, deje de comandos SQL pronta
proceso de salida.

Básicamente quiero escribir una GUI encima de cualquier aplicación de consola.

Quiero que la salida de cmd.exe se redirija a un campo de texto, y la entrada provenga de otro campo de texto (al presionar el botón enter/OK).Control de cmd.exe desde Winforms

No encuentro ninguna muestra para esto. ¿Hay alguna manera?

Respuesta

16

No es un buen ejemplo de CodeProject

Buena suerte!

-Edit: Creo que se parece más a esto, creé un formulario simple, 2 cuadros de texto y tres botones. El primer cuadro de texto es para la entrada de comandos, el segundo (multilínea) muestra el resultado.

El primer botón se ejecuta el comando, el segundo botón actualiza el resultado (asíncrono porque los resultados se leen)

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

En la imagen se puede ver que entré en el comando cd \ cambiar el directorio y el siguiente comando ejecutado en este directorio (dir). alt text

+0

Hola, ¿cómo puedo escribir Ctrl + C en el comando? –

2

No necesita interoperacion para esto. La clase .NET Process le ofrece todo lo que necesita, simplemente redirige la secuencia de entrada estándar y la secuencia de salida y ya está. Puede encontrar muchos ejemplos de cómo hacerlo en Internet.

+1

Sí, pero no es tan simple si desea emitir varios comandos uno tras otro EN EL MISMO PROCESO, donde el segundo comando no se conoce en tiempo de compilación, como se dijo. Y para eso, no encuentras ninguno que funcione. –

1

No necesita usar cmd.exe para esto, puede llamar a los comandos directamente con Process.Start(). Si redirige a StandardInput y StandardOutput, puede controlar el proceso.

He escrito un ejemplo como respuesta a another question.

Editar
que no tienen un ejemplo completo para ello, pero se podía escuchar StandardOutput con el evento Process.OutputDataReceived si no desea esperar de forma sincrónica. Hay un ejemplo en la página de MSDN.

+0

Esto de ninguna manera resuelve el problema. Cierra la secuencia de entrada para leer la salida, pero a partir de ese momento, no es posible enviar ningún comando adicional. –

+0

@Quandary, actualicé mi respuesta con un enlace al evento OutputDataReceived que podría ser más útil en su caso. –

0

Ésta es la respuesta perfecta:

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 

Más temprano el Probé con outputstream.Peek Wile() = -1 pero esto se estrelló por un error en la función Peek marco .NET, que doesn 't timeout o lanzar un error si lee al final de la secuencia ...

Funciona mejor, ya que realmente capta toda la salida, pero está lejos de ser perfecto.

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 
Cuestiones relacionadas