How to start a visible process - vb.net

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

Related

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!

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

Using "process" to call another program. Wanting to pass info back to parent program

I know how to send parameters to the child program via startinfo.arguments. I think I even know how to "listen" to anything the child might "say" via standardoutput.readline. What I don't know is what method to use for the child to "speak" back to the parent. Here is the code I have so far (on the parent side):
Dim proc As Process
Dim bRunProgramWorked As Boolean = True
Try
proc = New Process
Dim procInfo As New ProcessStartInfo
proc.StartInfo.FileName = strPathUpgradeEXE
proc.StartInfo.Arguments = param1 & " " & param2 & " " & param3
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
'proc.StartInfo.WindowStyle = ProcessWindowStyle.Maximized
proc.StartInfo.UseShellExecute = False
proc.StartInfo.CreateNoWindow = True
proc.StartInfo.RedirectStandardOutput = True
'proc.StartInfo.RedirectStandardError = True
proc.Start()
Dim output1 As String = proc.StandardOutput.ReadLine
Dim output2 As String = proc.StandardOutput.ReadLine
proc.WaitForExit()
proc.Close()
proc.Dispose()
Catch ex As Exception
LogIt(strMyBaseID, "Error at trying to run PVT-Export. " & ex.ToString)
bRunProgramWorked = False
End Try
The child process needs to write to Console.Out.

How to run batch commands with dynamic statements?

I am writing code in VB.NET 2.0 and want to run batch commands for FTP using FTP -s:filename command.
I have a Batch file FTP.TXT for FTP Upload. It has the following statements:
OPEN <FPT SERVER IP>
USERNAME
PASSWORD
ASC
CD FOLDERNAME
PUT D:\DRFT000009.TXT FTPDRFTIN.DRFT000009
BYE
I have to dynamically change the filename in the Batch File. Now either I can create a Batch file at runtime and then read it or I got a code to set the input stream of the Process object. But its not working as desired.
This code runs fine but here I read a static batch file FTP.TXT from the computer:
Public Sub FTP4()
Dim psi As ProcessStartInfo
Dim totalerror As String = ""
psi = New ProcessStartInfo()
psi.FileName = "FTP.EXE"
psi.Arguments = " -s:D:\FTP.TXT"
psi.RedirectStandardError = True
psi.RedirectStandardOutput = True
psi.CreateNoWindow = True
psi.WindowStyle = ProcessWindowStyle.Hidden
psi.UseShellExecute = False
Dim process As Process = process.Start(psi)
Dim error2 As String = process.StandardError.ReadToEnd()
totalerror = totalerror & error2
process.WaitForExit()
Response.Write(totalerror)
End Sub
But I want somehow to get the FTP done with custom file name for each request. This is what I tried which is not working:
Public Sub FTP5()
Dim totalerror As String = ""
Dim BatchScriptLines(6) As String
Dim process As New Process
process.StartInfo.FileName = "FTP.EXE"
process.StartInfo.UseShellExecute = False
process.StartInfo.CreateNoWindow = True
process.StartInfo.RedirectStandardInput = True
process.StartInfo.RedirectStandardOutput = True
process.StartInfo.RedirectStandardError = True
process.Start()
process.BeginOutputReadLine()
Using InputStream As System.IO.StreamWriter = process.StandardInput
InputStream.AutoFlush = True
BatchScriptLines(0) = "OPEN <FPT IP ADDRESS>"
BatchScriptLines(1) = "USERNAME"
BatchScriptLines(2) = "PASSWORD"
BatchScriptLines(3) = "ASC"
BatchScriptLines(4) = "CD SFCD40DAT"
BatchScriptLines(5) = "PUT D:\DRFT000006.TXT FTPDRFTIN.DRFT000006"
BatchScriptLines(6) = "BYE"
For Each ScriptLine As String In BatchScriptLines
InputStream.Write(ScriptLine & vbCrLf)
Next
End Using
Dim error2 As String = process.StandardError.ReadToEnd()
totalerror = totalerror & error2
process.WaitForExit()
Response.Write(totalerror)
End Sub
Please advise how I can get the "FTP -s:filename" command executed in this case. Basically I want to do something similar to single line batch file execution which I not able to do.
Being a simple text file with a clear format, you could rewrite the file passing the parameters that need to be dynamically changed
Public Sub FTP4()
' Of course I assume that, at this point your program knows the exact values '
' to pass at the procedure that rebuilds the file'
PrepareFTPFile("D:\DRFT000006.TXT", "USERNAME", "PASSWORD")
' Now you call the original code.....
Dim psi As ProcessStartInfo
Dim totalerror As String = ""
psi = New ProcessStartInfo()
psi.FileName = "FTP.EXE"
psi.Arguments = " -s:D:\FTP.TXT"
....
End Sub
Public Sub PrepareFTPFile(fileToUpload as String, username as string, userpass as string)
Using sw = new StreamWriter("D:\FTP.TXT", False)
sw.WriteLine("OPEN <FPT IP ADDRESS>")
sw.WriteLine(username)
sw.WriteLine(userpass)
sw.WriteLine("ASC")
sw.WriteLine("CD SFCD40DAT")
sw.WriteLine("PUT " + fileToUpload + " FTPDRFTIN." + Path.GetFileNameWithoutExtension(fileToUpdload))
sw.WriteLine("BYE")
End Using
End Sub

cmd process not exiting

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