为什么将Stdout重新打开到新分配的控制台偶尔会失败?
考虑以下程序:
#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;
}
复制步骤:在Visual Studio 2019中创建一个新的空C/C ++项目,转到Project Properties -&GT;配置属性 - &gt;链接器 - &gt;系统并将子系统更改为未设置,然后在名为source.c
的新文件中添加上述代码。
大多数时候我运行它,它会像预定的那样打开一个带有数字1的新控制台,但有时会失败。如果我使用“启动不调试”(CTRL+F5)运行它,则它的“ Freopen_s失败”消息大约在30中失败。如果我使用“开始调试”(F5)运行它,那么它也会失败10中的1个,而_ntclose
抛出一个例外,上面说“指定了无效的句柄”,带有堆栈跟踪指向我呼叫freopen_s
。
为什么这种间歇性失败会发生?我是否在C代码或项目配置中打破Windows API的规则之一?
到目前为止,我尝试过没有改变行为的事情:
- 使用
#pragma
- 使用
con
代替conout $
freopen_s
ingstdout
tonul
在调用freeconsole
之前
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, "CONOUTquot;, "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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这搞砸了,这不是你的错。
freeconsole()
继续销毁旧控制台并用它拆下手柄。这无效stdout
异步。您真的想做这样的事情。请注意,您确实需要做
stdin
和stderr
以及stdout
或不良的事情可能会在以后发生。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.