Redirecting standard I/O is a bit more involved on Windows due to the lack of a proper interface to map between arbitrary Win32 file handles and higher layer file descriptors/streams.
There are actually three different layers of I/O on Windows:
- Standard? C I/O streams (these are used by
printf
, scanf
, ...)
- POSIX I/O descriptors (these are integers used by
read
, write
, ...)
- Win32 API I/O handles (used by
ReadFile
, WriteFile
, ...)
Redirecting C Streams
To redirect C streams you can use freopen
. For instance, you can redirect C stdout
using:
freopen("log.txt", "w", stdout);
This redirection will generally not redirect I/O done by POSIX or Win32 APIs (they would still read/write the attached Console, if any). In addition, this redirection will not be inherited by child processes. (On POSIX-compliant/non-Windows systems, it is typical that the POSIX API is also the system API and the C API is implemented on top of the POSIX API. In these cases, freopen
is sufficient.)
Redirecting POSIX I/O descriptors
To redirect I/O at the POSIX API level, you can use dup2
. For example, you can reassign file descriptor STDOUT_FILENO
to redirect stdout
, something like:
int fd = open("log.txt", O_WRONLY);
dup2(fd, STDOUT_FILENO);
close(fd);
Unfortunately on Windows, even redirection at the POSIX API level does not guarantee redirection neither at the C nor the Win32 API levels. Whether this will work or not depends on the effort put in the implementation of the C library to map between POSIX file descriptors and Win32 file handles (presuming the C runtime library you are using layered its I/O on top of POSIX to begin with). There is also no guarantee that this redirection will be inherited by spawned children.
Redirecting Std I/O On Windows!
To correctly redirect I/O on Windows you have to redirect at the lowest level (i.e., the Win32 API level) and fix the linkage at higher levels as follows:
- Allocate a new handle by calling
CreateFile
.
- Assign that new handle to the desired std I/O device using
SetStdHandle
.
- Associate that new handle with the corresponding C std file descriptor using
_open_osfhandle
(returns a file descriptor number).
- Redirect the returned file descriptor using the
dup2
technique explained above.
Here is a sample snippet to redirect stdout
:
HANDLE new_stdout = CreateFileA("log.txt", ...);
SetStdHandle(STD_OUTPUT_HANDLE, new_stdout);
int fd = _open_osfhandle(new_stdout, O_WRONLY|O_TEXT);
dup2(fd, STDOUT_FILENO);
close(fd);
P.S. If you can do without I/O redirection inside the program, then you can simply use the Console's I/O redirection at the command line using a tiny Batch file:
@echo off
start "my_gui_app" "path/to/my_gui_app.exe" 1> "path/to/log.txt"