I'm trying to require a user to confirm a Windows shutdown while my program is performing critical tasks.
In order to do this, I want to listen for a WM_QUERYENDSESSION message (in a seperate thread from the main program).
If this message is received, I'm calling ShutdownBlockReasonCreate() to prevent the shutdown.
You'll find my current implementation below.
Since the Win32 API also states that only visible windows are allowed to block shutdowns, i made the window that listens to the messages visible once a WM_QUERYENDSESSION is received.
My issue is, that the program does not seem to receive any WM_QUERYENDSESSION messages ever. Logging all messages did reveal it receiving other messages, as expected, as well as messages 799 and 800, which i could not find in any Windows Messages Documentation.
I'm greatful for any help you can give me, as I feel very lost here.
My current implementation:
use std::ptr::null_mut;
use winapi::shared::minwindef::{LPARAM, LRESULT, UINT, WPARAM, HINSTANCE};
use winapi::shared::windef::{HWND, HMENU};
use winapi::um::winuser::{
CreateWindowExW, DefWindowProcW, DispatchMessageW, GetMessageW, PostQuitMessage,
RegisterClassW, ShowWindow, TranslateMessage, MSG, CW_USEDEFAULT,
WM_CREATE, WM_DESTROY, WM_QUERYENDSESSION, SW_HIDE, SW_SHOW,
WS_EX_TOOLWINDOW,
ShutdownBlockReasonCreate, ShutdownBlockReasonDestroy,
};
pub fn start_preventing_shutdown() {
let class_name = "ProgramNameClass";
let window_name = "ProgramName";
let hinstance = null_mut();
let hwnd_parent = null_mut();
let hmenu = null_mut();
let hwnd = create_window(
class_name, window_name, hinstance, hwnd_parent, hmenu, SW_HIDE,
);
let mut msg: MSG = Default::default();
loop {
unsafe {
GetMessageW(&mut msg, hwnd, 0, 0);
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
}
fn create_window(
class_name: &str,
window_name: &str,
hinstance: HINSTANCE,
hwnd_parent: HWND,
hmenu: HMENU,
n_cmd_show: i32,
) -> HWND {
let wnd_class = winapi::um::winuser::WNDCLASSW {
style: 0,
lpfnWndProc: Some(wnd_proc),
hInstance: hinstance,
lpszClassName: class_name.encode_utf16().collect::<Vec<u16>>().as_ptr(),
cbClsExtra: 0,
cbWndExtra: 0,
hIcon: null_mut(),
hCursor: null_mut(),
hbrBackground: null_mut(),
lpszMenuName: null_mut(),
};
unsafe {
RegisterClassW(&wnd_class);
let hwnd = CreateWindowExW(
WS_EX_TOOLWINDOW, // set the window style to WS_EX_TOOLWINDOW
class_name.encode_utf16().collect::<Vec<u16>>().as_ptr(),
window_name.encode_utf16().collect::<Vec<u16>>().as_ptr(),
0,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
hwnd_parent,
hmenu,
hinstance,
null_mut(),
);
ShowWindow(hwnd, n_cmd_show); // hide the window when it is created
hwnd
}
}
unsafe extern "system" fn wnd_proc(
hwnd: HWND,
msg: UINT,
w_param: WPARAM,
l_param: LPARAM,
) -> LRESULT {
match msg {
WM_CREATE => {
0
}
WM_DESTROY => {
ShutdownBlockReasonDestroy(hwnd); // remove the shutdown block when the application is closing
PostQuitMessage(0);
0
}
WM_QUERYENDSESSION => {
ShowWindow(hwnd, SW_SHOW); // show the window when the system is trying to shut down
ShutdownBlockReasonCreate(hwnd, "Preventing shutdown".encode_utf16().collect::<Vec<u16>>().as_ptr()); // call ShutdownBlockReasonCreate before returning from the message handler
1
}
_ => {
DefWindowProcW(hwnd, msg, w_param, l_param)
}
}
}