在这篇伟大的文章中, Keith解释了Powershell中终止和非终止错误之间的区别.根据Keith从调用.NET对象或类型成员抛出的异常是非终止错误.
确实,如果我们定义这个.NET类进行测试:
$a = Add-Type 'public class bla { public static void bl() { throw new System.ApplicationException("test"); }}' -PassThru
Run Code Online (Sandbox Code Playgroud)
然后这个功能:
function tst { 1 | write-host; $a::bl(); 2 | Write-host }
Run Code Online (Sandbox Code Playgroud)
我们将看到,当调用tst函数时,异常似乎是非终止的:第二个Write-Host起作用.
但考虑一下:
function tst2 { try { tst } catch { "Catch!" } }
Run Code Online (Sandbox Code Playgroud)
如果我们打开文档,我们可以读到catch响应或处理脚本中的终止错误.在文章的整个文本中,文章所处理的错误在许多地方被称为"终止".
因此,当我们在第二个Write-Host上面运行该行时,不会运行但是catch块会运行.似乎我们的非终止错误突然终止了.
怎么会?
另一个观察结果是,有了旧的陷阱,它仍然是非终止错误:
function tst3 { tst trap { "Trap!" } }
Run Code Online (Sandbox Code Playgroud)
现在,从实际角度来看,我想要实现的目标如下.在一段代码中,我想终止从.NET代码抛出的异常.我想留下cmdlet终止的终止错误和cmdlet非终止的非终止错误.
我该如何实现这一目标?
例:
Do-Something
Call::Something()
Do-SomethingElse
Call::SomethingElse()
Do-YetMoreSomething
Call::YetMoreSomething()
Run Code Online (Sandbox Code Playgroud)
我想终止上面.NET调用的所有异常.我还想终止从cmdlet终止错误.我不想终止cmdlet中的非终止错误.
我有一个“hello world”Windows桌面应用程序,其来源来自这个官方演练。
当我从适用于 Linux 的 Windows 子系统运行此程序时,我得到了预期的行为:shell 阻塞,等待进程退出,并且 shell 提示符仅在进程退出后重新出现。然后我可以检查进程退出代码(此处设置为 3,通过从 中返回wWinMain):
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
Run Code Online (Sandbox Code Playgroud)
但是,这不是我从命令提示符或 PowerShell 运行程序时得到的行为。在这里,进程启动了,但是 shell 声称进程立即退出,立即给我一个新的提示!但该进程显然没有退出,因为它创建的窗口仍然存在,我可以与它交互。
在这两种情况下(适用于 Linux 的 Windows 子系统和 PowerShell),进程 stdout 不会打印到终端。(使用 进行验证std::cout << "test",它不会向终端打印任何内容。)
就好像原始进程生成了一个守护进程来运行 win32 的东西。但我不认为这是正在发生的事情,因为 Linux 的 Windows 子系统至少会阻塞直到退出。
当我使用 Visual Studio 创建“控制台”C++ 应用程序时,它的行为符合预期。这种奇怪的提前退出且无输出的行为只发生在我的“桌面”win32 程序中。
那么,为什么命令提示符或 PowerShell 声称进程立即退出呢?它的标准输出在哪里?