use std::sync::Once;
use std::sync::atomic::{AtomicBool, Ordering};
pub(super) fn attach_parent() -> bool {
use windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE;
use windows_sys::Win32::System::Console::{
ATTACH_PARENT_PROCESS, AttachConsole, GetStdHandle, STD_ERROR_HANDLE, STD_OUTPUT_HANDLE,
SetConsoleCtrlHandler,
};
static ONCE: Once = Once::new();
static ATTACHED: AtomicBool = AtomicBool::new(false);
ONCE.call_once(|| {
let has = |id| {
let h = unsafe { GetStdHandle(id) };
h != 0 && h != INVALID_HANDLE_VALUE
};
if has(STD_OUTPUT_HANDLE) || has(STD_ERROR_HANDLE) {
return;
}
let ok = unsafe { AttachConsole(ATTACH_PARENT_PROCESS) } != 0;
if ok {
unsafe { SetConsoleCtrlHandler(Some(swallow_interrupts), 1) };
}
ATTACHED.store(ok, Ordering::Relaxed);
});
ATTACHED.load(Ordering::Relaxed)
}
unsafe extern "system" fn swallow_interrupts(event: u32) -> windows_sys::Win32::Foundation::BOOL {
use windows_sys::Win32::System::Console::{CTRL_BREAK_EVENT, CTRL_C_EVENT};
(event == CTRL_C_EVENT || event == CTRL_BREAK_EVENT) as _
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_process_with_handles_keeps_them() {
use windows_sys::Win32::System::Console::{GetStdHandle, STD_ERROR_HANDLE};
let before = unsafe { GetStdHandle(STD_ERROR_HANDLE) };
assert!(!attach_parent());
assert!(!attach_parent(), "once per process, and the answer is kept");
assert_eq!(unsafe { GetStdHandle(STD_ERROR_HANDLE) }, before);
eprintln!("still here");
}
}