为什么 Environment. Exit()不再终止程序?

这是我几天前发现的东西,我从 这个问题得到确认,它不仅仅局限于我的机器。

最简单的复制方法是启动一个 Windows 窗体应用程序,添加一个按钮并编写以下代码:

    private void button1_Click(object sender, EventArgs e) {
MessageBox.Show("yada");
Environment.Exit(1);         // Kaboom!
}

程序失败 之后的 Exit ()语句执行。在 Windows 窗体你得到“错误创建窗口句柄”。

启用非托管调试可以在一定程度上清楚发生了什么。COM模式循环正在执行,并允许传递 WM _ PAINT 消息。这对已处理的尸体来说是致命的。

到目前为止,我收集到的唯一事实是:

  • 它不仅仅局限于使用调试器运行。如果没有一个,这种做法也会失败。WER 崩溃对话框显示的 两次也很糟糕。
  • 这和过程的艰辛没有任何关系。Wow64层非常臭名昭著,但 AnyCPU 构建也会以同样的方式崩溃。
  • 它与.NET 版本没有任何关系,4.5和3.5以相同的方式崩溃。
  • 出口密码不重要。
  • 在调用 Exit ()之前调用 Thread.Sleep ()并不能修复它。
  • 这种情况发生在64位版本的 Windows8上,而 Windows7似乎没有受到同样的影响。
  • 这应该是相对较新的行为,我以前没见过。我没有看到通过 Windows 更新传递的相关更新,尽管在我的机器上更新历史不再准确。
  • 这种行为太过分了。您可以在 AppDomain 的事件处理程序中编写这样的代码。UnhandledException,它也会以同样的方式崩溃。

我特别感兴趣的是你能做些什么来避免这次坠机。尤其是 AppDomain。方案难倒了我; 没有很多方法可以终止。NET 程序。请注意,调用应用程序。出口()或表格。Close ()在 UnhandledException 的事件处理程序中无效,因此它们不是解决方案。


更新: Mehrdad 指出终结器线程可能是问题的一部分。我想我看到了这一点,并且也看到了一些证据,表明 CLR 给终结器线程提供了2秒钟的超时来完成执行。

终结器位于 NativeWindow 内部。ForceExitMessageLoop ().这里有一个 IsWindow () Win32函数,它大致对应于代码位置,在32位模式下查看机器代码时偏移量为0x3c。看起来 IsWindow ()是死锁的。我不能得到一个很好的内部堆栈跟踪,然而,调试器认为 请求调用刚刚返回。这很难解释。如果你能得到一个更好的堆栈跟踪,然后我很乐意看到它。我的:

System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.ForceExitMessageLoop() + 0x3c bytes
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.Finalize() + 0x16 bytes
[Native to Managed Transition]
kernel32.dll!@BaseThreadInitThunk@12()  + 0xe bytes
ntdll.dll!___RtlUserThreadStart@8()  + 0x27 bytes
ntdll.dll!__RtlUserThreadStart@8()  + 0x1b bytes

在启用非托管调试器的 ForceExitMessageLoop 调用之上没有任何内容。

33585 次浏览

这并不能解释为什么会发生这种情况,但是我不会像您的示例那样在按钮事件处理程序中调用 Environment.Exit,而是按照 Rene 的回答中的建议关闭主窗体。

至于 AppDomain.UnhandledException处理程序,也许您可以只设置 Environment.ExitCode,而不是调用 Environment.Exit

我不知道你想达到什么目的。为什么要从 Windows 窗体应用程序返回退出代码?通常,控制台应用程序使用退出代码。

我特别感兴趣的是你能做些什么来避免这次坠机 调用 Environment. Exit ()可以防止显示 WER 对话框。

Main 方法中有 try/catch 吗?对于 Windows 窗体应用程序,我总是在消息循环和未处理的异常处理程序周围使用 try/catch。

我不知道为什么它不工作 “不再”,但我认为 Environment.Exit执行挂起的终结器。

这可能是因为(出于某种奇怪的原因)您有一些奇怪的挂起的终结器,它们必须在之后运行,从而导致这种情况发生。

我就这个问题联系了微软,似乎得到了回报。至少我愿意这么认为:)。尽管我没有从他们那里得到解决方案的确认,但 Windows 组很难直接联系,我不得不使用一个中间人。

通过 WindowsUpdate 交付的更新解决了这个问题。崩溃前明显的2秒钟延迟不再存在,这强烈表明 IsWindow ()死锁得到了解决。程序干净可靠地关闭了。更新为 Windows Defender、 wdboot.sys、 wdfilter.sys、 tcpip.sys、 rpcrt4.dll、 uxtheme.dll、 crypt32.dll 和 wintrust. dll 安装了补丁

Uxtheme.dll 是个奇怪的东西。它实现了 VisualStyles 主题化 API,并由此测试程序使用。我不能确定,但我打赌这是问题的根源。C: WINDOWS system 32中的副本版本号为6.2.9200.16660,创建于2013年8月14日,在我的机器上。

结案。

我在我们的应用程序中也发现了同样的问题,我们用以下结构解决了它:

Environment.ExitCode=1;
Application.Exit();