Description
I tried this code:
App P:
#![windows_subsystem = "windows"]
fn main() {
std::process::Command::new("<path_to_app_C>").spawn().unwrap();
std::thread::sleep(std::time::Duration::from_secs(100));
}
App C:
fn main() {
loop {
println!("Hello World!");
std::thread::sleep(std::time::Duration::from_secs(1));
}
}
Build this in Windows.
I expected to see this happen:
Since P
has "windows" subsystem, it will create no console window (i.e. no conhost.exe process). Since C
is a console app, when the process is created, I expect to see one console window that prints "Hello World" infinitely.
Instead, this happened: explanation
App C
creates its console window but no text is printed.
What I suspect the cause of the issue
In Windows, spawn() eventually calls to CreateProcessW
with a STARTUPINFO
, whose dwFlags
is hard coded to STARTF_USESTDHANDLES
. Additionally, it also get device handles of stdin, stdout and stderr with GetStdHandle
, and set them to the STARTUPINFO
. Since app P
uses "windows" subsystem, it does not have console. stdout is always INVALID_HANDLE_VALUE
. Combining STARTF_USESTDHANDLES
with INVALID_HANDLE_VALUE
in STARTUPINFO
causes the unexpected behavior.
If I make a call to CreateProcessW
with same parameters except a "zeroed" STARTUPINFO
, it exhibits the correct behavior.
Suggestion
spawn() should only conditionally set the STARTF_USESTDHANDLES
flag if it can obtain those device handles, and never set any of those handles INVALID_HANDLE_VALUE
. Like this (pseudo code):
let mut si = zeroed_startupinfo();
si.cb = mem::size_of::<c::STARTUPINFO>() as c::DWORD;
si.hStdInput = stdin.to_handle().unwrap_or(0);
si.hStdOutput = stdout.to_handle().unwrap_or(0);
si.hStdError = stderr.to_handle().unwrap_or(0);
if si.hStdInput != 0 || si.hStdOutput != 0 || si.hStdError != 0 {
si.dwFlags |= c::STARTF_USESTDHANDLES;
}
Meta
rustc --version --verbose
:
rustc 1.63.0 (4b91a6ea7 2022-08-08)
binary: rustc
commit-hash: 4b91a6ea7258a947e59c6522cd5898e7c0a6a88f
commit-date: 2022-08-08
host: x86_64-pc-windows-msvc
release: 1.63.0
LLVM version: 14.0.5