Python - Windows 关闭事件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1411186/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python - Windows Shutdown Events
提问by Dave
When using win32api.setConsoleCtrlHandler(), I'm able to receive shutdown/logoff/etc events from Windows, and cleanly shut down my app.
使用 win32api.setConsoleCtrlHandler() 时,我能够从 Windows 接收关闭/注销/等事件,并彻底关闭我的应用程序。
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).
但是,这只适用于在 python.exe 下运行应用程序(即,它有一个控制台窗口),而不是在 pythonw.exe 下(没有控制台窗口)。
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?
当您没有控制台也没有窗口来接收这些事件时,在 Windows 中是否有一种等效的方式来接收这些事件?或者,是否有隐藏控制台窗口的编程方式?
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.
明确地说 - 我的目标是能够成功接收 Windows 关闭/注销/等事件,而无需显示任何类型的控制台窗口。
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.
编辑:我一直在玩,而且我已经走得更远了。我为此写了一段测试代码。当我执行“taskkill /im pythonw.exe”时 - 它会收到消息。
However, when I do a shutdown, restart, or logoff on Windows, I do not get any messages.
但是,当我在 Windows 上关闭、重新启动或注销时,我没有收到任何消息。
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!
我觉得我离这里很近了,但我肯定错过了一些东西!
回答by Dave
The problem here was that the HWND_MESSAGE window type doesn't actually receive broadcast messages - like the WM_QUERYENDSESSION and WM_ENDSESSION.
这里的问题是 HWND_MESSAGE 窗口类型实际上并不接收广播消息——比如 WM_QUERYENDSESSION 和 WM_ENDSESSION。
So instead of specifying win32con.HWND_MESSAGE for the "parent window" parameter of CreateWindowEx(), I just specified "0".
因此,我没有为 CreateWindowEx() 的“父窗口”参数指定 win32con.HWND_MESSAGE,而是指定了“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.
基本上,这会创建一个实际的窗口,但我从不显示它,因此它实际上是同一回事。现在,我可以成功接收这些广播消息并正确关闭应用程序。
回答by Alex Martelli
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).
如果您没有控制台,则设置控制台处理程序当然是行不通的。您可以通过创建另一个窗口(不必是可见的)来接收 GUI(非控制台)程序上的系统事件,确保其上有一个正常的“消息泵”服务,并处理WM_QUERYENDSESSION
——这就是消息您关于关闭和注销事件的窗口(并且您的窗口可以尝试通过为此消息返回 0 来推回结束会话)。(“Windows 服务”与普通应用程序不同——如果这是您编写的内容,请参阅此处的示例)。