Win10关机时如何自动终止常驻程序避免阻停并执行预设指令
Windows下自运行循环程序适配关机流程方案
Windows提供了原生的系统事件通知机制,可以在关机触发后、正式断电/重启前执行自定义收尾逻辑,让程序正常退出,不会弹出“程序阻止关机”的系统提示。
核心原理
- 系统触发关机流程时,会按顺序向所有运行中的程序发送通知消息,预留固定时长供程序自行退出
- 桌面类程序需要响应
WM_QUERYENDSESSION、WM_ENDSESSION两个窗口消息,控制台程序可以通过监听控制台控制事件捕获关机信号 - 收到关机信号后,主动终止while主循环、按顺序执行资源释放、数据保存等指定操作,最后正常退出进程即可,不需要额外调用系统关机接口
- 系统默认给单程序预留的关机处理时长为5秒,自定义收尾逻辑不要包含长时间阻塞的操作,避免被系统强制终止
实现示例
1. 桌面类/无窗口Python程序实现
通过创建隐藏的消息窗口接收系统关机消息,不依赖第三方库:
import ctypes import ctypes.wintypes import threading import time # 全局运行标记,控制主循环状态 is_running = True def shutdown_monitor(): # 窗口消息处理回调 def window_proc(hwnd, msg, wparam, lparam): global is_running # 收到关机查询消息,直接返回同意关机 if msg == 0x0011: # WM_QUERYENDSESSION return 1 # 收到正式关机通知,执行自定义收尾逻辑 if msg == 0x0016: # WM_ENDSESSION if wparam: # 以下位置按顺序写需要在关机前执行的指令 print("停止接收新业务请求") time.sleep(0.3) print("持久化内存中未保存的数据") time.sleep(0.3) print("释放端口、文件句柄等占用资源") # 修改循环标记,终止主服务循环 is_running = False return 0 return ctypes.windll.user32.DefWindowProcW(hwnd, msg, wparam, lparam) # 注册隐藏窗口用于接收系统消息 h_instance = ctypes.windll.kernel32.GetModuleHandleW(None) wnd_class = ctypes.wintypes.WNDCLASSW() wnd_class.lpfnWndProc = ctypes.WINFUNCTYPE( ctypes.c_long, ctypes.wintypes.HWND, ctypes.wintypes.UINT, ctypes.wintypes.WPARAM, ctypes.wintypes.LPARAM )(window_proc) wnd_class.hInstance = h_instance wnd_class.lpszClassName = "ShutdownMonitorWin" ctypes.windll.user32.RegisterClassW(ctypes.byref(wnd_class)) ctypes.windll.user32.CreateWindowExW( 0, wnd_class.lpszClassName, "", 0, 0, 0, 0, 0, 0, 0, h_instance, 0 ) # 启动消息循环监听系统事件 msg = ctypes.wintypes.MSG() while ctypes.windll.user32.GetMessageW(ctypes.byref(msg), 0, 0, 0) != 0: ctypes.windll.user32.TranslateMessage(ctypes.byref(msg)) ctypes.windll.user32.DispatchMessageW(ctypes.byref(msg)) # 启动关机监听守护线程 threading.Thread(target=shutdown_monitor, daemon=True).start() # 原有的while循环服务逻辑 request_count = 0 while is_running: print(f"服务正常运行,累计处理请求数:{request_count}") request_count += 1 time.sleep(1) print("程序正常退出,不会阻断系统关机流程")
2. 控制台程序简易实现
如果你的程序是直接运行的控制台程序,可以用更简单的控制台事件监听方式:
import ctypes import time is_running = True @ctypes.WINFUNCTYPE(ctypes.c_long, ctypes.c_ulong) def console_ctrl_handler(ctrl_type): global is_running # 监听到系统关机事件 if ctrl_type == 6: # CTRL_SHUTDOWN_EVENT # 执行自定义收尾指令 print("收到关机信号,准备退出") is_running = False return 1 return 0 # 注册控制台事件回调 ctypes.windll.kernel32.SetConsoleCtrlHandler(console_ctrl_handler, 1) # 原有while服务循环 while is_running: time.sleep(1)
优化建议
- 如果是需要长期后台运行的服务类程序,建议封装为标准Windows系统服务,通过服务控制管理器的停止回调处理关机逻辑,稳定性更高,不会受前台程序超时规则限制
- 收尾逻辑尽量精简,不要包含网络请求、大文件写入等耗时操作,避免超过系统预留的处理时间被强制杀死
- 不要在关机回调中弹出交互对话框,会被系统判定为未响应程序,依然会触发阻断关机的提示
内容的提问来源于stack exchange,提问作者Mouad Essalim
相关产品推荐
相关产品推荐

