#![cfg(windows)]
use std::io;
use std::os::windows::io::{AsRawHandle, OwnedHandle, RawHandle};
use windows_sys::Win32::Foundation::{GetLastError, HANDLE, WAIT_OBJECT_0};
use windows_sys::Win32::System::Threading::{
GetExitCodeProcess, GetProcessId, TerminateProcess, WaitForSingleObject, INFINITE,
};
const STILL_ACTIVE: u32 = 259;
pub(crate) struct ConPtyChild {
process: OwnedHandle,
_main_thread: OwnedHandle,
}
impl ConPtyChild {
pub(crate) fn new(process: OwnedHandle, main_thread: OwnedHandle) -> Self {
Self {
process,
_main_thread: main_thread,
}
}
fn process_handle(&self) -> HANDLE {
self.process.as_raw_handle() as HANDLE
}
pub(crate) fn pid(&self) -> u32 {
unsafe { GetProcessId(self.process_handle()) }
}
pub(crate) fn try_wait(&self) -> io::Result<Option<u32>> {
let mut code: u32 = 0;
let ok = unsafe { GetExitCodeProcess(self.process_handle(), &mut code) };
if ok == 0 {
return Err(io::Error::last_os_error());
}
if code == STILL_ACTIVE {
return Ok(None);
}
Ok(Some(code))
}
pub(crate) fn wait(&self) -> io::Result<u32> {
let r = unsafe { WaitForSingleObject(self.process_handle(), INFINITE) };
if r != WAIT_OBJECT_0 {
let err = unsafe { GetLastError() };
return Err(io::Error::other(format!(
"WaitForSingleObject returned {r}, last_error = {err}"
)));
}
let mut code: u32 = 0;
let ok = unsafe { GetExitCodeProcess(self.process_handle(), &mut code) };
if ok == 0 {
return Err(io::Error::last_os_error());
}
Ok(code)
}
pub(crate) fn kill(&self) -> io::Result<()> {
let ok = unsafe { TerminateProcess(self.process_handle(), 1) };
if ok == 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
pub(crate) fn as_raw_handle(&self) -> RawHandle {
self.process.as_raw_handle()
}
}