Why does my Windows desktop process appear to exit immediately with no stdout?
我有一个" hello world " Windows桌面应用程序,其来源来自此官方演练。
当我从Linux的Windows子系统运行该程序时,我得到的行为是我期望的:shell阻塞,等待进程退出,并且仅在进程退出后才再次出现shell提示符。然后,我可以检查进程退出代码(通过从
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),都不会将标准输出输出到终端。 (已通过
好像原始进程已经生成了一个守护程序进程来运行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 中的伪环境变量%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,例如,默认情况下为
-
默认情况下,同步调用控制台子系统和GUI子系统应用程序,然后在内置
$? 变量中反映这两种应用程序类型的退出代码。 -
要选择异步调用,请使用后置
& 从后台作业执行调用;例如(Notepad.exe &) -
注意:
(...) 禁止显示& 触发的shell的作业控制状态消息(在bash ,zsh 和dash 中有效,但在ksh 中无效);有关详细信息,请参见此答案。
-
注意:
[1] GUI和控制台子系统与那些旨在由最终用户直接运行的可执行文件有关。如本帮助主题中有关PE格式(Windows上的可执行文件的格式)所述,存在其他子系统。詹姆斯(OP)提供链接的提示。
[2]尽管GUI子系统应用程序可以根据需要显式创建控制台,但这种控制台独立于控制台子系统调用者的控制台。甚至可以将其附加到控制台子系统调用方的先前存在的控制台上,但是调用方将不会意识到这一点,因此将无法捕获,重定向或传递GUI写入该控制台的任何输出。 -子系统应用程序。