stdio_override/
windows.rs

1use std::fs::File;
2use std::io;
3use std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
4use std::ptr;
5
6use winapi::shared::minwindef::{BOOL, DWORD, FALSE, TRUE};
7use winapi::um::handleapi::{CloseHandle, DuplicateHandle, GetHandleInformation, INVALID_HANDLE_VALUE};
8use winapi::um::processenv::{GetStdHandle, SetStdHandle};
9use winapi::um::processthreadsapi::GetCurrentProcess;
10use winapi::um::winbase::HANDLE_FLAG_INHERIT;
11use winapi::um::winbase::{STD_ERROR_HANDLE, STD_INPUT_HANDLE, STD_OUTPUT_HANDLE};
12use winapi::um::winnt::DUPLICATE_SAME_ACCESS;
13
14pub(crate) use std::os::windows::io::{AsRawHandle as AsRaw, IntoRawHandle as IntoRaw, RawHandle as Raw};
15
16pub(crate) fn as_raw(io: &impl AsRawHandle) -> RawHandle {
17    io.as_raw_handle()
18}
19pub(crate) fn into_raw(io: impl IntoRawHandle) -> RawHandle {
20    io.into_raw_handle()
21}
22
23pub(crate) fn override_stdin(io: RawHandle, owned: bool) -> io::Result<File> {
24    override_stdio(STD_INPUT_HANDLE, io, owned)
25}
26pub(crate) fn override_stdout(io: RawHandle, owned: bool) -> io::Result<File> {
27    override_stdio(STD_OUTPUT_HANDLE, io, owned)
28}
29pub(crate) fn override_stderr(io: RawHandle, owned: bool) -> io::Result<File> {
30    override_stdio(STD_ERROR_HANDLE, io, owned)
31}
32
33pub(crate) fn reset_stdin(old: RawHandle) -> io::Result<()> {
34    reset_stdio(STD_INPUT_HANDLE, old)
35}
36pub(crate) fn reset_stdout(old: RawHandle) -> io::Result<()> {
37    reset_stdio(STD_OUTPUT_HANDLE, old)
38}
39pub(crate) fn reset_stderr(old: RawHandle) -> io::Result<()> {
40    reset_stdio(STD_ERROR_HANDLE, old)
41}
42
43fn override_stdio(stdio: DWORD, other: RawHandle, owned: bool) -> io::Result<File> {
44    let original = handle_res(unsafe { GetStdHandle(stdio) })?;
45
46    let other = if owned {
47        other
48    } else {
49        // If it isn't owned, duplicate the handle to prevent closing the original handle from
50        // closing the stdio handle.
51
52        let process = unsafe { GetCurrentProcess() };
53
54        let mut handle_information = 0;
55        io_res(unsafe { GetHandleInformation(other, &mut handle_information as *mut DWORD) })?;
56        let inherit_handle = if handle_information & HANDLE_FLAG_INHERIT == HANDLE_FLAG_INHERIT { TRUE } else { FALSE };
57
58        let mut target = ptr::null_mut();
59        io_res(unsafe {
60            DuplicateHandle(
61                process,
62                other,
63                process,
64                &mut target as *mut RawHandle,
65                0, // ignored
66                inherit_handle,
67                DUPLICATE_SAME_ACCESS,
68            )
69        })?;
70
71        target
72    };
73
74    io_res(unsafe { SetStdHandle(stdio, other) })?;
75
76    Ok(unsafe { File::from_raw_handle(original) })
77}
78fn reset_stdio(stdio: DWORD, other: RawHandle) -> io::Result<()> {
79    let current = handle_res(unsafe { GetStdHandle(stdio) })?;
80
81    io_res(unsafe { SetStdHandle(stdio, other) })?;
82
83    io_res(unsafe { CloseHandle(current) })?;
84
85    Ok(())
86}
87
88fn io_res(res: BOOL) -> io::Result<()> {
89    if res == 0 {
90        Err(io::Error::last_os_error())
91    } else {
92        Ok(())
93    }
94}
95
96fn handle_res(res: RawHandle) -> io::Result<RawHandle> {
97    if res == INVALID_HANDLE_VALUE {
98        Err(io::Error::last_os_error())
99    } else {
100        Ok(res)
101    }
102}
103
104impl AsRawHandle for crate::StdinOverride {
105    fn as_raw_handle(&self) -> RawHandle {
106        self.original.as_raw_handle()
107    }
108}
109impl AsRawHandle for crate::StdoutOverride {
110    fn as_raw_handle(&self) -> RawHandle {
111        self.original.as_raw_handle()
112    }
113}
114impl AsRawHandle for crate::StderrOverride {
115    fn as_raw_handle(&self) -> RawHandle {
116        self.original.as_raw_handle()
117    }
118}