I have been using this piece of code I made for a few months now to check if a certain group of windows I have open are stuck on a certain window title for a given amount of seconds, and then closes them if so. This code is continuously ran on my VPS.
import time
import datetime
import win32gui
import win32process
max_downtime = 90
pid_downtimes = {}
cur_pids = []
prev_pids = []
def winEnumHandler(hwnd, ctx):
class_name = win32gui.GetClassName(hwnd)
window_text = win32gui.GetWindowText(hwnd)
if class_name != "ConsoleWindowClass":
return
if not window_text.startswith("Plutonium"):
return
if "Server restarter" in window_text:
return
if "Dedicated Server" in window_text:
return
tid, pid = win32process.GetWindowThreadProcessId(hwnd)
if pid not in pid_downtimes:
pid_downtimes[pid] = 0
pid_downtimes[pid] += 1
if pid_downtimes[pid] >= max_downtime:
print("Server restarted at:", datetime.datetime.now())
win32gui.SendMessage(hwnd, 16) # close window
return
cur_pids.append(pid)
while True:
win32gui.EnumWindows(winEnumHandler, None)
old_pids = [pid for pid in prev_pids if pid not in cur_pids]
for pid in old_pids:
if pid in pid_downtimes:
del pid_downtimes[pid]
prev_pids = cur_pids
cur_pids = []
time.sleep(1)
A few days ago, for the first time it crashed.
Traceback (most recent call last):
line 43, in <module>
win32gui.EnumWindows(winEnumHandler, None)
line 12, in winEnumHandler
class_name = win32gui.GetClassName(hwnd)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
pywintypes.error: (1400, 'GetClassName', 'Invalid window handle.')
Anyone know what would cause this to crash after running smoothly for months? It seemed to have started the function winEnumHandler
with an invalid window handle from win32gui.EnumWindows
, which I didn't know was possible.
According to [MS.Learn]: GetClassName function (winuser.h) (emphasis is mine):
If the function fails, the return value is zero. To get extended error information, call GetLastError function.
so this function can fail for certain windows (maybe there are some that don't have a class?). So your code must handle this scenario. Could be something like:
import pywintypes
# ...
def win_enum_handler(hwnd, ctx):
window_text = win32gui.GetWindowText(hwnd)
try:
class_name = win32gui.GetClassName(hwnd)
except pywintypes.error:
class_name = "Could not be determined"
# ...