How to capture C's stdout/stderr

I'm writing a GUI program on Windows which needs to call some functions implemented in an external C library. Unfortunately, these functions print out messages into stdout and stderr then I need to redirect/capture them to my own handler.

There are several helps and they are around using open_osfhandle to redirect stdout and stderr to Windows's HANDLE.

But I still don't know how to obtain these C's IO handler in Rust. Many thanks for any help.

You could use the winapi crate for SetStdHandle to change stdin/out/err into pipes, convert the pipes into a Stdio using the FromRawHandle trait.

Full example using WinAPI (in C): https://docs.microsoft.com/en-us/windows/win32/procthread/creating-a-child-process-with-redirected-input-and-output?redirectedfrom=MSDN

1 Like

Thank you, but the problem is how to access stdin/out/err. They are IO handlers create by Windows CRT, I found that they are defined in corecrt_wstdio.h as:

#define stdin  (__acrt_iob_func(0))
#define stdout (__acrt_iob_func(1))
#define stderr (__acrt_iob_func(2))

I've found a tricky way using:

#[link(name = "ucrt")]
extern "C" {
    fn __acrt_iob_func(fileno: u32) -> *mut FILE;
}
...
let stdout = __acrt_iob_func(1);

You can also use cc crate: https://crates.io/crates/cc write function to disable stdout/stderr on C and just call it from Rust.

If you have Windows HANDLE, you can use https://doc.rust-lang.org/std/os/windows/io/trait.FromRawHandle.html to make it a libstd's File or stdio stream.

Similarly you can take a Rust pipe or File, and get HANDLE out of it: https://doc.rust-lang.org/std/os/windows/io/trait.AsRawHandle.html

1 Like

SetStdHandleEx also gives you the previous handle, so you can capture what you need and later switch back to the original handles