I run multiple exe with different names by using Process.start() and enables Raisingevents to True. To check the status of Process, I intimated User at Process Exited event and show a message to user.
But the problem is I want to show the particular Exe Name to User at that Exit event. My code for For process Start is:
Private Sub StartExe()
Private psi As ProcessStartInfo
Private cmd As Process
Dim filePath As String = "vision.exe"
psi = New ProcessStartInfo(filePath)
Dim systemencoding As System.Text.Encoding = _
System.Text.Encoding.GetEncoding(Globalization.CultureInfo.CurrentUICulture.TextInfo.OEMCodePage)
With psi
.Arguments = "Some Input String"
.UseShellExecute = False
.RedirectStandardError = True
.RedirectStandardOutput = True
.RedirectStandardInput = True
.CreateNoWindow = False
.StandardOutputEncoding = systemencoding
.StandardErrorEncoding = systemencoding
End With
cmd = New Process With {.StartInfo = psi, .EnableRaisingEvents = True}
AddHandler cmd.ErrorDataReceived, AddressOf Async_Data_Received
AddHandler cmd.OutputDataReceived, AddressOf Async_Data_Received
AddHandler cmd.Exited, AddressOf processExited
cmd.Start()
cmd.BeginOutputReadLine()
cmd.BeginErrorReadLine()
End Sub
'For Receiving the Output of Exe, I used a TextBox to view
Private Sub Async_Data_Received(ByVal sender As Object, ByVal e As DataReceivedEventArgs)
Me.Invoke(New InvokeWithString(AddressOf Sync_Output1), e.Data)
End Sub
Private Sub Sync_Output1(ByVal text As String)
txtLog.AppendText(text & Environment.NewLine)
End Sub
'At the Exit event, I inform the user that an Exe exited due to some reason etc.
Private Sub processExited(ByVal sender As Object, ByVal e As EventArgs)
Me.BeginInvoke(New Action(Function()
MessageBox.Show("The Stream for " &Particular Exe& "is Exited.", "", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
End Function))
End Sub
At the Process Exited Event, how can I show name of that particular Exe which fired that event. Like in that particular code, I started an "vision.exe", So I want to inform the user that vision.exe is terminated due to some reason etc.
By the time the Exited event runs, the process is already dead and you cannot retrieve its properties anymore. Since you already use lambda expressions, you can solve this one too by writing one that captures the filePath variable. Like this:
AddHandler cmd.Exited,
Sub(s, e)
Me.BeginInvoke(New Action(
Sub()
MessageBox.Show(filePath + " has ended")
End Sub))
End Sub
Do beware that you'll have to keep your Form object alive until the process terminates or your own program exits. If you don't then the BeginInvoke() call is going to be made on a disposed form, also a problem in your original code. You can avoid this by checking Me.InvokeRequired. If it returns false then don't do anything.
Related
I am trying to change the state of a button from another function where I use the AddHandler and AddressOf but it turns out that said function does not allow me to make changes to the UI .
Sub Button1Click(sender As Object, e As EventArgs)
CMD_CS("C:\Users\Gabr\Desktop","dir element.docx /s /p")
End Sub
Private Sub CMD_CS(ByVal path As String, ByVal comand As String)
button1.Enabled = False
Dim p As Process = New Process()
Dim ps As ProcessStartInfo = New ProcessStartInfo()
Environment.CurrentDirectory = path
ps.UseShellExecute = True
ps.WindowStyle = ProcessWindowStyle.Hidden
ps.FileName = "cmd"
ps.Arguments = " /c " + comand
p.StartInfo = ps
p.Start()
p.EnableRaisingEvents = True
AddHandler p.Exited, AddressOf PsExit
End Sub
Public Sub PsExit()
Me.button1.Enabled = True ' <---- error Button1 no access
Console.WriteLine("process end")
' get p.StandardOutput.ReadLine
End Sub
It would also be very useful to know the result that the console is throwing at me but I have no idea.
Here I have two objectives, the first is that I do not know how to change the state of the button from the PsExit() function and the second is that in that same function print the results generated by the cmd
Error
System.InvalidOperationException: Cross-thread operation not valid: Control 'button1' accessed from a thread other than the thread it was created on.
There are better ways to check if a file exists, but perhaps you're just using it for testing.
If one needs to update a property for a Button during cross-threaded operations, one can do either of the following:
Option 1: (Action)
Button1.Invoke(New Action(Sub()
Button1.Enabled = True
End Sub))
Option 2: (MethodInvoker)
Button1.Invoke(New MethodInvoker(Sub()
Button1.Enabled = True
End Sub))
The code below shows how to use System.Diagnostics.Process. I've included two different ways of determining whether or not the command being run by Process completed successfully or not.
Using an event named ProcessCompleted. The value of hasSuccessfullyCompleted lets one know if the the operation successfully completed without errors.
Using a return value from the Function. If the return value is "Success", then the operation successfully completed without errors. If an error occurred, the error message is returned.
Create a WinForms project
VS 2017:
Open Visual Studio
Click File
Select New
Select Project
Expand Installed
Expand Visual Basic
Click Windows Desktop
Select Windows Forms App (.NET Framework)
Specify project name (name: ReadSerialPort)
Click OK
VS 2019:
Open Visual Studio
Click Continue without code
Click File
Select New
Select Project
Visual Basic Windows Desktop
Click Windows Forms App (.NET Framework)
Click Next
Specify project name (name: ReadSerialPort)
Click Create
Note: From this point forward, the process is the same for both VS 2017 and VS 2019.
Create a class (name: HelperProcess.vb)
In VS menu, click Project
Select Add Class
For name, enter "HelperProcess.vb"
Click Add
HelperProcess.vb
Public Class HelperProcess
Public Event ErrorDataReceived(sender As Object, data As String)
Public Event OutputDataReceived(sender As Object, data As String)
Public Event ProcessCompleted(sender As Object, hasSuccessfullyCompleted As Boolean)
Private ProcessError As String = String.Empty
Public Function RunCmd(ByVal exePath As String, ByVal Optional arguments As String = Nothing) As String
Dim errMsg As String = String.Empty
'set value
ProcessError = String.Empty
If String.IsNullOrEmpty(exePath) Then
errMsg = "exePath not specified"
Debug.WriteLine(errMsg)
're-initialize
ProcessError = "Error: " & errMsg
Throw New Exception(errMsg)
End If
Try
'create new instance
Dim psInfo As ProcessStartInfo = New ProcessStartInfo(exePath, arguments)
'set properties
psInfo.Arguments = arguments 'arguments
psInfo.CreateNoWindow = True 'don't create a window
psInfo.RedirectStandardError = True 'redirect standard Error
psInfo.RedirectStandardOutput = True 'redirect standard output
psInfo.RedirectStandardInput = False
psInfo.UseShellExecute = False 'If True, uses 'ShellExecute'; if false, uses 'CreateProcess'
psInfo.WindowStyle = ProcessWindowStyle.Hidden
psInfo.ErrorDialog = False
'create new instance - setting the desired properties
Using p As Process = New Process() With {.EnableRaisingEvents = True, .StartInfo = psInfo}
'subscribe to events (add event handlers)
AddHandler p.ErrorDataReceived, AddressOf Process_ErrorDataReceived
AddHandler p.OutputDataReceived, AddressOf Process_OutputDataReceived
'start process
p.Start()
p.BeginErrorReadLine() 'begin async reading for standard error
p.BeginOutputReadLine() 'begin async reading for standard output
'waits until the process is finished before continuing
p.WaitForExit()
'unsubscribe from events (remove event handlers)
RemoveHandler p.ErrorDataReceived, AddressOf Process_ErrorDataReceived
RemoveHandler p.OutputDataReceived, AddressOf Process_OutputDataReceived
End Using
Catch ex As System.ComponentModel.Win32Exception
errMsg = "Error (Win32Exception): " & ex.Message
Debug.WriteLine(errMsg)
'set value
ProcessError = errMsg
Throw ex
Catch ex As Exception
errMsg = "Error: " & ex.Message
Debug.WriteLine(errMsg)
'set value
ProcessError = errMsg
Throw ex
End Try
If Not String.IsNullOrEmpty(ProcessError) Then
'raise event
RaiseEvent ProcessCompleted(Me, False)
Return "Error: " & ProcessError
Else
'raise event
RaiseEvent ProcessCompleted(Me, True)
End If
Return "Success"
End Function
Private Sub Process_ErrorDataReceived(sender As Object, e As DataReceivedEventArgs)
'ToDo: add desired code
If Not String.IsNullOrEmpty(e.Data) Then
Debug.WriteLine("Process_ErrorDataReceived: " & e.Data)
If Not String.IsNullOrEmpty(ProcessError) Then
'add space
ProcessError += " "
End If
'append
ProcessError += e.Data
'raise event
RaiseEvent ErrorDataReceived(Me, e.Data)
End If
End Sub
Private Sub Process_OutputDataReceived(sender As Object, e As DataReceivedEventArgs)
'ToDo: add desired code
If Not String.IsNullOrEmpty(e.Data) Then
Debug.WriteLine("Process_OutputDataReceived: " & e.Data)
'raise event
RaiseEvent OutputDataReceived(Me, e.Data)
End If
End Sub
End Class
Open Properties Window
In VS menu, select View
Select Properties Window
Open Solution Explorer
In VS menu, select View
Select Solution Explorer
In Solution Explorer, double-click Form1.vb to open the designer.
Add Buttons to Form1
Add "Run" button to Form1
In VS menu, select View
Select Toolbox
Select Button
Click on Form1 to add the button to the form
In Properties Window, for "button1", set (name): btnRun; set Text: Connect
In Properties Window, click (Events). Double-click Click to add event handler to Form1.vb
Add "Button1" button to Form1
In VS menu, select View
Select Toolbox
Select Button
Click on Form1 to add the button to the form
Add "Load" event handler to Form1
In Properties Window, for "Form1"", click (Events). Double-click Load to add event handler to Form1.vb
Modify Form1.vb code
In Solution Explorer, right-click Form1.vb
Select View Code
Form1.vb
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'set value
Button1.Enabled = False
End Sub
Private Sub btnRun_Click(sender As Object, e As EventArgs) Handles btnRun.Click
'set value
Button1.Enabled = False
Dim helper As New HelperProcess
'subscribe to events (add event handlers)
AddHandler helper.ErrorDataReceived, AddressOf Helper_ErrorDataReceived
AddHandler helper.OutputDataReceived, AddressOf Helper_OutputDataReceived
AddHandler helper.ProcessCompleted, AddressOf Helper_ProcessCompleted
'set value
Dim folderName As String = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
Dim filename As String = System.IO.Path.Combine(folderName, "element.docx")
Dim arguments As String = String.Format("/c dir ""{0}"" | find /v ""Volume"" | find /v ""Directory of"" | find /v ""bytes"" ", filename)
'execute
Dim result As String = helper.RunCmd("cmd", arguments)
'unsubscribe from events (remove event handlers)
RemoveHandler helper.ErrorDataReceived, AddressOf Helper_ErrorDataReceived
RemoveHandler helper.OutputDataReceived, AddressOf Helper_OutputDataReceived
RemoveHandler helper.ProcessCompleted, AddressOf Helper_ProcessCompleted
'set value
helper = Nothing
Debug.WriteLine("result: " & result)
If result = "Success" Then
Button1.Enabled = True
Else
Button1.Enabled = False
End If
End Sub
Private Sub Helper_ErrorDataReceived(sender As Object, data As String)
'ToDo: add desired code
If Not String.IsNullOrEmpty(data) Then
Debug.WriteLine("Helper_ErrorDataReceived: " & data)
End If
End Sub
Private Sub Helper_OutputDataReceived(sender As Object, data As String)
'ToDo: add desired code
If Not String.IsNullOrEmpty(data) Then
Debug.WriteLine("Helper_OutputDataReceived: " & data)
End If
End Sub
Private Sub Helper_ProcessCompleted(sender As Object, hasSuccessfullyCompleted As Boolean)
'ToDo: add desired code and/or uncomment desired code below
Debug.WriteLine("hasSuccessFullyCompleted: " & hasSuccessfullyCompleted.ToString())
If hasSuccessfullyCompleted Then
'Button1.Invoke(New MethodInvoker(Sub()
'Button1.Enabled = True
'End Sub))
'Button1.Invoke(New Action(Sub()
'Button1.Enabled = True
'End Sub))
Else
'Button1.Invoke(New MethodInvoker(Sub()
'Button1.Enabled = False
'End Sub))
'Button1.Invoke(New Action(Sub()
'Button1.Enabled = False
'End Sub))
End If
End Sub
End Class
I simpily made a consol app which is a TCP-server if i start the normal way like go to the .exe and start with click it works normaly soo not that is the problem as i think. What i want to do is just read the last line from that consol Here is my code
I got this code from another website
Sub Go()
Dim p As New Process
p.StartInfo.FileName = mainloc & "\ut\server.exe"
p.StartInfo.UseShellExecute = False
p.StartInfo.RedirectStandardOutput = True
AddHandler p.OutputDataReceived, AddressOf HelloMum
MsgBox(p.StartInfo.FileName.ToString)
p.Start()
p.BeginOutputReadLine()
End Sub
Sub HelloMum(ByVal sender As Object, ByVal e As DataReceivedEventArgs)
UpdateTextBox(e.Data)
End Sub
Private Delegate Sub UpdateTextBoxDelegate(ByVal Text As String)
Private Sub UpdateTextBox(ByVal Tex As String)
If Me.InvokeRequired Then
Dim del As New UpdateTextBoxDelegate(AddressOf UpdateTextBox)
Dim args As Object() = {Tex}
Me.Invoke(del, args)
Else
RichTextBox1.Text &= Tex & Environment.NewLine
End If
End Sub
And my problem is when i start this code with the Go sub the consol app show up for a second then it close by that second before it close it read the first two line then close, Before you ask in the consol app there is this line Console.ReadLine()
I am totally have no idea what i can do.
Thanks for any help
I am using webbrowser to navigate to a website then automating the login. Everything works perfectly up until the point of the comment "Navigating Event" After entering one credential it will login and navigate to another website. After the event none of the code will work as it is not picking up the new site. I am using a waitforpageload() function to let me know when it is completed loading however when I check the url it is still pointing to the original site. Any ideas why it would be doing this and how to possibly get around it?
Private Property pageready As Boolean = False
webBrowser1.Navigate("https://www.lamedicaid.com/sprovweb1/provider_login/provider_login.asp")
waitforpageload()
Dim allelements As HtmlElementCollection = webBrowser1.Document.All
For Each webpageelement As HtmlElement In allelements
'NPI #
If webpageelement.GetAttribute("name") = "Provider_Id" Then
webpageelement.SetAttribute("value", "xxxxxx")
End If
'Clicking enter to input NPI
If webpageelement.GetAttribute("name") = "submit1" Then
webpageelement.InvokeMember("focus")
webpageelement.InvokeMember("click")
waitforpageload()
End If
'Navigation event happens here
'Entering username
If webpageelement.GetAttribute("name") = "Login_Id" Then
webpageelement.SetAttribute("value", "xxxxxxx")
End If
'Entering Password
If webpageelement.GetAttribute("name") = "Password" Then
webpageelement.SetAttribute("value", "xxxxxxxxx")
End If
'logging in
If webpageelement.GetAttribute("name") = "submit_button" Then
webpageelement.InvokeMember("focus")
webpageelement.InvokeMember("click")
waitforpageload()
End If
#Region "Page Loading Functions"
Private Sub waitforpageload()
AddHandler webBrowser1.DocumentCompleted, New WebBrowserDocumentCompletedEventHandler(AddressOf PageWaiter)
While Not pageready
Application.DoEvents()
End While
pageready = False
End Sub
Private Sub PageWaiter(ByVal sender As Object, ByVal e As WebBrowserDocumentCompletedEventArgs)
If webBrowser1.ReadyState = WebBrowserReadyState.Complete Then
pageready = True
RemoveHandler webBrowser1.DocumentCompleted, New WebBrowserDocumentCompletedEventHandler(AddressOf PageWaiter)
End If
End Sub
#End Region
Please, for the love of god, get rid of that waitforpageload() function! Using Application.DoEvents() is BAD PRACTICE and in a loop like that, will utilize 100% of your CPU!
The person who originally wrote that function (it's from another Stack Overflow post) clearly didn't know what he/she was doing at the time. Using Application.DoEvents() creates more problems than it solves, and should NEVER be used in anyone's code (it exists mostly because it is used by internal methods).
Refer to: Keeping your UI Responsive and the Dangers of Application.DoEvents for more info.
The WebBrowser has a dedicated DocumentCompleted event that is raised every time a page (or part of a page, such as an iframe) has been completely loaded.
To make sure that the page really is fully loaded, subscribe to the DocumentCompleted event and check if the ReadyState property is equal to WebBrowserReadyState.Complete.
To be able to run code more "dynamically" when the DocumentCompleted event is raised you can utilize lambda expressions as a way of creating inline methods.
In your case they can be used like this:
'Second step (these must always be in descending order since the first step must be able to reference the second, and so on).
Dim credentialHandler As WebBrowserDocumentCompletedEventHandler = _
Sub(wsender As Object, we As WebBrowserDocumentCompletedEventArgs)
'If the WebBrowser HASN'T finished loading, do not continue.
If webBrowser1.ReadyState <> WebBrowserReadyState.Complete Then Return
'Remove the event handler to avoid this code being called twice.
RemoveHandler webBrowser1.DocumentCompleted, credentialHandler
'Entering username
If webpageelement.GetAttribute("name") = "Login_Id" Then
webpageelement.SetAttribute("value", "xxxxxxx")
End If
'Entering Password
If webpageelement.GetAttribute("name") = "Password" Then
webpageelement.SetAttribute("value", "xxxxxxxxx")
End If
'logging in
If webpageelement.GetAttribute("name") = "submit_button" Then
webpageelement.InvokeMember("focus")
webpageelement.InvokeMember("click")
End If
End Sub
'First step.
Dim loginHandler As WebBrowserDocumentCompletedEventHandler = _
Sub(wsender As Object, we As WebBrowserDocumentCompletedEventArgs)
'If the WebBrowser hasn't finished loading, do not continue.
If webBrowser1.ReadyState <> WebBrowserReadyState.Complete Then Return
'Remove the event handler to avoid this code being called twice.
RemoveHandler webBrowser1.DocumentCompleted, loginHandler
Dim allelements As HtmlElementCollection = webBrowser1.Document.All
For Each webpageelement As HtmlElement In allelements
'NPI #
If webpageelement.GetAttribute("name") = "Provider_Id" Then
webpageelement.SetAttribute("value", "xxxxxx")
'-- Why would you even wait in here?? There's no reason for you to wait after only changing an attribute since nothing is loaded from the internet.
End If
'Clicking enter to input NPI
If webpageelement.GetAttribute("name") = "submit1" Then
'Adding the event handler performing our next step.
AddHandler webBrowser1.DocumentCompleted, credentialHandler
webpageelement.InvokeMember("focus")
webpageelement.InvokeMember("click")
End If
Next
End Sub
'Add the event handler performing our first step.
AddHandler webBrowser1.DocumentCompleted, loginHandler
webBrowser1.Navigate("https://www.lamedicaid.com/sprovweb1/provider_login/provider_login.asp")
Now every time you need to wait for the document/website to be fully loaded, just declare a new lambda and add it as an event handler to DocumentCompleted:
Dim thirdStepHandler As WebBrowserDocumentCompletedEventHandler = _
Sub(wsender As Object, we As WebBrowserDocumentCompletedEventArgs)
'If the WebBrowser hasn't finished loading, do not continue.
If webBrowser1.ReadyState <> WebBrowserReadyState.Complete Then Return
'Remove the event handler to avoid this code being called twice.
RemoveHandler webBrowser1.DocumentCompleted, thirdStepHandler
'Your goes code here...
End Sub
'To wait until performing the next step (be sure to do this BEFORE navigating):
AddHandler webBrowser1.DocumentCompleted, thirdStepHandler
I am trying to make an application to run multiple (adb specially) commands and get the output and display in a label.
First of all, i need to start the process to execute the commands. Thanks to stackoverflow and #pasty I found this (second reply): How to get Output of a Command Prompt Window line by line in Visual Basic?
Well, i thought that because it outputted to the console, it would be simple to just write it to the label. BIG MISTAKE! It gives me a cross threading error!
A little bit of googling and stack overflow I found this: vb.net accessed from a thread other than the thread it was created on
Well, i tried to implement that, but the program just crashes freezes.
Here is the code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' store error output lines
Dim executable As String() = {"adb", "adb"}
Dim arguments As String() = {"help", "reboot"}
For i As Integer = 0 To 0
Dim process = New Process()
process.StartInfo = createStartInfo(executable(i), arguments(i))
process.EnableRaisingEvents = True
AddHandler process.Exited, Sub(ByVal sendera As Object, ByVal ea As System.EventArgs)
Console.WriteLine(process.ExitTime)
Console.WriteLine(". Processing done.")
'UpdateTextBox(ea)
End Sub
' catch standard output
AddHandler process.OutputDataReceived, Sub(ByVal senderb As Object, ByVal eb As DataReceivedEventArgs)
If (Not String.IsNullOrEmpty(eb.Data)) Then
Console.WriteLine(String.Format("{0}> {1}", DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss"), eb.Data))
'UpdateTextBox(eb.Data)
End If
End Sub
' catch errors
AddHandler process.ErrorDataReceived, Sub(ByVal senderc As Object, ByVal ec As DataReceivedEventArgs)
Console.WriteLine(String.Format("! {0}", ec.Data))
Dim a As String = String.Format("! {0}", ec.Data)
'UpdateTextBox(a)
End Sub
' start process
Dim result = process.Start()
' and wait for output
process.BeginOutputReadLine()
' and wait for errors :-)
process.BeginErrorReadLine()
process.WaitForExit()
Next
End Sub
Private Sub UpdateTextBox(ByVal a As String)
If Me.InvokeRequired Then
Dim args() As String = {a}
Me.Invoke(New Action(Of String)(AddressOf UpdateTextBox), args)
Return
End If
Label1.Text += "a"
End Sub
Private Function createStartInfo(ByVal executable As String, ByVal arguments As String) As ProcessStartInfo
Dim processStartInfo = New ProcessStartInfo(executable, arguments)
processStartInfo.WorkingDirectory = Path.GetDirectoryName(executable)
' we want to read standard output
processStartInfo.RedirectStandardOutput = True
' we want to read the standard error
processStartInfo.RedirectStandardError = True
processStartInfo.UseShellExecute = False
processStartInfo.ErrorDialog = False
processStartInfo.CreateNoWindow = True
Return processStartInfo
End Function
And the source code: https://github.com/iAmAOpenSource/SyncfusionWindowsFormsApplication3
The call to process.WaitForExit() will block the UI thread until the spawned process exits, but while processing the output in the process.OutputDataReceived event you are calling Me.Invoke which tries to run the code on the UI thread, which is blocked, so the program freezes. You could move the logic in Button1_Click onto another thread, e.g.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Task.Run(
Sub()
... current logic
End Sub
)
End Sub
That way the UI thread won't be blocked and the Me.Invoke call won't cause a deadlock.
I'm using this code:
Shared sb_OutputData As New StringBuilder()
Shared sb_ErrorData As New StringBuilder()
Shared proc As Process = Nothing
Private Sub cmd()
If proc IsNot Nothing Then
Exit Sub
End If
Dim info As New ProcessStartInfo("cmd.exe")
' Redirect the standard output of the process.
info.RedirectStandardOutput = True
info.RedirectStandardInput = True
info.RedirectStandardError = True
' Set UseShellExecute to false for redirection
info.UseShellExecute = False
proc = New Process
proc.StartInfo = info
' Set our event handler to asynchronously read the sort output.
AddHandler proc.OutputDataReceived, AddressOf proc_OutputDataReceived
AddHandler proc.ErrorDataReceived, AddressOf proc_ErrorDataReceived
proc.Start()
' Start the asynchronous read of the sort output stream. Note this line!
proc.BeginOutputReadLine()
proc.BeginErrorReadLine()
End Sub
Private Shared Sub proc_ErrorDataReceived(sender As Object, e As DataReceivedEventArgs)
'Console.WriteLine("Error data: {0}", e.Data)
sb_ErrorData.AppendLine(e.Data)
End Sub
Private Shared Sub proc_OutputDataReceived(sender As Object, e As DataReceivedEventArgs)
' Console.WriteLine("Output data: {0}", e.Data)
sb_OutputData.AppendLine(e.Data)
End Sub
Sub CmdWrite(arguments As String)
Dim writeStream As StreamWriter = proc.StandardInput
writeStream.WriteLine(arguments)
End Sub
It works exactly as I want, be able to retrieve cmd output and error data without closing it (and asynchronously), however, I'm not able to know when the command is finished executing. I'd like to know when it reaches the end of the stream for me to grab all the output and do something with it...
I've been searching for quite long, and can't find an answer to this.
Help please?
The stream is open is long as the command window is open. You can't tell when they stop or start. If the command you're running doesn't indicate its end with a unique/detectable pattern, you're stuck, unless you can edit the script you're running and insert a string - which you can't guarantee won't show in the normal output - in between the command calls.