winit icon indicating copy to clipboard operation
winit copied to clipboard

Detect Windows reboot (WM_QUERYENDSESSION and WM_ENDSESSION)

Open erith835 opened this issue 3 months ago • 1 comments

Description

Hello, I want my app to detect when Windows reboots. I wrote a test app that compiles and runs and detects lots of events, but not the WM_QUERYENDSESSION or WM_ENDSESSION events. What is wrong? Or is there any other way to detect a Windows reboot or shut down?

Cargo.toml

[package]
name = "test"
version = "0.1.0"
edition = "2024"

[dependencies]
winit = "0.30.12"

winapi = { version = "0.3.9", features = ["winuser"] }
windows-sys = { version = "0.61.0", features = [
    "Win32_UI_WindowsAndMessaging",
] }

main.rs

use winapi::um::winuser::MSG;
use windows_sys::Win32::UI::WindowsAndMessaging;
use winit::application::ApplicationHandler;
use winit::event::WindowEvent;
use winit::event_loop::ActiveEventLoop;
use winit::event_loop::EventLoop;
use winit::platform::windows::EventLoopBuilderExtWindows;
use winit::window::{Window, WindowId};

#[derive(Default)]
struct App {
    window: Option<Window>,
}
impl ApplicationHandler for App {
    fn resumed(&mut self, event_loop: &ActiveEventLoop) {
        self.window = Some(
            event_loop
                .create_window(Window::default_attributes())
                .unwrap(),
        );
    }
    fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) {
        match event {
            WindowEvent::CloseRequested => {
                log_event("CloseRequested");
                event_loop.exit();
            }
            WindowEvent::RedrawRequested => {
                self.window.as_ref().unwrap().request_redraw();
            }
            _ => (),
        }
    }
}
fn log_event(event: &str) {
    use std::io::Write;
    println!("{:?}", event);
    let mut file = std::fs::OpenOptions::new()
        .write(true)
        .create(true)
        .append(true)
        .open("log.txt")
        .unwrap();
    let _ = writeln!(file, "{}", event);
}
fn main() {
    let mut builder = EventLoop::builder();
    builder.with_msg_hook(|msg| {
        let msg = msg as *const MSG;
        let mess = unsafe { (*msg).message };
        match mess {
            WindowsAndMessaging::WM_PAINT => (),
            WindowsAndMessaging::WM_NCMOUSEMOVE => (),
            WindowsAndMessaging::WM_INPUT => (),
            WindowsAndMessaging::WM_MOUSEMOVE => (),
            WindowsAndMessaging::WM_QUERYENDSESSION => log_event("WM_QUERYENDSESSION"),
            WindowsAndMessaging::WM_ENDSESSION => log_event("WM_ENDSESSION"),
            _ => {
                log_event(&format!("{}", mess));
            }
        }
        false
    });
    let event_loop = builder.build().unwrap();
    let mut app = App::default();
    let _ = event_loop.run_app(&mut app);
}

Windows version

Microsoft Windows [Version 10.0.26100.6584]

Winit version

0.30.12

erith835 avatar Sep 14 '25 22:09 erith835

Hi! I’ve been running into the same issue (both in console apps and when using egui).

From what I understand, I don’t think this is actually a bug. Windows handles shutdown signals differently depending on whether the app is a console (terminal) app or a GUI app. According to the Windows docs, messages like WM_QUERYENDSESSION and WM_ENDSESSION are only sent to top-level windows, not to console applications. That’s the first issue: console apps need to handle different signals.

The docs are pretty helpful if you dig through them and follow the related signals and functions. A good starting point is here: https://learn.microsoft.com/en-us/windows/win32/shutdown/wm-queryendsession

At the moment, I don’t have a full solution. To handle this properly, you’d need to hook into the raw Win32 API and set a custom wnd_proc function — but with egui, window creation is managed for you, so you don’t have direct control over that.

For console applications, shutdown signals should instead be handled using SetConsoleCtrlHandler: https://learn.microsoft.com/en-us/windows/console/setconsolectrlhandler

That said, I haven’t been able to get a completely reliable shutdown sequence this way, since Windows only allows shutdown to be blocked when there’s a GUI window.

mabartcz avatar Sep 18 '25 13:09 mabartcz