Guy's I know I can terminate a process via WMI Services, TaskKill, CmdLine and API's but what's considered the best option?
The process in question is a PIC Programmer. My program will time the programmer and kill it if it hasn't reported success within a defined timeout period.
The purpose of my program is a safeguard to prevent the programmer from locking up my PC if it encounters an error that its error handlers failed to catch and exit the program.
The Programmer is a Command Line program that's interfaced with a windows GUI for users that don't like to use a console interface but it can be run either way.
Opinions will be appreciated.
Cheers,
Chris
<--- Did someone help you? Please rate their post. The little green squares make us feel really smart!
If topic has been resolved, please pull down the Thread Tools & mark it Resolved.
Is VB consuming your life, and is that a bad thing??
I use WMI all the time and I've never had a problem with it. Dilettante says it's not always available, but I've never seen a case where it wasn't.
Good Luck,
Elroy
EDIT1: Just FYI, here's the procedure I use:
Code:
Public Sub KillProcess(ByVal sProcessName As String)
' Kill process using Visual Basic 6 0 and WMI.
' The full .exe name (including the .exe) is supplied, but no path.
' Example: KillProcess "excel.exe"
' BE CAREFUL: No prompt for saving takes place.
' ALSO, it kills all occurrences.
Dim oWMI As Object
Dim ret As Long
Dim oServices As Object
Dim oService As Object
Dim sServiceName As String
Dim bFoundOne As Boolean
'
On Error Resume Next
sProcessName = LCase$(sProcessName)
Set oWMI = GetObject("WinMgmts:")
Set oServices = oWMI.InstancesOf("win32_process")
'
Do
For Each oService In oServices
sServiceName = LCase$(Trim$(CStr(oService.Name)))
If sServiceName = sProcessName Then
ret = oService.Terminate
bFoundOne = True
End If
Next oService
If Not bFoundOne Then Exit Do
If Err Then Exit Do
bFoundOne = False
Loop
On Error GoTo 0
End Sub
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
I wouldn't bother with the heavyweight WMI Service. The fact that it might be stopped, not installed at all, or secured against standard user access is just the beginning of its issues. It is only meant as an administrative scripting tool, not something for applications to use.
Besides, we have API calls to accomplish all of what you want and probably more. And since this is a process that you have started you can be sure that you are fiddling with the same instance that you started. Relying on the name is more than a little bit shaky. What if there could be multiple instances running?
There's a rearely used feature in the "WScript.Shell" COM-Object -
namely its .Exec-Method, which returns an Object that has StdIn, StdOut, StdErr-Objects
as well as a Terminate-Method (and a .Status-Property as well).
Here is two usecases in one single Demo:
Code:
Option Explicit
Private NotepadProcess As Object
Private Sub Form_Load()
AutoRedraw = True
'first scenario: shell an external process asynchronously (and auto-close it in Form_Unload if necessary)
Set NotepadProcess = CreateObject("WScript.Shell").Exec("Notepad.exe")
'second scenario: execute a ping-command synchronously, and capture its output in the VB-App
With CreateObject("WScript.Shell").Exec("%comspec% /c ping google.com")
Do Until .Status: Print .StdOut.ReadLine: Loop
Print "Cmd-Process finished with Status:"; .Status
End With
Show 'finally show our own App-Window on Top of Notepad (after the Ping-Processing was finished)
End Sub
Private Sub Form_Unload(Cancel As Integer)
If NotepadProcess.Status = 0 Then 'if 0, then it's still running...
NotepadProcess.Terminate '... so we close the process here
MsgBox "Notepad closed in Form_Unload with Status: " & NotepadProcess.Status
Else
MsgBox "Notepad was already externally closed due to User-interaction"
End If
End Sub
Gentlemen, thank you all for your code contributions. Olaf was the only member that accepted a like rating due to the spreading around the ratings policy. Elroy's WMI code works fine and is similar to quite a few .vbp's I have on file or edited over the years. Olaf's "WScript.Shell" COM-Object demo might be new to me. I have to search my files to see if I've ever played with it. It also works very well. Dilettant's API approach may very well be what I'll build from. I have familiarity with those API's and have snippets of those API's scattered in many of my VB "examples" files.
Here's another question that's born from each of the posted code examples. Each one starts the target .exe by Shelling it. My client (this is a gratis project) may want the opposite action, ie when the user starts the compiler or starts the parent program it also starts this watchdog timer. I don't know how to execute either one of those options. If he insists on this I don't see a lot of options other than starting the watchdog timer at system startup. Am I wrong about this? I would also think that having another timer that's checking when the compiler is started would not be as efficient.
Any opinions on this?
Cheers.
Chris
<--- Did someone help you? Please rate their post. The little green squares make us feel really smart!
If topic has been resolved, please pull down the Thread Tools & mark it Resolved.
Is VB consuming your life, and is that a bad thing??
I'm not at all sure I understand your second paragraph (post #6). However, with the code I posted (post #2), it's not at all necessary that the VB6 program started the target program (through either Shell or ShellExecute). It will kill any program you want.
Also, it sounds like you want some code to see if a program is "hung". I don't have that at my fingertips but I wouldn't mind having it if someone else posts it. I believe I've seen it before, but I'll let you do the search.
It also seems that information about the running process would be useful to you, specifically, how long it's been running. Again, I don't have this code handy, but I'd be surprised if it's not retrievable.
Good Luck,
Elroy
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Option Explicit
'
Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type
Private Type SYSTEMTIME
wYear As Integer
wMonth As Integer
wDayOfWeek As Integer
wDay As Integer
wHour As Integer
wMinute As Integer
wSecond As Integer
wMilliseconds As Integer
End Type
Private Declare Function GetProcessTimes Lib "kernel32" (ByVal hProcess As Long, lpCreationTime As FILETIME, lpExitTime As FILETIME, lpKernelTime As FILETIME, lpUserTime As FILETIME) As Long
Private Declare Function FileTimeToLocalFileTime Lib "kernel32" (lpFileTime As FILETIME, lpLocalFileTime As FILETIME) As Long
Private Declare Function FileTimeToSystemTime Lib "kernel32" (lpFileTime As FILETIME, lpSystemTime As SYSTEMTIME) As Long
Private Declare Function GetCurrentProcess Lib "kernel32" () As Long
'
Private Sub Form_Load()
Dim FT0 As FILETIME, FT1 As FILETIME, ST As SYSTEMTIME
'
GetProcessTimes GetCurrentProcess, FT1, FT0, FT0, FT0
FileTimeToLocalFileTime FT1, FT1
FileTimeToSystemTime FT1, ST
MsgBox "This program was started at " + CStr(ST.wHour) + ":" + CStr(ST.wMinute) + "." + CStr(ST.wSecond) + " on " + CStr(ST.wMonth) + "/" + CStr(ST.wDay) + "/" + CStr(ST.wYear)
End Sub
With some tweaking (i.e., getting the ProcessID of your target application), it seems that you could monitor how long your target program has been running, and then kill it if you so desire.
Good Luck,
Elroy
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Yes Elroy, I realize that none of the posted examples require Shell or ShellExecute to kill a process. My problem is that it's easy to Shell or ShellExecute a process but what about the reverse, ie the target process starting the .vbp? I don't think that's possible but starting my watchdog app at system boot is.
Thanks for the additional code! Dilettante's code also clocks start and end times of the target process and they both utilize API's. I like them both!
Cheers,
Chris
<--- Did someone help you? Please rate their post. The little green squares make us feel really smart!
If topic has been resolved, please pull down the Thread Tools & mark it Resolved.
Is VB consuming your life, and is that a bad thing??
<--- Did someone help you? Please rate their post. The little green squares make us feel really smart!
If topic has been resolved, please pull down the Thread Tools & mark it Resolved.
Is VB consuming your life, and is that a bad thing??
Also, it sounds like you want some code to see if a program is "hung". I don't have that at my fingertips but I wouldn't mind having it if someone else posts it.
It seems that your approach hinges on the IsHungAppWindow API call. I hadn't seen this API call before, although I'm not sure I've wanted to know if an app was hung before either. Use of this API call seems a bit dubious in that Microsoft says "The IsHungAppWindow function is not intended for general use. It may be altered or unavailable in subsequent versions of Windows." However, I tested under Windows 10 and it seems to work fine. Truth be told, if I needed such a function, I'd probably use this, just being sure to test on various Windows OS environments.
Also, your work had a substantial amount of overhead in it. I cut it down to the essentials:
Code:
Option Explicit
'
Private Declare Function IsHungAppWindow Lib "user32" (ByVal hWnd As Long) As Long
'
Public Function IsWindowHung(hWndOfInterest As Long) As Boolean
' From Microsoft MSDN:
' The IsHungAppWindow function is not intended for general use.
' It may be altered or unavailable in subsequent versions of Windows.
' Determines whether the system considers that a specified application is not responding.
' An application is considered to be not responding if it is not waiting for input,
' is not in startup processing, and has not called PeekMessage within the internal
' timeout period of 5 seconds. Ghost windows always return TRUE.
' The Windows timeout criteria of 5 seconds is subject to change.
'
' If hWndOfInterest is NOT a window, False (not hung) is returned.
'
IsWindowHung = IsHungAppWindow(hWndOfInterest) <> 0&
End Function
I'll let people sort out how to get a ThreadID or ProcessID from a hWnd (or vice-versa) if they so desire, as those tasks seem straightforward to me.
Best Regards,
Elroy
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
That API is new to me too. It's not listed in the AllAPI Network viewer or the ApiViewer 2004. Both of these are very out of date.
Thanks for the link and another big thanks to Elroy for cleaning up the code.
Cheers,
Chris
<--- Did someone help you? Please rate their post. The little green squares make us feel really smart!
If topic has been resolved, please pull down the Thread Tools & mark it Resolved.
Is VB consuming your life, and is that a bad thing??
What's still somewhat confusing to me is ... it's a "thread" that hangs, and not a "window". It's rather trivial to write an application with no window that hangs...
Code:
Option Explicit
Sub Main()
Do
'... No Exit, as Sartre says.
Loop
End Sub
It seems that there should also be an API named IsHungAppThread, but I can't seem to find anything like this.
Best Regards,
Elroy
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
@Dragokas: Ahhh, good point. I suppose, since there's no messaging, there's very little to check. I suppose, on Shutdown, Windows would just kill such an application with no user-prompt.
For us, I suppose we could examine CPU load, but even that would be dubious. I think I'm going to quit worrying about it.
Take Care,
Elroy
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.