cmd process not exiting - vb.net

I was running the following code to execute commands from vb.net app.
Dim CMDServer As Diagnostics.ProcessStartInfo
Dim CMDReply As Diagnostics.Process
CMDServer = New Diagnostics.ProcessStartInfo
CMDServer.WorkingDirectory = "C:/"
CMDServer.FileName = "cmd.exe"
CMDServer.UseShellExecute = False
CMDServer.RedirectStandardOutput = True
CMDServer.RedirectStandardError = True
CMDServer.CreateNoWindow = True
CMDServer.Arguments = "/C " + command
CMDReply = Process.Start(CMDServer)
MsgBox("START")
Dim Reply As String = ""
If Not CMDReply.HasExited Then
CMDReply.WaitForExit()
End If
MsgBox("EXIT")
Try
Dim ext = CMDReply.ExitCode
Reply = CMDReply.StandardOutput.ReadToEnd()
MsgBox(ext.ToString + " " + Reply)
Catch ex As Exception
MsgBox(ex.ToString)
End Try
it works fine for almost all commands, but when the command="help" the program stucks on CMDReply.WaitForExit(). Can anyone explain what may be the problem here?

Standard deadlock. Read the output first and then wait for exit. The
program cannot exit until you've read all of its output. The code you
have can only work if there's little output that fits the buffer.
From Hans Passant's comment

Related

richtextbox for = i multiple function

I am looking for the answer to my question, here I clearly explain the situation to you.
I have a richtextbox, and 10 lines included.
line1
line2
line3
line4
line5
..
line10
and i am doing this;
For i = 0 to richtextbox.Lines.Count = - 1
Button1_Click;
Dim getlist as Process = Process.Start("cmd", "commands" + richtextbox.Lines(i))
getlist.WaitForExit()
Next
I tried this but it didn't work;
Dim getlist as Process = Process.Start("cmd", "commands" + richtextbox.Lines(i))
Dim getlist2 as Process = Process.Start("cmd", "commands" + richtextbox.Lines(i + 1))
when I do this, it gets like;
first: richtextbox line 0 and line 1
and getlist starts line1 and getlist2 starts line2
I want it to be like;
getlist: line0
getlist2: line1
and who finishes earlier, the function starts to get new line;
for example:
getlist: line0-line2-line3-line5
getlist2: line1-line4-line6
how could I do this? thanks a lot for all answers!
In order to do this, you'll need to use some sort of threading-based solution to execute in parallel. Probably the most straightforward of these is to use Task-based asynchronous methods.
This would end up looking something like this:
Dim T1 = Task.Run(Sub()
Dim getlist as Process = Process.Start("cmd", "commands" & richtextbox.Lines(1))
getlist.WaitForExit()
End Sub)
Dim T2 = Task.Run(Sub()
Dim getlist as Process = Process.Start("cmd", "commands" & richtextbox.Lines(2))
getlist.WaitForExit()
End Sub)
Then, you would be able to use various approaches to wait for one or both tasks to finish. If you mark the containing routine as Async you could Await either T1 or T2. You can also Await Task.WhenAny to continue as soon as either one finishes.
I would strongly recommend reading the MSDN documentation on Task-based asynchrony. In particular, you should read "Implementing the Task-based Asynchronous Pattern", as the sections on Interleaving and Throttling are likely to be applicable to what you want to do. Unfortunately, the examples are all in C# in my copy of the online help, but the material should be straightforward to translate to VB.
If I understand your intention, this is the perfect application for threading. This works - I just wrote it, compiled it and ran it. To see it do some simple tasks in separate threads, running just 2 threads at a time until all commands have been executed, just enter valid shell commands into your richtextbox1. To test it, I used:
Echo A
Echo B
Echo C
Echo D
NOTES:
I appended a PAUSE into the CMD arguments, so you can see clearly what's happening.
Threading has a lot of nuances that I can't begin to get into here such as ApartmentState, but it's something that you'll want to educate yourself about.
I'm no guru, and I'm sure there are some more elegant ways to handle some of this 😄
Hope this helps!
Imports System.Threading
Public Class Form1
Dim Thread1 As Thread
Dim Thread2 As Thread
Dim Thread1cmd As String = ""
Dim Thread2cmd As String = ""
Dim Thread1Running As Boolean = False
Dim Thread2Running As Boolean = False
Dim LastCmd As Int32 = -1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
LastCmd = -1
While LastCmd < RichTextBox1.Lines.Count
If Thread1Running = False And (LastCmd + 1) < RichTextBox1.Lines.Count Then
LastCmd += 1
Thread1cmd = RichTextBox1.Lines(LastCmd)
output.Text += LastCmd.ToString + " Thread 1: " + Thread1cmd + vbCrLf
Thread1 = New Thread(AddressOf Thread1Helper)
Thread1.IsBackground = True
Thread1.Start()
End If
If Thread2Running = False And (LastCmd + 1) < RichTextBox1.Lines.Count Then
LastCmd += 1
Thread2cmd = RichTextBox1.Lines(LastCmd)
output.Text += LastCmd.ToString + " Thread 2: " + Thread2cmd + vbCrLf
Thread2 = New Thread(AddressOf Thread2Helper)
Thread2.IsBackground = True
Thread2.Start()
End If
'Note - there is debate around the DoEvents that follows, so experiment with it and see what works best for you
Application.DoEvents()
'the main thread now sleeps to give helper threads time to do some work:
System.Threading.Thread.Sleep(200)
End While
End Sub
Sub Thread1Helper()
Thread1Running = True
Dim p1 As System.Diagnostics.Process
Try
p1 = New System.Diagnostics.Process
Dim MyCMD As String = Environment.GetFolderPath(Environment.SpecialFolder.System) + "\cmd"
p1.StartInfo.FileName = MyCMD
p1.StartInfo.Arguments = " /c " + """" + Thread1cmd + "&&PAUSE" + """"
'MsgBox(p1.StartInfo.FileName.ToString)
p1.Start()
p1.WaitForExit()
p1.Close()
Catch ex As Exception
MsgBox(ex.ToString)
End Try
Thread1Running = False
End Sub
Sub Thread2Helper()
Thread2Running = True
Dim p2 As System.Diagnostics.Process
Try
p2 = New System.Diagnostics.Process
Dim MyCMD As String = Environment.GetFolderPath(Environment.SpecialFolder.System) + "\cmd"
p2.StartInfo.FileName = MyCMD
p2.StartInfo.Arguments = " /c " + """" + Thread2cmd + "&&PAUSE" + """"
'MsgBox(p2.StartInfo.FileName.ToString)
p2.Start()
p2.WaitForExit()
p2.Close()
Catch ex As Exception
MsgBox(ex.ToString)
End Try
Thread2Running = False
End Sub
End Class

standard outputread does not read anything until process is closed vb.net

I am trying to redirect the output from xfoil.exe with downloadables here. The issue is when I am redirecting the standardoutput, my code will not read anything until I use the "quit" command which closes the external xfoil.exe and hence, I cannot run any further commands.
first defining variables
Dim p as process = New Process()
Dim startinfo = New ProcessStartInfo()
Dim bt As Threading.Thread
I start the process using
With startinfo
.FileName = Application.StartupPath & "\appdata\xfoil.exe"
.Arguments = ""
.WorkingDirectory = Application.StartupPath
.RedirectStandardError = True
.RedirectStandardOutput = True
.RedirectStandardInput = True
.UseShellExecute = False
.CreateNoWindow = True
End With
p.StartInfo = startinfo
p.EnableRaisingEvents = True
If Not IsNothing(bt) Then bt.Abort()
bt = New Threading.Thread(AddressOf ReadThread)
bt.IsBackground = True
bt.Start()
p.Start()
The definition for the ReadThread is
Private Sub ReadThread()
Dim rLine As String
Do Until Leaving
Try
rLine = p.StandardOutput.Read()
logtext += (Chr(rLine))
If p.StandardOutput.Peek = -1 Then
Me.Invoke(Sub() txtLog.AppendText(logtext))
logtext = ""
End If
Catch ex As Exception
Console.WriteLine("error " & ex.Message)
End Try
Loop
End Sub
This setup works perfectly with another app from the same developer Mark Drela. When I use the other app AVL with download link here everything works fine. However, xfoil does not work with this setup and I have spent some hours on this without any luck. I am using VB.net on Windows 10 in Visual Studio.NET 2019 community edition.
Edit
Both methods using threading and events were implemented and no luck.
A sample code using both methods in VB.net is now available on Github for review comments. Let me know if anyone has any experience with this and can help. This would really help my students in the class!

VB.Net shell output sometimes not returning

for 99% of all my Shell commands this code works fine, but for just one command I don't get the returned text, which is normally visible in the Shell window. Here is the code I use to execute commands and read back the results:
Function RunCommandCom(command As String, arguments As String) As String()
Dim p As Process = New Process()
Dim pi As ProcessStartInfo = New ProcessStartInfo()
Dim output As String
pi.Arguments = " " + "/c" + " " + command + " " + arguments
pi.FileName = "cmd.exe"
pi.RedirectStandardOutput = True 'pi.CreateNoWindow = True
pi.WindowStyle = ProcessWindowStyle.Normal
pi.UseShellExecute = False
p.StartInfo = pi
p.Start()
output = p.StandardOutput.ReadToEnd()
p.WaitForExit()
p.Close()
If output Is ""
Then
Return Nothing
Else
Return output.Replace(Chr(13), "").Split(Chr(10))
End If
End Function
The command making Problems is executed fine. It shall create a entry in a database, which defintly is existing after calling my funciton. Executing the command directly in a Shell generates the same entry and I can see the returned text.
Does anyone has an idea why the streamreader does not read/contain anything for exactly this one special command?
Arg. I found the problem. These two commands send their output to the StandardError stream. I don't know why, as no error occured.

Process.Start() with "manage-bde.exe" crashing in VB.NET

I'm trying to start manage-bde.exe as a new process in VB.net but when it tries to start the proc, Bitlocker crashes. Could anyone please tell me what I'm doing wrong here? This code was converted from C# where it works all day long....
Code:
Private Sub btnLock_Click(sender As Object, e As EventArgs) Handles btnLock.Click
Dim drvSelected As String = cmbDriveSelect.SelectedValue.ToString()
Dim sysDirWithBDE As String = Environment.SystemDirectory + "\manage-bde.exe"
Dim lockStatus As String = String.Empty
' This is the code for the base process
Dim myProcess As New Process()
' Start a new instance of this program
Dim myProcessStartInfo As New ProcessStartInfo(sysDirWithBDE, " -lock " + drvSelected.Remove(2))
'Set Use Shell to false so as to redirect process run info to application
myProcessStartInfo.UseShellExecute = False
myProcessStartInfo.RedirectStandardOutput = True
myProcess.StartInfo = myProcessStartInfo
Try
myProcess.Start()
lblDriveLockMsg.Show()
Catch err As Exception
lblDriveLockMsg.Text = err.Message
End Try
'Read the standard output of the process.
lockStatus = myProcess.StandardOutput.ReadToEnd()
If lockStatus.Contains("code 0x80070057") Then
lblDriveLockMsg.Text = "Drive selected is not Bit Locker encrypted"
ElseIf lockStatus.Contains("code 0x80070005") Then
lblDriveLockMsg.Text = "Drive selected is in use by an application on your machine, force dismounting might result in data loss, please check and close any applications using the drive"
Else
lblDriveLockMsg.Text = lockStatus
End If
myProcess.WaitForExit()
myProcess.Close()
End Sub

How to start a visible process

I have the following code to start the program R (even though I think that the program is not relevent for the problem here) and run a script:
Public Shared Sub RunRScript(rCodeFilePath As String, rScriptExecutablePath As String, args As String)
Dim file As String = rCodeFilePath
Dim result As String = String.Empty
Try
Dim info = New ProcessStartInfo()
info.FileName = rScriptExecutablePath
info.WorkingDirectory = Path.GetDirectoryName(rScriptExecutablePath)
info.Arguments = rCodeFilePath & " " & args
info.RedirectStandardInput = False
info.RedirectStandardOutput = True
info.UseShellExecute = False
info.CreateNoWindow = True
Using proc = New Process()
proc.StartInfo = info
proc.Start()
result = proc.StandardOutput.ReadToEnd()
proc.Close()
End Using
Catch ex As Exception
Throw New Exception("R Script failed: " & result, ex)
End Try
End Sub
Problem is, if there is an error in the script I run within R I dont get an error message because the instance is invisible. I tried to make it visible with
.WindowStyle = ProcessWindowStyle.Normal
in all combinations of .UseShellExcecute and .CreateNoWindow but this is not working. Could anyone help me to can make my process visible?
Since you are redirecting StandardInput and StandardOutput, you should now redirect StandardError to trap the errors also.
More info available on MSDN