Answered Continuous Shell Session

  • Wednesday, August 22, 2012 9:40 PM
     
      Has Code

    Hello, I have been back and forth on a personal project to get an application using shell in VB.net for some experience. I have everything working great but I have come to a crossroads with a limitation. I have a process in my program that operates commands with shell, the problem is that for every command I send through runs its own shell session rather than a continuous single session. I very much enjoy figuring these things out but I am finding this subject matter rather hard to find in the communities.  Within this process, is it possible to keep the same session open rather than opening a new one for each input. example, if i run ping -t localhost and type it again, it will just create two instances of the the ping and send them both back to my textbox and so on. The other hindrance in this is that if i send a looping command such as ping -t in, i have no way to kill other than to close the program itself. Any input would be appreciated.

    Public Class

        Private cmd As String
        Delegate Sub AppendText(ByVal Textbox As TextBox, ByVal Text As String)
        Sub AppendToTextBox(ByVal Textbox As TextBox, ByVal Text As String)
            If Textbox.InvokeRequired Then
                Textbox.Invoke(New AppendText(AddressOf AppendToTextBox), Textbox, Text)
            Else
                Try
                    Textbox.AppendText(Text & vbCrLf)
                    Textbox.Update()
                Catch
                End Try
            End If
        End Sub

        Public Sub recieveScript(ByVal script As String)
            cmdProcess(script, addEntry:=False)
        End Sub

    Public Sub cmdProcess(ByVal cmdInput As String, Optional ByVal addEntry As Boolean = True) Dim myProcess As Process = New Process Dim s As String = "" AddHandler myProcess.OutputDataReceived, AddressOf cmdOutput myProcess.StartInfo.FileName = "c:\windows\system32\cmd.exe" myProcess.StartInfo.UseShellExecute = False myProcess.StartInfo.CreateNoWindow = True myProcess.StartInfo.RedirectStandardInput = True myProcess.StartInfo.RedirectStandardOutput = True myProcess.StartInfo.RedirectStandardError = True myProcess.Start() myProcess.BeginOutputReadLine() Dim sIn As System.IO.StreamWriter = myProcess.StandardInput Dim sErr As System.IO.StreamReader = myProcess.StandardError sIn.AutoFlush = True sIn.Write(cmdInput & System.Environment.NewLine) sIn.Write("exit" & System.Environment.NewLine) cmdOutputTextBox.Text = s cmdOutputTextBox.Visible = True sIn.Close() sErr.Close() myProcess.Close() End Sub

        Public Sub cmdOutput(ByVal sendingProcess As Object, ByVal outLine As DataReceivedEventArgs)

            cmd = outLine.Data
            AppendToTextBox(cmdOutputTextBox, outLine.Data)

        End Sub

    Private Function Button1_Click_2(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bntSend.Click

            Dim cmdInput As String
            cmdInput = txtCMD.Text
            cmdProcess(cmdInput)
            Return cmdInput

            txtCMD.Text = ""

        End Function

    End Class


    Thank you,


    • Edited by JooseJoose Wednesday, August 22, 2012 9:42 PM
    •  

All Replies

  • Wednesday, August 22, 2012 9:47 PM
     
     

    The problem is that for every command you send, you start up the cmd.exe process, execute the command, and then close it.  Instead, create or start the cmd process when the app starts and keep a referecne to it open and then only close it when you  close your application.

    Keep references to the input and output streams and in your cmdProcess method just write the commands to the streams.

  • Thursday, August 23, 2012 12:05 AM
     
     

    Hey thank you so much for the advice, this works great. I did run into a new bug though and maybe you can identify it if I incorporated your advice wrong. Say for example I send a simply command such as "dir" into the shell, it returns everything wonderfully, however say I typed it again. Now in the output I will get each line twice, then three then four. Its like process is stacking up.

    Here was the adjustment I made based on what I understood from your advice.

    Public Class program

        Private cmd As String
        Delegate Sub AppendText(ByVal Textbox As TextBox, ByVal Text As String)

        Dim myProcess As Process = New Process
        Dim s As String = ""

        Dim cmdID As Integer = 0

        Dim sIn As System.IO.StreamWriter
        Dim sErr As System.IO.StreamReader

        Sub AppendToTextBox(ByVal Textbox As TextBox, ByVal Text As String)
            If Textbox.InvokeRequired Then
                Textbox.Invoke(New AppendText(AddressOf AppendToTextBox), Textbox, Text)
            Else
                Try
                    Textbox.AppendText(Text & vbCrLf)
                    Textbox.Update()
                Catch
                End Try
            End If
        End Sub

        Public Sub recieveScript(ByVal script As String)
            cmdProcess(script, addEntry:=False)
        End Sub

        Public Sub cmdProcess(ByVal cmdInput As String, Optional ByVal addEntry As Boolean = True)


            AddHandler myProcess.OutputDataReceived, AddressOf cmdOutput

            sIn.AutoFlush = True
            sIn.Write(cmdInput & System.Environment.NewLine)

            cmdOutputTextBox.Text = s
            cmdOutputTextBox.Visible = True

        End Sub

        Public Sub cmdOutput(ByVal sendingProcess As Object, ByVal outLine As DataReceivedEventArgs)

            cmd = outLine.Data
            AppendToTextBox(cmdOutputTextBox, outLine.Data)

        End Sub
        
        Private Sub program_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

            myProcess.StartInfo.FileName = "c:\windows\system32\cmd.exe"
            myProcess.StartInfo.UseShellExecute = False
            myProcess.StartInfo.CreateNoWindow = True
            myProcess.StartInfo.RedirectStandardInput = True
            myProcess.StartInfo.RedirectStandardOutput = True
            myProcess.StartInfo.RedirectStandardError = True
            myProcess.Start()
            myProcess.BeginOutputReadLine()
            sIn = myProcess.StandardInput
            sErr = myProcess.StandardError
            cmdID = myProcess.Id

        End Sub

    Private Function Button1_Click_2(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bntSend.Click

            Dim cmdInput As String
            cmdInput = txtCMD.Text
            cmdProcess(cmdInput)
            Return cmdInput

            txtCMD.Text = ""

        End Function

    End class
  • Thursday, August 23, 2012 12:26 AM
    Moderator
     
     Answered Has Code

    try these

    Public Class Form1
        Private cmd As String
        Public OPTB As TextBox
        Delegate Sub AppendText(ByVal Textbox As TextBox, ByVal Text As String)
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Dim ScriptLines As New List(Of String)
            ScriptLines.Add("cd blabal")
            ScriptLines.Add("dir /w /ad")
            'etc...
            ExecuteCmds(ScriptLines, TextBox1)
        End Sub
        Sub AppendToTextBox(ByVal Textbox As TextBox, ByVal Text As String)
            If Textbox.InvokeRequired Then
                Textbox.Invoke(New AppendText(AddressOf AppendToTextBox), Textbox, Text)
            Else
                Try
                    Textbox.AppendText(Text & vbCrLf)
                    Textbox.Update()
                Catch
                End Try
            End If
        End Sub
        Public Sub ExecuteCmds(ByVal cmdInput As List(Of String), Optional ByVal OutPutTextBox As TextBox = Nothing, Optional ByVal addEntry As Boolean = True)
            Try
                OPTB = OutPutTextBox
                Dim myProcess As Process = New Process
                Dim s As String = ""
                AddHandler myProcess.OutputDataReceived, AddressOf cmdOutput
                myProcess.StartInfo.FileName = "c:\windows\system32\cmd.exe"
                myProcess.StartInfo.Verb = "runas"
                myProcess.StartInfo.UseShellExecute = False
                myProcess.StartInfo.CreateNoWindow = True
                myProcess.StartInfo.RedirectStandardInput = True
                myProcess.StartInfo.RedirectStandardOutput = True
                myProcess.StartInfo.RedirectStandardError = True
                myProcess.Start()
                myProcess.BeginOutputReadLine()
                Dim sIn As System.IO.StreamWriter = myProcess.StandardInput
                Dim sErr As System.IO.StreamReader = myProcess.StandardError
                sIn.AutoFlush = True
                For Each ss As String In cmdInput
                    sIn.Write(ss & System.Environment.NewLine)
                Next
                If Not OutPutTextBox Is Nothing Then
                    OutPutTextBox.Text = s
                    OutPutTextBox.Visible = True
                End If
                sIn.Close()
                sErr.Close()
                myProcess.Close()
            Catch ex As Exception
                MsgBox(ex.ToString)
            End Try
    
        End Sub
        Public Sub cmdOutput(ByVal sendingProcess As Object, ByVal outLine As DataReceivedEventArgs)
            cmd = outLine.Data
            If Not OPTB Is Nothing Then
                AppendToTextBox(OPTB, outLine.Data)
            End If
        End Sub
    End Class
    


    If you want something you've never had, you need to do something you've never done.