1use std::future::{Future};
2use std::pin::{Pin};
3use std::task::{Context, Poll, Waker, RawWaker, RawWakerVTable};
4
5use log;
6
7use windows::core::{
8 HSTRING,
9 PCWSTR,
10};
11
12use windows::Win32::Foundation::{
14 HWND,
15 WPARAM, LPARAM, LRESULT,
16 GetLastError,
17};
18
19use windows::Win32::System::LibraryLoader::{
21 GetModuleHandleW,
22};
23
24use windows::Win32::UI::WindowsAndMessaging::{
26 WNDCLASSEXW,
27 RegisterClassExW, CreateWindowExW,
29 DestroyWindow,
30 SetForegroundWindow,
31 WS_POPUP,
32 WS_EX_LEFT,
33 HMENU,
34 MSG,
35 GetMessageW,
36 TranslateMessage,
37 DispatchMessageW,
38 WM_USER,
39 CS_HREDRAW,
40 CS_VREDRAW,
41 DefWindowProcW,
42 IDI_APPLICATION,
43 IDC_ARROW,
44 HICON,
45 COLOR_WINDOW,
46 LoadIconW,
47 LoadCursorW,
48 PostMessageW,
49};
50
51use windows::Win32::Graphics::Gdi::{
52 HBRUSH,
53};
54
55const VTABLE: RawWakerVTable = RawWakerVTable::new(
56 |dummy_window| {
58 RawWaker::new(dummy_window, &VTABLE)
59 },
60
61 |dummy_window| {
63 let dummy_window:&DummyWindow = unsafe { &*(dummy_window as *const DummyWindow) };
64 crate::executor::post_message_asyncop_completed(dummy_window);
65 },
66
67 |dummy_window| {
69 let dummy_window:&DummyWindow = unsafe { &*(dummy_window as *const DummyWindow) };
70 crate::executor::post_message_asyncop_completed(dummy_window);
71 },
72
73 |_| {},
75);
76
77const DUMMY_WINDOW_CLASSNAME:&str = "windows-msgloop-async:DummyWindow";
78const DUMMY_WINDOW_WINDOWNAME:&str = "windows-msgloop-async:DummyWindow";
79const WM_USER_ASYNCOP_COMPLETED:u32 = WM_USER + 1;
80
81static mut REGISTER_ATOM: Option<u16> = None;
82
83
84fn post_message_asyncop_completed(dummy_window: &DummyWindow) {
85 unsafe {
86 log::trace!("PostMessage(WM_USER_ASYNCOP_COMPLETED) to {:?}", dummy_window);
87 PostMessageW(dummy_window.hwnd(), WM_USER_ASYNCOP_COMPLETED, WPARAM(0), LPARAM(0));
88 }
89}
90
91extern "system" fn wndproc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
92 match msg {
93 WM_USER_ASYNCOP_COMPLETED => {
94 log::trace!("AsyncOperation/AsyncAction Completed ({:?})", hwnd);
95 }
96 _ => {}
97 }
98
99 unsafe { DefWindowProcW(hwnd, msg, wparam, lparam) }
100}
101
102pub fn block_on<T>(mut f: impl Future<Output=T>) -> T {
106
107 let wnd = create_dummy_window();
109 let pwnd: *const DummyWindow = &wnd;
110
111 let waker = unsafe { Waker::from_raw(RawWaker::new(pwnd as *const (), &VTABLE)) };
112 let mut ctx = Context::from_waker(&waker);
113
114 let mut msg = MSG::default();
115 loop {
116 let f = unsafe { Pin::new_unchecked(&mut f) };
117 if let Poll::Ready(ret) = Future::poll(f, &mut ctx) {
118 return ret;
119 }
120
121 unsafe {
122 GetMessageW(&mut msg, None, 0, 0);
123 TranslateMessage(&mut msg);
124 DispatchMessageW(&mut msg);
125 }
126 }
127}
128
129#[derive(Debug)]
131#[repr(transparent)]
132pub struct DummyWindow(HWND);
133
134impl DummyWindow {
135 pub fn hwnd(&self) -> HWND {
137 self.0.clone()
138 }
139}
140
141impl Drop for DummyWindow {
142 fn drop(&mut self) {
144 unsafe {
145 DestroyWindow(self.0);
146 }
147 }
148}
149
150fn register_dummy_window() {
151 unsafe {
152 let hmodule = GetModuleHandleW(PCWSTR(std::ptr::null()));
153
154 let wndcls = WNDCLASSEXW {
155 cbSize: std::mem::size_of::<WNDCLASSEXW>() as u32,
156 style: CS_HREDRAW | CS_VREDRAW,
157 lpfnWndProc: Some(wndproc),
158 cbClsExtra: 0,
159 cbWndExtra: 0,
160 hInstance: hmodule,
161 hIcon: LoadIconW(hmodule.clone(), IDI_APPLICATION),
162 hCursor: LoadCursorW(hmodule.clone(), IDC_ARROW),
163 hbrBackground: HBRUSH((COLOR_WINDOW.0 + 1) as isize),
164 lpszMenuName: PCWSTR(std::ptr::null()),
165 lpszClassName: PCWSTR(&HSTRING::from(DUMMY_WINDOW_CLASSNAME).as_wide()[0]),
166 hIconSm: HICON::default(),
167 };
168
169 let ret = RegisterClassExW(&wndcls);
170 if ret == 0 {
171 let err = GetLastError();
172 log::debug!("RegisterClassExW failed (last_error={:?})", err);
173 }
174 else {
175 REGISTER_ATOM = Some(ret);
176 }
177 }
178}
179
180pub fn create_dummy_window() -> DummyWindow {
182 unsafe {
183 if REGISTER_ATOM.is_none() {
184 register_dummy_window();
185 }
186 let hmodule = GetModuleHandleW(PCWSTR(std::ptr::null()));
187 let hwnd = CreateWindowExW(
188 WS_EX_LEFT,
189 PCWSTR(&HSTRING::from(DUMMY_WINDOW_CLASSNAME).as_wide()[0]),
190 PCWSTR(&HSTRING::from(DUMMY_WINDOW_WINDOWNAME).as_wide()[0]),
191 WS_POPUP,
192 1, 1, 1, 1,
193 HWND::default(),
194 HMENU::default(),
195 hmodule,
196 std::ptr::null_mut(),
197 );
198
199 if hwnd.0 == 0 {
200 let err = GetLastError();
201 log::debug!("CreateWindowExW failed (last_error={:?})", err);
202 }
203 else {
204 log::trace!("Create Dummy window ({:?})", hwnd);
205 }
206
207 SetForegroundWindow(hwnd);
208 DummyWindow(hwnd)
209 }
210}