rs_teststand_sys/window/pump.rs
1//! Servicing the thread's Windows message queue.
2
3use windows::Win32::Foundation::HWND;
4use windows::Win32::UI::WindowsAndMessaging::{
5 DispatchMessageW, MSG, PM_REMOVE, PeekMessageW, TranslateMessage, WM_QUIT,
6};
7
8/// Dispatches every Windows message currently waiting on this thread.
9///
10/// Returns `true` if a quit message was seen.
11///
12/// A single-threaded COM apartment delivers cross-apartment calls as window
13/// messages, so a thread that owns apartment objects and never pumps starves
14/// them. On a background thread, where nothing pumps by default, an engine
15/// running an execution will abort the process rather than fail cleanly, so
16/// this must be called regularly from any loop that owns such a thread.
17///
18/// A thread that only makes direct calls and owns no callbacks does not need
19/// it; the cost is one `PeekMessage` per call when the queue is empty.
20#[must_use]
21pub fn pump_thread_messages() -> bool {
22 let mut message = MSG::default();
23 let mut quitting = false;
24
25 // SAFETY: `message` is a valid, owned MSG for the duration of each call.
26 // PeekMessageW with a null HWND takes messages for this thread only, and
27 // PM_REMOVE dequeues what it returns, so the loop terminates once the queue
28 // is drained. TranslateMessage and DispatchMessageW read the message we
29 // just received and do not retain it.
30 unsafe {
31 while PeekMessageW(&raw mut message, Some(HWND::default()), 0, 0, PM_REMOVE).as_bool() {
32 if message.message == WM_QUIT {
33 quitting = true;
34 break;
35 }
36 let _ = TranslateMessage(&raw const message);
37 DispatchMessageW(&raw const message);
38 }
39 }
40 quitting
41}