rt_local/runtime/
windows.rs

1use rt_local_core::base::{on_idle, RuntimeLoop, RuntimeWaker};
2use std::{future::Future, marker::PhantomData, ops::ControlFlow, sync::Arc};
3use windows::Win32::{
4    Foundation::{HWND, LPARAM, WPARAM},
5    System::Threading::GetCurrentThreadId,
6    UI::WindowsAndMessaging::{
7        DispatchMessageW, GetMessageW, PeekMessageW, PostThreadMessageW, TranslateMessage, MSG,
8        PM_REMOVE, WM_NULL, WM_QUIT,
9    },
10};
11
12/// Executes the specified future and blocks until it completes.
13pub fn run<F: Future>(future: F) -> F::Output {
14    rt_local_core::base::run(&WindowsMessageLoop::new(), future)
15}
16
17pub use rt_local_macros::windows_main as main;
18pub use rt_local_macros::windows_test as test;
19
20struct WindowsMessageLoop {
21    waker: Arc<Waker>,
22    _not_send: PhantomData<*mut ()>,
23}
24
25impl WindowsMessageLoop {
26    fn new() -> Self {
27        unsafe {
28            let thread_id = GetCurrentThreadId();
29            Self {
30                waker: Arc::new(Waker { thread_id }),
31                _not_send: PhantomData,
32            }
33        }
34    }
35}
36impl RuntimeLoop for WindowsMessageLoop {
37    fn waker(&self) -> Arc<dyn RuntimeWaker> {
38        self.waker.clone()
39    }
40    fn run<T>(&self, mut on_step: impl FnMut() -> ControlFlow<T>) -> T {
41        loop {
42            if let ControlFlow::Break(value) = on_step() {
43                return value;
44            }
45            let mut msg = MSG::default();
46            unsafe {
47                if !PeekMessageW(&mut msg, HWND(0), 0, 0, PM_REMOVE).as_bool() {
48                    if on_idle() {
49                        continue;
50                    } else {
51                        GetMessageW(&mut msg, HWND(0), 0, 0).ok().unwrap();
52                    }
53                }
54                if msg.message == WM_QUIT {
55                    panic!("message loop terminated");
56                }
57                TranslateMessage(&msg);
58                DispatchMessageW(&msg);
59            }
60        }
61    }
62}
63
64struct Waker {
65    thread_id: u32,
66}
67impl RuntimeWaker for Waker {
68    fn wake(&self) {
69        unsafe {
70            let _ = PostThreadMessageW(self.thread_id, WM_NULL, WPARAM(0), LPARAM(0));
71        }
72    }
73}