Read Standard Output and check status of multiple processes VB.NET - vb.net

I run multiple command line processes, starting them in a loop. It works and starts all of them async.
Public Sub DoWork
Dim i As Integer = 0
While (Args_reader.Peek() > -1)
i = i + 1
MyArg = Args_reader.ReadLine
Dim MyArg As String
Dim MyProcess(i) As Process
MyProcess(i) = New Process
With MyProcess(i).StartInfo
.FileName = MyFile
.Arguments = MyArg
.UseShellExecute = False
.CreateNoWindow = True
.RedirectStandardInput = True
.RedirectStandardOutput = True
.RedirectStandardError = True
.WindowStyle = ProcessWindowStyle.Hidden
End With
MyProcess(i).Start()
End While
Args_reader.Close()
i = 0
End Sub
Haw can I read stdOutput for all of them and check their status?
I need to wait until they finish to continue executing the program.

I would recommend you to assign async events to every process inside a loop, so they get fired when that process has any output. Standard Output or Error Output:
Dim Proceso As New Process
'Add the event handlers:
AddHandler Proceso.OutputDataReceived, AddressOf CallbackProcesoAsync
AddHandler Proceso.ErrorDataReceived, AddressOf ErrorDataReceivedAsync
Dim startInfo As New ProcessStartInfo
startInfo.FileName = execFile
startInfo.RedirectStandardOutput = True
startInfo.RedirectStandardError = True
startInfo.CreateNoWindow = False
Proceso.StartInfo = startInfo
Proceso.Start()
the async events should be something like this:
Private Sub CallbackProcesoAsync(sender As Object, args As System.Diagnostics.DataReceivedEventArgs)
If Not args.Data Is Nothing AndAlso Not String.IsNullOrEmpty(args.Data) Then
'args.Data have the output
End If
End Sub
Private Sub ErrorDataReceivedAsync(sender As Object, args As System.Diagnostics.DataReceivedEventArgs)
If Not args.Data Is Nothing AndAlso Not String.IsNullOrEmpty(args.Data) Then
'args.Data have the output
End If
End Sub

Related

VB.NET Read 2 checkboxes status from file

I am trying to recover the status of 2 checkboxes.
This 2 checkboxes i made them to work as radiobuttun: While one is checked, the another one uncheck.
I have an external file for the configuration of the program and i want that evrytime that I exit from the program, everything be saved in this file.
For do it I use this code:
Private Sub Form1_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
Dim thefile As String = Application.StartupPath & "\SafetyBox.cfg"
Dim lines() As String = System.IO.File.ReadAllLines(thefile)
lines(1) = "Language_file=" & ComboBox1.Text
If CheckBox1.Checked = True Then
lines(2) = "Status1=" & "1"
Else
lines(2) = "Status1=" & "0"
End If
If CheckBox2.Checked = True Then
lines(3) = "Status2=" & "1"
Else
lines(3) = "Status2=" & "0"
End If
System.IO.File.WriteAllLines(thefile, lines)
End Sub`
And this part working great. Status1 should be the status of checkbox1, while status2 is the status of checkbox2.
The code that is not working is:
Dim path As String = Application.StartupPath & "\SafetyBox.cfg"
If File.Exists(path) Then
Using sr As StreamReader = New StreamReader(path)
Dim linenew As String = sr.ReadLine()
If linenew.Contains("\") Then
TextBox1.Text = linenew
Else
MsgBox("Configura il programma da usare")
End If
Dim lineN As String = sr.ReadLine()
If lineN.Contains("Language_file=") Then
ComboBox1.Text = lineN.Split("=").Last()
End If
If lineN.Contains("Status1=1") Then
CheckBox1.Checked = True
CheckBox2.Checked = False
ElseIf lineN.contains("Status1=0") Then
CheckBox1.Checked = False
CheckBox2.Checked = True
End If
If lineN.Contains("Status2=1") Then
CheckBox1.Checked = False
CheckBox2.Checked = True
ElseIf lineN.Contains("Status2=0") Then
CheckBox1.Checked = True
CheckBox2.Checked = False
End If
sr.ReadToEnd()
sr.Close()
End Using
Can yOu let me understnd where is my mistake? Why when in the .cfg file is wrote correctly Status1=0 and Status2=1, when loading the program i always see checkbox1 checkd and not checkbox2?
Thanks
You wrote that you got the CheckBoxes working as RadionButtons. I suspect that to do this you handled either or both of the events CheckedChanged and CheckStateChanged.
So that when the CheckState is changed, the other Checkbox is set or unset appropriately.
When you load the configuration/state of the form from the file, you are setting the values on the CheckBoxes and subsequently, causing the events to be fired. To prevent the events from being fired you should temporarily remove the event handlers from the Checkbox controls.
Add the lines at the start of your method to load the configuration:
RemoveHandler Checkbox1.CheckStateChanged, AddressOf Checkbox1_CheckStateChanged
RemoveHandler Checkbox2.CheckStateChanged, AddressOf Checkbox2_CheckStateChanged
And, at the end of the method, you will need to re-establish the event handlers by using:
AddHandler Checkbox1.CheckStateChanged, AddressOf Checkbox1_CheckStateChanged
AddHandler Checkbox2.CheckStateChanged, AddressOf Checkbox2_CheckStateChanged
If this is the problem, what you have encountered is a common enough problem when a form has multiple event handlers that respond to xxxChanged events.

I am trying to read the Output from the Openfiles.exe and this is not working

This is to run the openfiles.exe and return the output from it
If i run openfiles.exe at the command line it works as expected
When I run it here there is no error but i get nothing in the Messagebox
Dim NewProcess As New Process()
With NewProcess.StartInfo
.FileName = "openfiles.exe"
.Arguments = "/query /s FakeServer/fo csv /V /U FakeDomain\Fakeuser/P pword"
.RedirectStandardOutput = True
.RedirectStandardError = True
.RedirectStandardInput = True
.UseShellExecute = False
.WindowStyle = ProcessWindowStyle.Normal
.CreateNoWindow = False
End With
NewProcess.Start()
System.Threading.Thread.Sleep(5000)
MsgBox(NewProcess.StandardOutput.ReadToEnd)
This is just a sample code that I have that is similar to what you are trying to do. However, my app was trying to run a command using cmd.exe and display the result in real time to a textbox. You can try to modify it accordingly.
Dim cmd As New Process()
Dim strCommandLine As String = "Echo Hello World"
cmd.StartInfo.FileName = "cmd.exe"
cmd.StartInfo.RedirectStandardError = True
cmd.StartInfo.RedirectStandardInput = True
cmd.StartInfo.RedirectStandardOutput = True
cmd.StartInfo.CreateNoWindow = True
cmd.StartInfo.UseShellExecute = False
cmd.EnableRaisingEvents = True
Application.DoEvents()
AddHandler cmd.ErrorDataReceived, AddressOf OutputHandler
AddHandler cmd.OutputDataReceived, AddressOf OutputHandler
cmd.Start()
cmd.StandardInput.WriteLine(strCommandLine)
cmd.StandardInput.Flush()
cmd.StandardInput.Close()
cmd.BeginErrorReadLine()
cmd.BeginOutputReadLine()
cmd.Close()
Delegate Sub UpdateTextBoxDelg(text As String)
Public myDelegate As UpdateTextBoxDelg = New UpdateTextBoxDelg(AddressOf UpdateTextBox)
Public Sub UpdateTextBox(text As String)
txtOutput.Text += text & Environment.NewLine
txtOutput.SelectionStart = txtOutput.Text.Length
txtOutput.ScrollToCaret()
End Sub
Private Sub OutputHandler(sender As Object, e As DataReceivedEventArgs)
If Me.InvokeRequired = True Then
Me.Invoke(myDelegate, e.Data)
Else
UpdateTextBox(e.Data)
End If
End Sub

Command Prompt Batchfile output to VB textbox

I have a number of batch files and I'm trying to wrap a GUI around them so they are easily available for some of my users all in one place.
At the moment, I've got 2 buttons and a Textbox. Each button calls the same batch file with a different working directory (though in production, the batch files will be different). At the moment, all it does is call 'DIR /A /B" to list a directory contents.
DIR /A /B
exit
I've got the following code: (Button 2 is identical, but with a different working directory)
Public Class Form1
Dim P As New Process
Dim SW As System.IO.StreamWriter
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
AddHandler P.OutputDataReceived, AddressOf DisplayOutput
P.StartInfo.CreateNoWindow() = True
P.StartInfo.UseShellExecute = False
P.StartInfo.WorkingDirectory = "C:\temp"
P.StartInfo.RedirectStandardInput = True
P.StartInfo.RedirectStandardOutput = True
P.StartInfo.RedirectStandardError = True
P.StartInfo.FileName = "c:\temp\dircmd.cmd"
P.Start()
P.SynchronizingObject = TextBox1
Try
P.BeginOutputReadLine()
TextBox1.Text = TextBox1.Text & vbCrLf & "Begin output" & vbCrLf
SW = P.StandardInput
SW.WriteLine()
MsgBox("WriteLine()")
SW.Dispose()
SW.Close()
MsgBox("StreamWriter Close")
P.WaitForExit()
P.CancelOutputRead()
P.Close()
MsgBox("Process Close")
Catch ex As Exception
MsgBox(ex.ToString())
End Try
End Sub
Private Sub DisplayOutput(ByVal sendingProcess As Object, ByVal output As DataReceivedEventArgs)
Textbox1.AppendText(output.Data() & vbCrLf)
End Sub
My problem is that I'm getting the output from each command, however its getting duplicated. First button, first time works fine. Second button works, but everything is listed twice. Going back to first button, everything is listed 3 times. I initially thought I needed to clear the StreamWriter buffer, but its not repeating old info, its just repeating new info and I'm not sure why.
Begin output
C:\temp>DIR /A /B
bob.txt
dircmd.cmd
LocationRouting.xml
TempFrogsareNOTCool.txt
Test.txt
test2.txt
Test3.txt
C:\temp>exit
Begin output 2
C:\>DIR /A /B
C:\>DIR /A /B
$Recycle.Bin
$Recycle.Bin
Config.Msi
Config.Msi
Documents and Settings
Documents and Settings
<snip>
C:\>exit
C:\>exit
Switch to using a Using construct to instantiate and dispose of the Process:
Option A:
Using P As Process = New Process
P.StartInfo.CreateNoWindow = True
P.StartInfo.UseShellExecute = False
P.StartInfo.WorkingDirectory = "C:\temp"
P.StartInfo.RedirectStandardInput = True
P.StartInfo.RedirectStandardOutput = True
P.StartInfo.RedirectStandardError = True
P.StartInfo.FileName = "c:\temp\dircmd.cmd"
P.Start()
Dim sOutput As String
Using oStreamReader As System.IO.StreamReader = P.StandardOutput
sOutput = oStreamReader.ReadToEnd()
End Using
OutputTextBox.Text = sOutput
P.Close()
End Using
Option B:
Private Sub TestDirOutputButton_Click(sender As System.Object, e As System.EventArgs) Handles TestDirOutputButton.Click
Using P As Process = New Process
AddHandler P.OutputDataReceived, AddressOf DisplayOutput
P.StartInfo.CreateNoWindow() = True
P.StartInfo.UseShellExecute = False
P.StartInfo.WorkingDirectory = "C:\temp"
P.StartInfo.RedirectStandardInput = True
P.StartInfo.RedirectStandardOutput = True
P.StartInfo.RedirectStandardError = True
P.StartInfo.FileName = "c:\temp\dircmd.cmd"
P.Start()
P.SynchronizingObject = OutputTextBox
Try
P.BeginOutputReadLine()
OutputTextBox.Text = OutputTextBox.Text & vbCrLf & "Begin output" & vbCrLf
SW = P.StandardInput
SW.WriteLine()
MsgBox("WriteLine()")
SW.Dispose()
SW.Close()
MsgBox("StreamWriter Close")
P.WaitForExit()
P.CancelOutputRead()
P.Close()
MsgBox("Process Close")
Catch ex As Exception
MsgBox(ex.ToString())
End Try
RemoveHandler P.OutputDataReceived, AddressOf DisplayOutput
End Using
End Sub

Timer will not start a second time

I've got a function:
Private Sub UpdateSch()
Threading.Thread.Sleep(50)
Dim i As Integer = 1
While i = 1
Try
If DataGridView1.Rows.Count > 1 Then
DataGridView1.Rows.Clear()
End If
Using stream As System.IO.FileStream = System.IO.File.OpenRead("Z:\\SchData.txt")
Using reader As New System.IO.StreamReader(stream)
Dim line As String = reader.ReadLine()
While (line IsNot Nothing)
Dim columns = line.Split(";")
line = reader.ReadLine()
Dim index = Me.DataGridView1.Rows.Add()
Me.DataGridView1.Rows(index).SetValues(columns)
End While
End Using
End Using
Button88.Enabled = True
DataGridView1.CurrentCell = DataGridView1.Rows(rowIndex).Cells(colIndex)
i = 0
Catch ex As Exception
Threading.Thread.Sleep(50)
End Try
End While
'Check for local updating
If updatingSch = False Then
DataGridView1.Enabled = False
LockWarning1.Visible = True
lockVar1 = 0
LockTimer1.Start()
Else
updatingSch = False
End If
End Sub
And then I've got a timer:
Private Sub LockTimer1_Tick(sender As Object, e As EventArgs) Handles LockTimer1.Tick
LockWarning1.Visible = False
DataGridView1.Enabled = True
LockTimer1.Stop()
End Sub
The function updateSch is called at form load and whenever the file is changed. It locks the DataGridView, starts the timer which runs for 10 sec, and then unlocks the Datagridview. This all works on load, but when it is called again it locks and never unlocks. The second time around the timer is never started. (I put a break point on the "LockTimer1.Start()" and it is executed the second time, but the LockTimer_Tick event doesn't fire after that)
I've found a soution to my problem. For the life of me I can't figure out why my previous code won't work. What I was able to get working was a Systems.Timers.Timer (instead of System.Windows.Forms.Timer). My code creating the timer looks like this:
Dim LockTimer1 As New System.Timers.Timer()
LockTimer1.Interval = 10000
LockTimer1.AutoReset = False 'Run timer only once
LockTimer1.Start()
AddHandler LockTimer1.Elapsed, AddressOf LockTimer1_Tick
And then the function LockTimer1_tick:
Private Sub LockTimer1_Tick(ByVal sender As Object, ByVal e As ElapsedEventArgs)
LockWarning1.Visible = False
DataGridView1.Enabled = True
Button88.Enabled = True
Button1.Enabled = True
End Sub

VB.NET Process Redirect Output Not Working

I'm trying to redirect the output from a command-line application in VB.NET, and for some reason it fails to redirect the output. Here's my code:
Dim myProcess As Process = New Process
myProcess.StartInfo.FileName = "g++"
myProcess.StartInfo.Arguments = CMDLineCommand
myProcess.StartInfo.UseShellExecute = False
myProcess.StartInfo.RedirectStandardOutput = True
myProcess.StartInfo.RedirectStandardError = True
myProcess.StartInfo.CreateNoWindow = True
myProcess.Start()
Dim output As String = myProcess.StandardOutput.ReadToEnd
myProcess.WaitForExit()
CMDLineOutputTextBox.Text = output
Does anybody know why it's not being redirected? Thanks in advance!
-Neil
EDIT: Here's my full code, in case there's anything weird with my syntax:
Dim myProcess As Process = New Process
myProcess.StartInfo.FileName = "g++"
myProcess.StartInfo.Arguments = CMDLineCommand
myProcess.StartInfo.UseShellExecute = False
myProcess.StartInfo.RedirectStandardOutput = True
myProcess.StartInfo.RedirectStandardError = True
myProcess.StartInfo.CreateNoWindow = True
myProcess.EnableRaisingEvents = True
AddHandler myProcess.OutputDataReceived, AddressOf GotData
myProcess.Start()
CMDLineOutputTextBox.Text = ""
myProcess.BeginOutputReadLine()
Later on...
Private Sub GotData(sendingProcess As Object, outLine As DataReceivedEventArgs)
If Not String.IsNullOrEmpty(outLine.Data) Then
SetText(outLine.Data)
End If
End Sub
Delegate Sub SetTextCallback(value As String)
Private Sub SetText(ByVal value As String)
If Me.CMDLineOutputTextBox.InvokeRequired Then
Dim d As New SetTextCallback(AddressOf SetText)
Me.Invoke(d, New Object() {value})
Else
Me.CMDLineOutputTextBox.Text += value + Environment.NewLine
End If
End Sub
Anything weird?
Your method will work, provided by the time you hit the line where you read the output to the end, all of the output is there. Since you are using g++, I assume that may not always be the case. You will probably be better off using the OutputDataReceived Event and capturing the data from that.
Dim myProcess As Process = New Process
myProcess.StartInfo.FileName = "ping"
myProcess.StartInfo.Arguments = "www.google.com"
myProcess.StartInfo.UseShellExecute = False
myProcess.StartInfo.RedirectStandardOutput = True
myProcess.StartInfo.RedirectStandardError = True
myProcess.StartInfo.CreateNoWindow = True
myProcess.EnableRaisingEvents = True
AddHandler myProcess.OutputDataReceived, AddressOf GotData
myProcess.Start()
myProcess.BeginOutputReadLine()
Then you handle the event like this:
Private Sub GotData(sendingProcess As Object, outLine As DataReceivedEventArgs)
If Not String.IsNullOrEmpty(outLine.Data) Then
SetText(outLine.Data)
End If
End Sub
Delegate Sub SetTextCallback(value As String)
Private Sub SetText(ByVal value As String)
If Me.TextBox3.InvokeRequired Then
Dim d As New SetTextCallback(AddressOf SetText)
Me.Invoke(d, New Object() {value})
Else
Me.TextBox3.Text += value + Environment.NewLine
End If
End Sub
I have noticed the waitforExit seems to make the code lock during the invoke.required check. When I take out the waitforexit it works.