use std::{io, mem, ptr, time::Duration};
use tokio::sync::oneshot;
use winapi::{
shared::{
minwindef::FALSE,
windef::{HWND, POINT},
},
um::{
winbase::WAIT_FAILED,
winuser::{
CreateWindowExA, DestroyWindow, MsgWaitForMultipleObjects, PeekMessageW, HWND_MESSAGE,
MSG, PM_REMOVE, QS_ALLEVENTS,
},
},
};
pub fn run_dummy_message_loop(mut abort_receiver: oneshot::Receiver<()>) -> io::Result<()> {
let window = MessageOnlyWindow::new()?;
let mut msg = MSG {
hwnd: ptr::null_mut(),
message: 0,
wParam: 0,
lParam: 0,
time: 0,
pt: POINT { x: 0, y: 0 },
};
while matches!(
abort_receiver.try_recv(),
Err(oneshot::error::TryRecvError::Empty)
) {
while unsafe { PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, PM_REMOVE) } != 0 {}
if unsafe {
MsgWaitForMultipleObjects(
0,
ptr::null(),
FALSE,
Duration::from_secs(1).as_millis() as _,
QS_ALLEVENTS,
)
} == WAIT_FAILED
{
break;
}
}
window.destroy()
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct MessageOnlyWindow(HWND);
impl MessageOnlyWindow {
pub fn new() -> io::Result<Self> {
let handle = unsafe {
CreateWindowExA(
0,
cstr::cstr!("STATIC").as_ptr().cast(), ptr::null_mut(),
0,
0,
0,
0,
0,
HWND_MESSAGE, ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
)
};
if handle.is_null() {
return Err(io::Error::last_os_error());
}
Ok(Self(handle.cast()))
}
pub fn handle(&self) -> HWND {
self.0
}
pub fn destroy(mut self) -> io::Result<()> {
let result = unsafe { self._destroy() };
mem::forget(self);
result
}
unsafe fn _destroy(&mut self) -> io::Result<()> {
let result = unsafe { DestroyWindow(self.handle()) };
if result == 0 {
Err(io::Error::last_os_error())
} else {
Ok(())
}
}
}
impl Drop for MessageOnlyWindow {
fn drop(&mut self) {
let result = unsafe { self._destroy() };
debug_assert!(
result.is_ok(),
"MessageOnlyWindow::destroy() failed with {:?}",
result.unwrap_err()
);
}
}