use crate::Stdio;
use winapi::shared::minwindef::DWORD;
use winapi::shared::ntdef::HANDLE;
use winapi::um::handleapi::CloseHandle;
use winapi::um::processthreadsapi::GetExitCodeProcess;
use winapi::um::synchapi::WaitForSingleObject;
use winapi::um::winbase::{INFINITE, WAIT_OBJECT_0};
use std::io;
use std::ptr::null_mut;
pub struct Process {
pub(crate) handle: HANDLE,
pub(crate) stdin: Stdio,
pub(crate) stdout: Stdio,
pub(crate) stderr: Stdio,
}
impl Process {
pub fn wait(mut self) -> io::Result<ExitStatus> { self.join_impl() }
fn join_impl(&mut self) -> io::Result<ExitStatus> {
assert!(!self.handle.is_null(), "Process::join_impl already called once");
let wait = unsafe { WaitForSingleObject(self.handle, INFINITE) };
if wait != WAIT_OBJECT_0 { return Err(std::io::Error::last_os_error()); }
let handle = std::mem::replace(&mut self.handle, null_mut());
let _stdin = std::mem::replace(&mut self.stdin, Stdio::null());
let _stderr = std::mem::replace(&mut self.stderr, Stdio::null());
let _stdout = std::mem::replace(&mut self.stdout, Stdio::null());
let mut exit_code = 0;
let succeeded = unsafe { GetExitCodeProcess(handle, &mut exit_code) };
let exit_code = if succeeded != 0 { Some(exit_code) } else { None };
let succeeded = unsafe { CloseHandle(handle) };
if succeeded == 0 { return Err(std::io::Error::last_os_error()); }
Ok(ExitStatus { exit_code })
}
}
impl std::ops::Drop for Process {
fn drop(&mut self) {
if !self.handle.is_null() {
self.join_impl().expect("winapi error while dropping wslapi::Process");
}
}
}
pub struct ExitStatus {
exit_code: Option<DWORD>,
}
impl ExitStatus {
pub fn success(&self) -> bool { self.exit_code == Some(0) }
pub fn code(&self) -> Option<DWORD> { self.exit_code }
}