Consider this program:
#include <windows.h>
#include <stdio.h>
#pragma comment(linker, "/SUBSYSTEM:CONSOLE")
int main(void) {
if (!FreeConsole()) {
MessageBoxA(NULL, "FreeConsole failed", NULL, MB_ICONHAND);
return 1;
}
if (!AllocConsole()) {
MessageBoxA(NULL, "AllocConsole failed", NULL, MB_ICONHAND);
return 1;
}
FILE* newstdout;
if (freopen_s(&newstdout, "CONOUT$", "w", stdout)) {
MessageBoxA(NULL, "freopen_s failed", NULL, MB_ICONHAND);
return 1;
}
if (newstdout != stdout) {
MessageBoxA(NULL, "freopen_s did something wonky", NULL, MB_ICONHAND);
return 1;
}
puts("1");
MessageBoxA(NULL, "Look for 1 then press OK", NULL, 0);
return 0;
}
Steps to reproduce: create a new empty C/C++ project in Visual Studio 2019, go to Project Properties -> Configuration Properties -> Linker -> System and change SubSystem to Not Set, then add the above code to the project in a new file called Source.c
.
Most of the time I run it, it opens a new console with the number 1 in it, like it's supposed to, but sometimes it fails. If I used "Start Without Debugging" (Ctrl+F5) to run it, it fails about 1 run out of 30, with my "freopen_s failed" message. If I used "Start Debugging" (F5) to run it, it also fails about 1 run out of 10, with _NtClose
throwing an exception that says "An invalid handle was specified", with a stack trace pointing at my call to freopen_s
.
Why does this intermittent failure happen? Am I breaking one of the rules of the Windows API, either in the C code or in the project configuration?
Things I tried so far that didn't change the behavior:
- Removing the line with
#pragma
- Using
CON
in place ofCONOUT$
freopen_s
ingstdout
toNUL
before callingFreeConsole
This is messed up, it's not your fault.
FreeConsole()
proceeds to destroy the old console and take down the handle with it. This invalidatesstdout
asynchronously.You really want to do something like this. Note that you really do need to do
stdin
andstderr
as well asstdout
or bad things can happen later.