msys2如何显示非控制台应用程序的控制台输出?

3
如果我编译这段源代码:
#include <stdio.h>

int main(int argc, char* args[]) {
  printf("Done!\n");
  return 0;
}

msys2中使用mingw-w64-x86_64-toolchain工具链,通过gcc hello.c -o hello -mwindows编译hello.c文件,并在msys2内运行它,将会看到:

enter image description here

同时,如果我从PowerShell(或cmd)调用同一可执行文件,我会看到:

enter image description here

说实话,考虑到-mwindows表示生成Windows可执行文件而不是控制台可执行文件,我对后者的出现并不感到惊讶-我已经看到过很多次了。
但是msys2如何显示该输出?
1个回答

1
在Windows上,控制台应用程序和GUI应用程序之间几乎没有区别,C运行时stdio代码通常不关心这一点,它只关心标准Win32句柄。主要区别在于父应用程序中的CreateProcess如何工作。控制台应用程序会连接到父级的标准Win32句柄(如果父级有控制台)。如果父级没有控制台,则为应用程序创建新的控制台窗口。父级可以向CreateProcess传递可选标志,以强制/拒绝新的控制台。GUI应用程序不会连接到标准Win32句柄,也不会创建新的控制台。Powershell.exe是一个真正的控制台应用程序,它可以使用默认的CreateProcess处理方式。因为您的应用程序不是控制台应用程序,所以它将被创建为没有标准句柄的应用程序,因此它没有任何可写入的地方。msys2终端应用程序可能不是真正的控制台应用程序,并且可能使用强制句柄(STARTF_USESTDHANDLES)调用CreateProcess。这些句柄可能是管道句柄。您的应用程序将把这些句柄视为重定向的stdio句柄,并以类似于cmd.exe执行yourconsoleapp.exe | otherconsoleapp.exe的方式执行。

是的,MSYS2使用命名管道进行标准I/O。对于在写入管道或磁盘文件时使用完全缓冲的控制台应用程序来说,这是一个常见问题,可以通过winpty等解决方法来解决。 - Eryk Sun
1
关于CMD,有趣的是它暂时修改了自己的标准句柄,并依赖继承而不是使用“STARTUPINFO”标准句柄。它首先尝试使用“bInheritHandles”为“TRUE”调用“CreateProcessW”。如果成功,则创建的子进程将具有父进程标准句柄值的副本,无论它们是否被继承。内部的“ConsoleHandle”不会被继承到非控制台应用程序中,但可继承的标准I/O句柄在所有情况下都会被继承,因此我们可以执行类似于“.\hello.exe | more”的操作,假设“hello.exe”是OP的非控制台构建。 - Eryk Sun
1
如果我们通过文件类型关联来运行文件,则CMD使用ShellExecuteExW,在这种情况下,结果取决于相关的可执行文件是否为控制台应用程序。ShellExecuteExW不会继承句柄,因此,如果".EXT"与我们的非控制台应用程序"hello.exe"相关联,则"file.ext | more"将无法正常工作。如果我们将"hello.exe"构建为控制台应用程序,则它将可以正常工作,因为NtCreateUserProcess会隐式复制(而不是继承)标准句柄到控制台应用程序。 - Eryk Sun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接