I want to detect if a target process has ended or not. I have written the expected sequence below:
A process named TEST runs at the background.
Status.Text = "Running" to indicate process is running.
Process ends by itself.
Status.Text = "Finished" right after the process ends.
Unfortunately, the solution posted here requires to be run as administrator.
A simple polling-solution using a timer could do the work just fine.
If you use a polling solution, then of course you have to re-read the processes inside the loop or polling event.
Use the process name without .exe here.
Private timer_watcher As Timer
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.Label1.Text = "Watching"
Me.timer_watcher = New Timer
AddHandler timer_watcher.Tick, AddressOf TimerEvent
timer_watcher.Interval = TimeSpan.FromSeconds(1).TotalMilliseconds
timer_watcher.Start()
End Sub
Public Sub TimerEvent(sender As Object, e As EventArgs)
Dim p() As Process = System.Diagnostics.Process.GetProcessesByName("processname")
If p.Length = 0 Then
timer_watcher.Stop()
Me.Label1.Text = "Stopped"
End If
End Sub
Consider using the Process.Exited event.
Related
I'm new to the programming world.
I'm trying to make a simple software which will go through 5-6 forms (showing the progress bar as a picture) and on each form display progress as a picture while some other code is being run in the background. I've written my code and it just keeps looping the application for some reason and I don't know how to stop it from looping.
As I said, I'm new to visual basic and programming world, so please just go easy on me, thanks!
I just need help with stopping the timer after the HandleTimerTick() happens. I don't know how to call the timer to stop, from the previous sub or something. So, I just need a command to stop t.Tick once HandleTimerTick from the second sub starts.
If you have any simpler command to stop the code from executing for the number of seconds feel free to share. Thanks in advance!
Private Sub Delay1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim t As Timer = New Timer()
t.Interval = 2000
AddHandler t.Tick, AddressOf HandleTimerTick
t.Start()
End Sub
Private Sub HandleTimerTick()
Dim SecondForm As New Delay2
SecondForm.Show()
Me.Close()
End Sub
Use the proper signature for the Event handler In this way you get a reference to the Timer that trigger the event handler and you can stop it
Private Sub HandleTimerTick(sender As Object, e As EventArgs)
... your code to handle the event
' Stop the timer
Dim t As System.Windows.Forms.Timer
t = DirectCast(sender, System.Windows.Forms.Timer)
t.Stop
End Sub
I'm new to Visual Basic and overall kind of new to coding in general.
Currently I work on a program which uses a filewatcher. But If I try this:
Public Class Form1
Private WithEvents fsw As IO.FileSystemWatcher
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
fsw = New IO.FileSystemWatcher("PATH")
fsw.EnableRaisingEvents = True
' fsw.Filter = "*.settings"
End Sub
Private Sub GetSettingsFromFile()
Some Code
More Code
CheckBox1.Checked = True
End Sub
Private Sub fsw_Changed(sender As Object, e As FileSystemEventArgs) Handles fsw.Changed
fsw.EnableRaisingEvents = False 'this is set because the file is changed many times in rapid succesion so I need to stop the Filewatcher from going of 200x (anyone has a better idea to do this?)
Threading.Thread.Sleep(100)
GetSettingsFromFile()
fsw.EnableRaisingEvents = True 'enabling it again
End Sub
End Class
But when I do this (trying to change anyhting in the form) I get this error:
System.InvalidOperationException (WinForms.IllegalCrossThreadCall)
It wont stop the program from working, but I want to understand what is wrong here and why the debugger is throwing this at me
regards
The event is being raised on a secondary thread. Any changes to the UI must be made on the UI thread. You need to marshal a method call to the UI thread and update the UI there. Lots of information around on how to do that. Here's an example:
Private Sub UpdateCheckBox1(checked As Boolean)
If CheckBox1.InvokeRequired Then
'We are on a secondary thread so marshal a method call to the UI thread.
CheckBox1.Invoke(New Action(Of Boolean)(AddressOf UpdateCheckBox1), checked)
Else
'We are on the UI thread so update the control.
CheckBox1.Checked = checked
End If
End Sub
Now you simply call that method wherever you are and whatever thread you're on. If you're already on the UI thread then the control will just be updated. If you're on a secondary thread then the method will invoke itself a second time, this time on the UI thread, and the control will be updated in that second invocation.
I have the following code:
Dim p() As Process
Private Sub CheckIfRunning()
p = Process.GetProcessesByName("skype") 'Process name without the .exe
If p.Count > 0 Then
' Process is running
MessageBox.Show("Yes, Skype is running")
Else
' Process is not running
MessageBox.Show("No, Skype isn't running")
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
CheckIfRunning()
End Sub
And it works GREAT!
But I'm wondering how I would convert this to a monitoring application, to constantly check if the processes is running. Is it as simple as putting the check on a timer every 1 second, or is there a better, more efficient way to go about this.
In the end result, I'd like to have a label that says "Running", or "Not Running" based on the process, but I need something to watch the process constantly.
If you need the app running all the time, then you don't need a Timer at all. Subscribe to the Process.Exited() event to be notified when it closes. For instance, with Notepad:
Public Class Form1
Private P As Process
Private FileName As String = "C:\Windows\Notepad.exe"
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim ps() As Process = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(FileName))
If ps.Length = 0 Then
P = Process.Start(FileName)
P.EnableRaisingEvents = True
AddHandler P.Exited, AddressOf P_Exited
Else
P = ps(0)
P.EnableRaisingEvents = True
AddHandler P.Exited, AddressOf P_Exited
End If
End Sub
Private Sub P_Exited(sender As Object, e As EventArgs)
Console.WriteLine("App Exited # " & DateTime.Now)
Console.WriteLine("Restarting app: " & FileName)
P = Process.Start(FileName)
P.EnableRaisingEvents = True
AddHandler P.Exited, AddressOf P_Exited
End Sub
End Class
That would keep it open all the time, assuming you wanted to open it if it wasn't already running.
If you don't want to open it yourself, and need to detect when it does open, then you could use WMI via the ManagementEventWatcher as in this previous SO question.
I've done something similar to this to monitor an exe that I need to be running all the time, and to restart it if it was down.
Mine was running as a Windows Service - that way it would start when windows booted and id never need to look after it.
Alternatively you could just create it as a console app and put it in your startup folder?
I had:
Sub Main()
Do
Check_server()
Dim t As New TimeSpan(0, 15, 0)
Threading.Thread.Sleep(t)
Loop
End Sub
Public Sub Check_server()
Dim current_pros() As Process = get_pros()
Dim found As Boolean = False
If Now.Hour < "22" Then
For Each pro In current_pros
If pro.ProcessName.ToLower = "Lorraine" Then
found = True
Exit For
Else
found = False
End If
Next
If found Then
Console.WriteLine("Server up")
Else
Console.WriteLine("Server down - restarting")
restart_server()
End If
End If
End Sub
My "server" app was called Lorraine...Also a timer maybe better practice than having the thread sleep..
From my experience, a simple timer works best:
'Timer interval set to 1-5 seconds... no remotely significant CPU hit
Private Sub timerTest_Tick(sender As System.Object, e As System.EventArgs) Handles timerTest.Tick
Dim p() As Process = Process.GetProcessesByName("Skype")
lblStatus.Text = If(p.Length > 0, "Skype is running.", "Skype isn't running.")
End Sub
Your mileage may vary, but I don't like to deal with separate threads unless necessary.
My button is responding to clicks while disabled.
Private Sub btnGenerate_Click(sender As Object, e As EventArgs) Handles btnGenerate.Click
btnGenerate.Enabled = False
Me.Cursor = Cursors.WaitCursor
'Do a bunch of operations
Me.Cursor = Cursors.Default
btnGenerate.Enabled = True
End Sub
It takes about 5-10 seconds to process the stuff I'm doing in the background. During that 5-10 seconds the button is greyed out, but if I click it a second time, then it performs the operational stuff a second time after finishing the first.
I'm missing something here. How can I prevent button from allowing interaction until operations are finished?
Dim Working as boolean=false
Private Sub btnGenerate_Click(sender As Object, e As EventArgs) Handles btnGenerate.Click
if Working=true then exit sub
' Your Work Process
Work()
End Sub
sub Work()
Working=True
' Work code
Working=False
end sub
this should prevent the double click
With VS2012, Async Work is very easy to use (compared to previous versions...).
The problem is the UI thread is not letting go. Without seeing what 'work' is actually going on, I can not explain why. I am hoping nothing that re enables the button...
However, Async will allow release of the UI thread and the enabled = false should take effect. Try something like this:
Private Async Sub btnGenerate_Click(sender As Object, e As EventArgs) Handles btnGenerate.Click
btnGenerate.Enabled = False
Dim t As New Task(Sub() MyWorkLoad())
t.Start()
Await t
btnGenerate.Enabled = True
End Sub
Private Sub MyWorkLoad()
'do your work here
'for testing
Dim time As Date = Now
Do While True
If DateAdd(DateInterval.Second, -5, Now) > time Then Exit Do
Loop
End Sub
This did work for me...
I am writing a program in Visual Basic that will read text commands from the serial port that are sent using an external controller (an Arduino). However, when I try to test the code I get an error:
Cross-thread Operation Not Valid
Here is what the code looks like:
Private Sub SerialPort1_DataReceived(sender As Object, e As SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
Dim Data As String = SerialPort1.ReadExisting()
If Data = "l" Then
LeftRadio.Checked = True
ElseIf Data = "r" Then
RightRadio.Checked = True
ElseIf Data = "c" Then
CenterRadio.Checked = True
End If
End Sub
Private Sub connect_Click(sender As Object, e As EventArgs) Handles connect.Click
If Not SerialPort1.IsOpen Then
SerialPort1.PortName = "COM3"
SerialPort1.Open()
End If
End Sub
Please see Cross-thread operation not valid and Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on
Short answer: you perform UI operation in not-UI (main) thread what is not permitted.
In VB.NET should be something like:
Dim check = Sub()
LeftRadio.Checked = True
End Sub
LeftRadio.Invoke(check)
I have found that the DataReceived event doesn't usually work the way you think and can block the serial port while code runs in the event.
My preference is to add a Timer to the form that runs at a reasonable speed such as 5 times per second.
In the Timer OnTick event you can test SerialPort1.BytesAvailable to see if data has arrived. Then use ReadExisting() as you have above.
The timer code will be less prone to cross thread issues.