#![allow(unsafe_code)]
use std::mem::size_of;
use windows::core::{w, PCWSTR};
use windows::Foundation::{AsyncStatus, IAsyncOperation};
use windows::Security::Credentials::UI::UserConsentVerificationResult;
use windows::Win32::Foundation::{FALSE, HWND, LPARAM, LRESULT, TRUE, WPARAM};
use windows::Win32::System::Threading::{AttachThreadInput, GetCurrentThreadId};
use windows::Win32::UI::WindowsAndMessaging::{
BringWindowToTop, CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW,
GetForegroundWindow, GetWindowThreadProcessId, MsgWaitForMultipleObjectsEx, PeekMessageW,
RegisterClassExW, SetForegroundWindow, ShowWindow, TranslateMessage, UnregisterClassW,
CW_USEDEFAULT, MSG, MWMO_INPUTAVAILABLE, PM_REMOVE, QS_ALLINPUT, SW_SHOW, WNDCLASSEXW,
WS_EX_TOOLWINDOW, WS_EX_TOPMOST, WS_POPUP,
};
const CLASS_NAME: PCWSTR = w!("EnclaveAppHelloOwnerWindow");
unsafe extern "system" fn wnd_proc(
hwnd: HWND,
msg: u32,
wparam: WPARAM,
lparam: LPARAM,
) -> LRESULT {
DefWindowProcW(hwnd, msg, wparam, lparam)
}
pub(crate) struct ForegroundOwner {
hwnd: HWND,
}
impl ForegroundOwner {
pub(crate) fn create() -> windows::core::Result<Self> {
let hwnd = unsafe {
let wc = WNDCLASSEXW {
cbSize: size_of::<WNDCLASSEXW>() as u32,
lpfnWndProc: Some(wnd_proc),
lpszClassName: CLASS_NAME,
..Default::default()
};
let _ = RegisterClassExW(&wc);
CreateWindowExW(
WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
CLASS_NAME,
w!(""),
WS_POPUP,
CW_USEDEFAULT,
CW_USEDEFAULT,
1,
1,
None,
None,
None,
None,
)?
};
Ok(Self { hwnd })
}
pub(crate) fn hwnd(&self) -> HWND {
self.hwnd
}
pub(crate) fn foreground(&self) {
unsafe {
let _ = ShowWindow(self.hwnd, SW_SHOW);
let fg = GetForegroundWindow();
let our_tid = GetCurrentThreadId();
let fg_tid = GetWindowThreadProcessId(fg, None);
let attached = fg_tid != 0
&& fg_tid != our_tid
&& AttachThreadInput(our_tid, fg_tid, TRUE).as_bool();
BringWindowToTop(self.hwnd).ok();
let _ = SetForegroundWindow(self.hwnd);
if attached {
let _ = AttachThreadInput(our_tid, fg_tid, FALSE);
}
}
}
}
pub(crate) fn pump_until_complete(
op: &IAsyncOperation<UserConsentVerificationResult>,
) -> windows::core::Result<UserConsentVerificationResult> {
loop {
if op.Status()? != AsyncStatus::Started {
break;
}
unsafe {
let mut msg = MSG::default();
while PeekMessageW(&mut msg, None, 0, 0, PM_REMOVE).as_bool() {
let _ = TranslateMessage(&msg);
DispatchMessageW(&msg);
}
let _ = MsgWaitForMultipleObjectsEx(None, 100, QS_ALLINPUT, MWMO_INPUTAVAILABLE);
}
}
op.GetResults()
}
impl Drop for ForegroundOwner {
fn drop(&mut self) {
unsafe {
DestroyWindow(self.hwnd).ok();
UnregisterClassW(CLASS_NAME, None).ok();
}
}
}