问题 为什么GUI应用程序阻止批处理文件?


Internet上有许多引用声称GUI和控制台应用程序之间的区别之一是从批处理文件运行GUI应用程序不会阻止其执行,而运行控制台应用程序会阻止它。

很少有很多参考文献,特别是来自SO / SE:

而且,我自己也记得这是/是真的。

但它似乎没有这种方式。

我在一个简单的批处理文件上对此进行了测试,例如:

echo Pre
notepad
echo Post

Post 直到我关闭记事本才打印。为什么,当记事本显然是一个GUI应用程序?

我已经在Windows 8,7和XP上对此进行了测试,以排除在最新版本的Windows中行为发生变化的可能性。我试图将命令扩展禁用为可能的罪魁祸首之一。


1855
2017-10-15 12:19


起源

许多win32应用程序都是多线程的,它们将启动并将控制权返回给批处理文件。 - foxidrive
@foxidrive:他们如何将控制权返回给批处理文件? - Martin Prikryl
我在这里谈论GUI和控制台应用程序之间的差异。它们都在自己的进程中运行。你可能会谈论内部命令,比如 echo 确实在运行 cmd.exe。 - Martin Prikryl
好的。我首先虽然很容易回答,但事实并非如此。仅供参考,我在Windows上使用vim(gvim.exe并且它不像其他人那样阻止。可能 这些线条很长 ? - ixe013
很有意思。它在批处理脚本中阻塞,但不会阻止命令提示符。尝试 echo pre&notepad&echo post 在两种情况下。在你提出问题之前,我从未注意到这种差异。 - dbenham


答案:


它与您启动的应用程序如何运行和终止有关。一些程序启动另一个进程然后终止,其他程序继续运行。 Calc.exe和Notepad.exe只是运行,直到您关闭它们。 Write.exe和由于文件关联而启动的任何程序(例如,位图,波形文件,控制面板小程序等),实际启动另一个程序,然后启动它们的进程终止将控制权返回到批处理文件所以它可以执行下一行。

这里有些例子:

@echo off

echo Starting Calc.exe
calc.exe
echo Calc was closed by the user

echo Starting Notepad.exe
Notepad.exe
echo Notepad was closed by the user

echo Starting WordPad.exe
write.exe
echo Write launched WordPad and then terminated allowing the batchfile to continue

echo Starting Services.msc
services.msc
echo Windows launched MMC, opened services.msc, then returned control to the batchfile

echo Launching WMP via Chord.wav
c:\windows\media\chord.wav
echo Windows launched WMP, opened Chord.wav, then returned control to the batchfile

CMD进程知道Calc和Notepad仍在运行,因为它自己产生了它们。 CMD过程确实如此  知道其他人仍在运行,因为中间过程终止了。

要观察这一点,请打开 Process Explorer 并查看分层树中显示的进程。 Calc.exe和Notepad.exe都作为运行批处理文件的CMD进程的子进程保留。 Write.exe和MMC.exe(services.msc)都成为顶级进程,不再是CMD进程的子进程。 WMPlayer.exe仍然是svchost.exe的子进程,这是Windows启动它的方式。 CMD进程不知道它们仍在运行,因为  没有启动它们,其他一些Windows进程也没有。所以执行继续......

另一个例子是MSPaint.exe的功能。如果使用Windows内置文件关联为BMP运行它,则Windows将启动MSPaint.exe,并立即将控制权返回给批处理文件。但是,如果将BMP传递给MSPaint.exe,则批处理文件将等待您在继续之前关闭MSPaint。 (我在没有BMP的开发机器上,所以创建一个名为C:\ MyBitmap.bmp的简单机器。)

@echo off
C:\MyBitmap.bmp
calc.exe
mspaint.exe C:\MyBitmap.bmp
notepad.exe

Calc.exe将立即打开,在关闭MSPaint.exe的第二个实例之前,Notepad.exe将无法打开。

我知道您没有询问是否通过文件关联启动Windows进程,但它只是演示了拥有进程如何更改。如果CMD进程拥有已启动的进程,则应等待它终止以继续执行。如果生成的进程将控制权交给另一个进程,则CMD进程不知道孙进程,并继续执行。


9
2017-11-08 02:48



感谢您的答复。虽然它没有回答我的问题。请参阅我的问题中的参考文献,他们肯定不会处理使用您描述的技术的过程(我知道)。例如(第二个)[stackoverflow.com/questions/8177695/...。它处理 notepad 好像它不会阻止批处理文件。明显 notepad 不使用该技术。 - Martin Prikryl
您想知道为什么GUI应用程序会阻止批处理文件继续执行,直到GUI应用程序终止。这正是我所描述的。无论您引用的链接中是什么内容,CMD处理器都不会在批处理文件中执行下一行,直到它启动的程序终止。有时程序会创建另一个进程(CMD进程的孙子)然后终止。 CMD解释器看到它启动的进程终止,并继续执行。否则等待。它是GUI应用程序还是控制台应用程序并不重要。结果是一样的。 - James L.
运用 start 启动一个程序(没有 /wait option)改变CMD处理器的行为。它不是等待进程在继续之前终止,而是继续。如果你不使用 start,它将一直等到它启动的程序终止。它永远不会等待孙子进程终止。它只监视它自己创建的直接子进程。 - James L.
如果您只考虑我的问题的主题,那么是的,您的答案是正确的。如果你完全阅读它,而不是。我不能把所有东西都写成一个简短的主题。我问为什么人们相信批处理文件没有阻止。也许我说错了,我的错。无论如何,看起来我没有得到正确答案。我无法相信所有关于SO和其他地方的讨论都是完全错误的。赏金即将到期,所以它看起来像是你:) - Martin Prikryl
@MartinPrikryl:关于人们的信仰,你的问题从来没有任何问题。如果有的话,你的问题将被视为非主题,因为它本来是基于意见的。你的问题的实质内容确实已在这里得到解答,我只是没有看到更多地关注你这个完全有效的问题。 - Andriy M


因为它等待返回代码。你可以使用 开始 命令创建一个单独的子进程:

@echo pre
@start "notepad" notepad
@echo post

4
2017-10-15 12:23



感谢您的回答。这是什么意思“它等待返回代码”? (与“它等待进程终止”相反?)。我知道我可以用 start,我只相信它应该没有它。 - Martin Prikryl
应该是一样的。每次打电话后 .exe 命令提示符期望返回代码以检查命令是否已成功执行。例如。 color.exe 55 & echo %errorlevel% 。 color 55 将失败并将设置errorlevel 1。 - npocmaka
好的,但你错过了我的问题。你说的不应该是真的,请查看我的问题中的参考文献。它们都涉及如何使批处理等待进程完成(就好像它实际上没有)。 - Martin Prikryl
我应该删除我的答案。无论如何 - 有一种方法可以检查Windows附带的应用程序是否会阻止控制台 - 非阻塞(非强制GUI)将具有 This program cannot be run in DOS mode.字符串写在其中的某处(您可以使用类型命令,文本编辑器或strings.exe - >technet.microsoft.com/en-us/sysinternals/... 外部应用程序不适用,但它适用于使用visual studio构建的应用程序。(记事本没有它,但它在write.exe中显示)。可能这就是原因 - bit.ly/167vF8R - npocmaka
AllocConsole *。 - npocmaka


我从NT 3.1开始使用Windows,当你只输入程序名称(而不是使用START命令)时,我也会说“cmd.exe不会等待GUI程序终止”。虽然内存越来越暗淡,但我相信它最初是以这种方式运作的。但今天,我的声明是互动的,对于“批处理”文件是错误的。因此被提醒,我模糊地认为它是故意改变的,因为天真的批处理作者期望顺序执行,但我不能确定,我不知道什么时候。


1
2017-08-04 01:25





我认为答案就在于这个问题 Windows和Console应用程序之间的区别

我引用两个答案。

康拉德鲁道夫回答:

唯一的区别是控制台应用程序总是会生成一个控制台,如果它没有从一个控制台启动(或者控制台在启动时被主动抑制)。另一方面,Windows应用程序不会生成控制台。它仍然可以附加到一个existant控制台或使用AllocConsole创建一个新控制台。

这使得Windows应用程序更适合GUI应用程序或后台应用程序,因为您通常不希望为这些应用程序创建终端窗口。

oefe回答:

从命令提示符以交互方式调用时,控制台和Windows应用程序的行为有所不同:

启动控制台应用程序时,在控制台应用程序退出之前,命令提示符不会返回。当您启动Windows应用程序时,该命令立即返回。

批处理文件不是这样;他们将一直等到应用程序退出。

cmd和批处理之间的这种bahviour的差异使你认为它之前有用。


0
2018-01-24 14:17



感谢您的回答。我一直都知道这种差异。虽然它可能让我感到困惑,但它并不能解释为什么存在其他问题。 - Martin Prikryl