Python - Windows关机事件

17
使用win32api.setConsoleCtrlHandler()时,我可以从Windows接收到关机/注销等事件,并且干净地关闭我的应用程序。但是,这仅适用于在python.exe下运行应用程序(即有控制台窗口),而不适用于在pythonw.exe下运行应用程序(没有控制台窗口)。 在Windows中,是否有一种等效的方法可以在没有控制台和无法接收事件的窗口的情况下接收这些事件?或者,是否有一种编程方式可以隐藏控制台窗口? 明确一下 - 我的目标是能够成功收到Windows关机/注销等事件,而不显示任何控制台窗口。 编辑: 我一直在测试代码,并且取得了很大的进展。 我为此编写了一段测试代码。 当我执行taskkill /im pythonw.exe时,会接收到消息。 但是,当我在Windows上执行关机、重启或注销时,我没有收到任何消息。 以下是全部内容:
""" 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)

我感觉我离成功已经很接近了,但肯定还有什么重要的东西我没有考虑到!

2个回答

16

问题在于窗口类型HWND_MESSAGE实际上无法接收广播消息,例如WM_QUERYENDSESSIONWM_ENDSESSION

因此,我将CreateWindowEx()的“父窗口”参数指定为0而不是win32con.HWND_MESSAGE。基本上,这会创建一个实际的窗口,但我从未显示它,所以它实际上是相同的。现在,我可以成功地接收那些广播消息并正确关闭应用程序。


如何执行这个...我尝试运行提供的脚本,但它没有返回任何系统Logogg、关闭事件,甚至如果我从任务管理器中结束任务。 - Rao
在Windows 10上,这仅适用于python.exe,而不是pythonw.exe - Karalga
这对我不起作用。我有Python 3.10。 - Sandeep S D

5
如果您没有控制台,则设置控制台处理程序当然无法工作。您可以通过创建另一个窗口(不必可见),确保在其上提供正常的“消息泵”并处理WM_QUERYENDSESSION来在GUI(非控制台)程序上接收系统事件 - 这是告知您的窗口有关关闭和注销事件的消息(您的窗口可以尝试通过返回此消息的0来反对结束会话)。如果您正在编写“Windows服务”(如果您正在编写这样的应用程序),则与普通应用程序不同-请参见此处的示例。

我尝试了上面的代码,但是在注销/关机时系统事件从未触发。你能帮我解决一下吗? - Rao

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接