Continuous Shell Session
-
Wednesday, August 22, 2012 9:40 PM
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 SubPublic 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 SubPrivate 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 FunctionEnd 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 SubPrivate Function Button1_Click_2(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bntSend.Click
End class
Dim cmdInput As String
cmdInput = txtCMD.Text
cmdProcess(cmdInput)
Return cmdInput
txtCMD.Text = ""
End Function -
Thursday, August 23, 2012 12:26 AMModerator
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.
- Marked As Answer by Shanks ZenMicrosoft Contingent Staff, Moderator Thursday, September 06, 2012 6:09 AM

