Cross-thread operation in button property from another function vb.net - vb.net

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

Related

InvokeMember("click") does not trigger WebBrowser.DocumentCompleted event

This old unresolved question seems to relate most to my issue WebBrowser control not responding to InvokeMember("click")
The main difference is where the conversation petered out, my webpage does respond to ContentPlaceHolder1_btnComtrsView.click() correctly, where in the original question it did not.
I am trying to pull up a lat/long result after clicking the "View" button after entering in a value for COMTRS (use "M11S19E20" for example): https://www.earthpoint.us/TownshipsCaliforniaSearchByDescription.aspx
I've got the 2 separate document completed event handlers working correctly and all of that. So is it possible to handle the event of the document updating after clicking view? My code does work if I just click once to load the page and click, and a second time to pull the data out.
WebBrowserTRS.ScriptErrorsSuppressed = True
AddHandler WebBrowserTRS.DocumentCompleted, AddressOf ClickViewButton
WebBrowserTRS.Navigate("https://www.earthpoint.us/TownshipsCaliforniaSearchByDescription.aspx")
Private Sub ClickViewButton(sender As Object, e As WebBrowserDocumentCompletedEventArgs)
If e.Url.ToString() = "about:blank" Then Return
RemoveHandler WebBrowserTRS.DocumentCompleted, AddressOf ClickViewButton
Dim trsDoc As HtmlDocument = WebBrowserTRS.Document
Dim elem_Input_Submit As HtmlElement = trsDoc.GetElementById("ContentPlaceHolder1_btnComtrsView")
trsDoc.GetElementById("ContentPlaceHolder1_Comtrs").InnerText = _comtrs
AddHandler WebBrowserTRS.DocumentCompleted, AddressOf GetLatLong
elem_Input_Submit.InvokeMember("click")
End Sub
Private Sub GetLatLong(sender As Object, e As WebBrowserDocumentCompletedEventArgs)
RemoveHandler WebBrowserTRS.DocumentCompleted, AddressOf GetLatLong
Dim trsDoc As HtmlDocument = WebBrowserTRS.Document
Dim centroidFound As Boolean = False
For Each el As HtmlElement In trsDoc.GetElementsByTagName("tr")
Dim val As String
For Each el1 As HtmlElement In el.GetElementsByTagName("TD")
val = el1.InnerText
If val IsNot Nothing AndAlso val.Contains("Centroid") Then
centroidFound = True
' ...
WebBrowserTRS = New WebBrowser
Return
End If
Next
Next
If Not centroidFound Then
MsgBox("Unable to parse the township and range.",
MsgBoxStyle.Information, "Error in location lookup")
End If
Cursor = Cursors.Default
toolstripViewMap.Enabled = True
End Sub

qwinsta /server in vb.net Display result in DataGridView

It is necessary to execute the batch file command -
qwinsta /server:NamePC
and display the result in a DataGridView.
I'm using the following code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim p As New Process
p.StartInfo.FileName = "cmd.exe"
p.StartInfo.Arguments = "/c qwinsta /server:" & TextBox1.Text & ""
p.StartInfo.UseShellExecute = False
p.StartInfo.CreateNoWindow = True
p.StartInfo.RedirectStandardOutput = True
p.StartInfo.RedirectStandardError = True
p.StartInfo.StandardOutputEncoding = System.Text.Encoding.GetEncoding(866)
p.StartInfo.StandardErrorEncoding = System.Text.Encoding.GetEncoding(866)
p.Start()
Dim Result As String = p.StandardOutput.ReadToEnd
If Result.Length < 1 Then
MsgBox(p.StandardError.ReadToEnd)
Exit Sub
End If
p.WaitForExit(3000)
SplitOutput(Result)
End Sub
Sub SplitOutput(ByVal text As String)
Try
Dim source() As String = Split(text, Chr(13))
For i = 0 To UBound(source)
Dim r() As String = source(i).Split(New Char() {" "}, StringSplitOptions.RemoveEmptyEntries)
DataGridView1.Rows.Add(r(0), r(1), r(2), r(3), r(4), r(5))
Next
Catch ex As Exception
End Try
End Sub
But the output procedure in the DataGridView does not work correctly. It displays only the title of the result.
Most likely I'm not splitting the line correctly. What could be wrong?
It's not necessary to use cmd.exe. However, on 64-bit Windows, "qwinsta.exe" only exists in %windir%\System32 - not in %windir%\SysWOW64.
If your application is running as 32-bit on 64-bit Windows, it's necessary to use Sysnative in the path:
Dim qwistaPath As String = System.IO.Path.Combine(Environment.GetEnvironmentVariable("windir"), "Sysnative", "qwinsta.exe")
If your application is running as 64-bit on 64-bit Windows (or 32-bit on 32-bit Windows), use the following:
Dim qwistaPath As String = System.IO.Path.Combine(Environment.GetEnvironmentVariable("windir"), "System32", "qwinsta.exe")
Try the following:
Private Sub GetQwinstaInfo(Optional arguments As String = Nothing, Optional encoding As System.Text.Encoding = Nothing)
Debug.WriteLine("Is64BitProcess: " & Environment.Is64BitProcess.ToString())
Dim qwistaPath As String
'environment variable windir has the same value as SystemRoot
'use 'Sysnative' to access 64-bit files (in System32) if program is running as 32-bit process
'use 'SysWow64' to access 32-bit files on 64-bit OS
'on 64-bit OS, 'qwinsta.exe' only exists in %windir%\System32 - not in SysWOW64
If Environment.Is64BitOperatingSystem AndAlso Not Environment.Is64BitProcess Then
qwistaPath = System.IO.Path.Combine(Environment.GetEnvironmentVariable("windir"), "Sysnative", "qwinsta.exe")
Else
qwistaPath = System.IO.Path.Combine(Environment.GetEnvironmentVariable("windir"), "System32", "qwinsta.exe")
End If
Dim psInfo As ProcessStartInfo = New ProcessStartInfo(qwistaPath)
psInfo.Arguments = arguments 'arguments
psInfo.CreateNoWindow = True 'don't create a window
If encoding IsNot Nothing Then
psInfo.StandardErrorEncoding = encoding
psInfo.StandardOutputEncoding = encoding
End If
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
'create new instance and set properties
Using p As Process = New Process() With {.EnableRaisingEvents = True, .StartInfo = psInfo}
'subscribe to events (add event handlers)
AddHandler p.ErrorDataReceived, AddressOf P_ErrorDataReceived
AddHandler p.OutputDataReceived, AddressOf P_OutputDataReceived
'start
p.Start()
'begin async reading for both standard error and standard output
p.BeginErrorReadLine()
p.BeginOutputReadLine()
'wait until the process is finished before continuing
p.WaitForExit()
'unsubscribe from events (remove event handlers)
RemoveHandler p.ErrorDataReceived, AddressOf P_ErrorDataReceived
RemoveHandler p.OutputDataReceived, AddressOf P_OutputDataReceived
End Using
'ToDo: add desired code
End Sub
Private Sub P_ErrorDataReceived(sender As Object, e As DataReceivedEventArgs)
If Not String.IsNullOrEmpty(e.Data) Then
'ToDo: add desired code
Debug.WriteLine("error: " & e.Data)
End If
End Sub
Private Sub P_OutputDataReceived(sender As Object, e As DataReceivedEventArgs)
If Not String.IsNullOrEmpty(e.Data) Then
'ToDo: add desired code
Debug.WriteLine("output: " & e.Data)
End If
End Sub
Usage - Example #1:
GetQwinstaInfo()
Usage - Example #2:
GetQwinstaInfo(arguments:="/server:myServerNameOrPCName")
Usage - Example #3:
GetQwinstaInfo("/server:myServerNameOrPCName", System.Text.Encoding.GetEncoding(866))

How to run an external script using visual basic?

I want to make a Windows application using visual basic and visual studio 2017.
Here I want to run an external Python script which will run when 'Button 1' is pressed in the windows form. It will take input from the Textbox in the form and do some calculations and then return the result and put it back in the Textbox in the form.
The python code can be either this :
r = input()
p = 2*3.14*r
print(p) #Instead of print(p) something that can return the value to the form
OR This:
def peri(r):
p = 2*3.14*r
return p
I managed to find this solution for you and i really hope it works:
1.Write your python code , for example : print("Hello world python !!") in text file and save to .py
2.Create project at VB.NET, drag component 1 button and 1 textbox into form.
3.Double click button1, at event click button1 write this code
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim proc As Process = New Process
proc.StartInfo.FileName = "C:\Python34\python.exe" 'Default Python Installation
proc.StartInfo.Arguments = pathmypythonfile.py
proc.StartInfo.UseShellExecute = False 'required for redirect.
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden 'don't show commandprompt.
proc.StartInfo.CreateNoWindow = True
proc.StartInfo.RedirectStandardOutput = True 'captures output from commandprompt.
proc.Start()
AddHandler proc.OutputDataReceived, AddressOf proccess_OutputDataReceived
proc.BeginOutputReadLine()
proc.WaitForExit()
TextBox1.Text = Value
End Sub
Public sub proccess_OutputDataReceived(ByVal sender As Object, ByVal e As DataReceivedEventArgs)
On Error Resume Next
If e.Data = "" Then
Else
Value = e.Data
End If
End sub
4. Create module file, and write this variable global :
Module module
Public Value As String
End Module
5. Running the application, if textbox1 have populated with some string then your code was success.
HERE is a lick with the full process.
This is the answer by #Dimitar_Georgiev, with small corrections and formatting fixes.
I managed to find this solution for you and i really hope it works:
Write your python code , for example : print("Hello world python !!") in text file and save to .py
Create project at VB.NET, drag component 1 button and 1 textbox into form.
Double click button1, at event click button1 write this code
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim proc As Process = New Process
proc.StartInfo.FileName = "C:\Python34\python.exe" 'Default Python Installation
proc.StartInfo.Arguments = "C:\path\to\my\pythonfile.py"
proc.StartInfo.UseShellExecute = False 'required for redirect.
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden 'don't show commandprompt.
proc.StartInfo.CreateNoWindow = True
proc.StartInfo.RedirectStandardOutput = True 'captures output from commandprompt.
proc.Start()
AddHandler proc.OutputDataReceived, AddressOf proccess_OutputDataReceived
proc.BeginOutputReadLine()
proc.WaitForExit()
TextBox1.Text = Value
End Sub
Public sub proccess_OutputDataReceived(ByVal sender As Object, ByVal e As DataReceivedEventArgs)
On Error Resume Next
If e.Data = "" Then
Else
Value = e.Data
End If
End sub
Create module file, and write this variable global :
Module module
Public Value As String
End Module
Running the application, if textbox1 have populated with some string then your code was success.
HERE is a lick with the full process.

Wait until download is complete before starting other tasks

I am trying to download a file, and then run some adb commands. However when downloading, i could not get it to update the progress bar using
downloadFile(url,filename)` command.
A bit of searching it said that the command was blocking the UI thread, so i decided to use Task.Run() (a solution to my previous post to run ADB Commands when it blocked the UIThread).
This made no difference. Another solution that i found is to use
downloadFileAsync(url, filename)
The progress bar is updating!
But, the ADB commands are running before the file is downloaded! They are declared after, but they are still being run before the file is downloaded, which I don't want.
Here is the code:
Private Sub btnFlashRecovery_Click(sender As Object, e As EventArgs) Handles btnFlashRecovery.Click
'Insert ommited Code here (removed to simplify question)
'id is variable obtained from a previous code that was ommited here
Dim fileName As String = "downloads/twrp-" & id & ".img"
DownloadFile(url, fileName)
'run the right commands
LabelToOutput = txtBoxRecovery
Dim commands(3, 3) As String
commands = {{"adb", "reboot bootloader", "Rebooting to bootloader"},
{"fastboot", "flash recovery" & "downloads/twrp-3.1.1-0.img", "Flashing recovery: (make sure device is plugged, otherwise it will not output anything)"},
{"fastboot", "reboot", "Rebooting device"}
}
'Task to run after
Task.Run(Sub() runComands(commands))
End Sub
Private Sub UpdateProgressBar(ByVal a As Integer)
If Me.InvokeRequired Then
Dim args() As String = {a}
Me.Invoke(New Action(Of String)(AddressOf UpdateProgressBar), args)
Return
End If
ProgressBar1.Value = CInt(a)
End Sub
Public Sub DownloadFile(urlAddress As String, location As String)
Using webClient = New WebClient()
AddHandler webClient.DownloadFileCompleted, AddressOf Completed
AddHandler webClient.DownloadProgressChanged, AddressOf ProgressChanged
Try
' Start downloading the file
webClient.DownloadFileAsync(New Uri(urlAddress), location)
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Using
End Sub
' The event that will fire whenever the progress of the WebClient is changed
Private Sub ProgressChanged(sender As Object, e As DownloadProgressChangedEventArgs)
'Console.WriteLine(e.ProgressPercentage)
' Update the progressbar percentage only when the value is not the same.
UpdateProgressBar(e.ProgressPercentage)
End Sub
' The event that will trigger when the WebClient is completed
Private Sub Completed(sender As Object, e As AsyncCompletedEventArgs)
If e.Cancelled = True Then
MessageBox.Show("Download has been canceled.")
Else
MessageBox.Show("Download completed!")
End If
End Sub
Do it like this:
'Need Async keyword with the method
Private Async Sub btnFlashRecovery_Click(sender As Object, e As EventArgs) Handles btnFlashRecovery.Click
'Insert ommited Code here (removed to simplify question)
'id is variable obtained from a previous code that was ommited here
Dim fileName As String = "downloads/twrp-" & id & ".img"
'You need to AWAIT the result of the task
Await Task.Run(Sub() DownloadFile(url, fileName))
'run the right commands
LabelToOutput = txtBoxRecovery
Dim commands(3, 3) As String
commands = { {"adb", "reboot bootloader", "Rebooting to bootloader"},
{"fastboot", "flash recovery" & "downloads/twrp-3.1.1-0.img", "Flashing recovery: (make sure device is plugged, otherwise it will not output anything)"},
{"fastboot", "reboot", "Rebooting device"}
}
'Task to run after
'Await here, too, to allow the UI to remain responsive
Await Task.Run(Sub() runComands(commands))
End Sub

How to Know the Process Name at Process Exited Event

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.