When using win32api.setConsoleCtrlHandler()
, I'm able to receive shutdown/logoff/etc events from Windows, and cleanly shut down my app.
However, this only works when running the app under python.exe (i.e., it has a console window), but not under pythonw.exe (no console window).
Is there an equivalent way in Windows to receive these events when you have no console and no window to receive them? Or, is there a programmatic way to hide the console window?
To be clear - my goal is to be able to successfully receive Windows shutdown/logoff/etc events, without having any kind of console window showing.
EDIT:
I've been playing around, and I've gotten quite a bit further. I wrote a piece of test code for this. When I do a taskkill /im pythonw.exe
- it will receive the message.
However, when I do a shutdown, restart, or logoff on Windows, I do not get any messages.
Here's the whole thing:
""" Testing Windows shutdown events """
import win32con
import win32api
import win32gui
import sys
import time
def log_info(msg):
""" Prints """
print msg
f = open("c:\\test.log", "a")
f.write(msg + "\n")
f.close()
def wndproc(hwnd, msg, wparam, lparam):
log_info("wndproc: %s" % msg)
if __name__ == "__main__":
log_info("*** STARTING ***")
hinst = win32api.GetModuleHandle(None)
wndclass = win32gui.WNDCLASS()
wndclass.hInstance = hinst
wndclass.lpszClassName = "testWindowClass"
messageMap = { win32con.WM_QUERYENDSESSION : wndproc,
win32con.WM_ENDSESSION : wndproc,
win32con.WM_QUIT : wndproc,
win32con.WM_DESTROY : wndproc,
win32con.WM_CLOSE : wndproc }
wndclass.lpfnWndProc = messageMap
try:
myWindowClass = win32gui.RegisterClass(wndclass)
hwnd = win32gui.CreateWindowEx(win32con.WS_EX_LEFT,
myWindowClass,
"testMsgWindow",
0,
0,
0,
win32con.CW_USEDEFAULT,
win32con.CW_USEDEFAULT,
win32con.HWND_MESSAGE,
0,
hinst,
None)
except Exception, e:
log_info("Exception: %s" % str(e))
if hwnd is None:
log_info("hwnd is none!")
else:
log_info("hwnd: %s" % hwnd)
while True:
win32gui.PumpWaitingMessages()
time.sleep(1)
I feel like I'm pretty close here, but I'm definitely missing something!
If you don't have a console, setting a console handler of course can't work. You can receive system events on a GUI (non-console) program by making another window (doesn't have to be visible), making sure you have a normal "message pump" on it serving, and handling WM_QUERYENDSESSION
-- that's the message telling your window about shutdown and logoff events (and your window can try to push back against the end-session by returning 0 for this message). ("Windows Services" are different from normal apps -- if that's what you're writing, see an example here).
The problem here was that the HWND_MESSAGE
window type doesn't actually receive broadcast messages - like the WM_QUERYENDSESSION
and WM_ENDSESSION
.
So instead of specifying win32con.HWND_MESSAGE
for the "parent window" parameter of CreateWindowEx()
, I just specified 0
.
Basically, this creates an actual window, but I never show it, so it's effectively the same thing. Now, I can successfully receive those broadcast messages and shut down the app properly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With