关于C#:为什么我的Windows桌面进程似乎没有标准输出立即退出?

Why does my Windows desktop process appear to exit immediately with no stdout?

我有一个" hello world " Windows桌面应用程序,其来源来自此官方演练。

当我从Linux的Windows子系统运行该程序时,我得到的行为是我期望的:shell阻塞,等待进程退出,并且仅在进程退出后才再次出现shell提示符。然后,我可以检查进程退出代码(通过从wWinMain返回此代码,将其设置为3):

1
2
3
jim@LAPTOP-SMUS1UJN:/mnt/c/Users/james/source/repos/DesktopApp/x64/Release$ ./DesktopApp.exe  # blocks until I close the window ...
jim@LAPTOP-SMUS1UJN:/mnt/c/Users/james/source/repos/DesktopApp/x64/Release$ echo $?
3

但是,这不是从命令提示符或PowerShell运行程序时得到的行为。在这里,进程开始了,但是shell程序声称进程立即退出了,立即给了我新的提示!但是该过程显然还没有退出,因为它创建的窗口仍然存在,我可以与之交互。

在两种情况下(用于Linux的Windows子系统和PowerShell),都不会将标准输出输出到终端。 (已通过std::cout <<"test"验证,该命令不会在终端上打印任何内容。)

好像原始进程已经生成了一个守护程序进程来运行win32东西。但是我不认为这是正在发生的事情,因为Linux的Windows子系统至少会阻塞直到退出。

当我使用Visual Studio创建"控制台" C应用程序时,它的行为符合预期。奇怪的提前退出而没有输出的行为仅发生在我的" desktop " win32程序中。

那么,为什么命令提示符或PowerShell声称该过程立即退出?它的标准输出在哪里?


乔纳森·波特(Jonathan Potter)在对该问题的评论中提供了关键的指示;详细说明:

任何给定的Windows应用程序都属于这两个互斥类别之一[1]:

  • GUI子系统应用程序,例如Notepad.exe

    • 此类应用程序通常会创建GUI窗口,有时甚至根本没有UI。

    • 由于未与控制台关联,因此无法写入标准输出(stdout)或标准错误(stderr)流。[2]

  • 控制台子系统应用程序,例如findstr.exe

    • 这类应用程序在被调用时会创建一个控制台窗口,或者在一个预先存在的窗口中运行,通常是由命令行shell程序(例如cmd.exe或PowerShell)创建的。

    • 它们将输出写入标准输出(stdout)和/或标准错误(stderr)输出流。

Windows上的

(基于控制台的)命令行shell,例如cmd.exe和PowerShell:

  • 同步调用控制台子系统应用程序并报告其退出代码:通过cmd.exe中的伪环境变量%ERRORLEVEL%和PowerShell中的变量$LASTEXITCODE

    • 此外,默认情况下,此类应用程序输出的stdout和/或stderr输出到控制台,但也可以通过管道捕获,重定向或传递给其他控制台子系统应用程序。
  • 默认情况下以启动和忘记的方式异步调用GUI子系统应用程序。

    • 也就是说,默认情况下,shell既不等待应用程序完成,也不报告退出代码。

    • 但是,这两个shell程序都以选择加入的方式提供同步调用,包括退出代码报告:

      • cmd.exe中,使用start /WAIT ...进行同步执行,然后将退出代码反映在%ERRORLEVEL%中;请参阅内部start命令的文档。

      • 在PowerShell中,使用Start-Process -Wait ...进行同步执行;要获取进程退出代码,请使用$ps = Start-Process -Wait -PassThru ...,然后检查$ps.ExitCode-请参见Start-Process cmdlet的文档。

相比之下,WSL(Linux的Windows子系统)的POSIX式shell,例如,默认情况下为bash

  • 默认情况下,同步调用控制台子系统和GUI子系统应用程序,然后在内置$?变量中反映这两种应用程序类型的退出代码。

  • 要选择异步调用,请使用后置&从后台作业执行调用;例如(Notepad.exe &)

    • 注意:(...)禁止显示&触发的shell的作业控制状态消息(在bashzshdash中有效,但在ksh中无效);有关详细信息,请参见此答案。

[1] GUI和控制台子系统与那些旨在由最终用户直接运行的可执行文件有关。如本帮助主题中有关PE格式(Windows上的可执行文件的格式)所述,存在其他子系统。詹姆斯(OP)提供链接的提示。

[2]尽管GUI子系统应用程序可以根据需要显式创建控制台,但这种控制台独立于控制台子系统调用者的控制台。甚至可以将其附加到控制台子系统调用方的先前存在的控制台上,但是调用方将不会意识到这一点,因此将无法捕获,重定向或传递GUI写入该控制台的任何输出。 -子系统应用程序。