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

时间:2013-08-03 20:11:54

标签: c# .net windows

这是我几天前发现的,我得到确认,它不仅限于我this question的机器。

最简单的重做方法是启动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位版本的Windows 8上,而Windows 7似乎没有受到同样的影响。
  • 这应该是比较新的行为,我之前没见过。我看到没有通过Windows Update提供相关更新,尽管我的计算机上的更新历史记录不准确。
  • 这是严重破坏行为。你可以在AppDomain.UnhandledException的事件处理程序中编写这样的代码,它会以同样的方式崩溃。

我特别感兴趣的是你可以做些什么来避免这次崩溃。特别是AppDomain.UnhandledException场景让我感到困惑;没有很多方法可以终止.NET程序。请注意,调用Application.Exit()或Form.Close()在UnhandledException的事件处理程序中无效,因此它们不是解决方法。


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

终结器位于NativeWindow.ForceExitMessageLoop()内。那里有一个IsWindow()Win32函数,大致对应于代码位置,在32位模式下查看机器代码时偏移量为0x3c。似乎IsWindow()正在陷入僵局。我无法获得内部的良好堆栈跟踪,但调试器认为刚刚返回P/Invoke调用。这很难解释。如果你能获得更好的堆栈跟踪,那么我很乐意看到它。矿:

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调用之上没有任何内容,启用了非托管调试器。

4 个答案:

答案 0 :(得分:82)

我与微软就这个问题联系过,这似乎得到了回报。至少我想它确实:)。虽然我没有得到他们的回复确认,但Windows组很难直接联系,我不得不使用中介。

通过Windows Update提供的更新解决了这个问题。崩溃前明显的2秒延迟不再存在,强烈暗示IsWindow()死锁已经解决。程序干净可靠地关闭。此更新安装了Windows Defender,wdboot.sys,wdfilter.sys,tcpip.sys,rpcrt4.dll,uxtheme.dll,crypt32.dll和wintrust.dll的补丁

Uxtheme.dll是奇怪的。它实现了Visual Styles主题API,并由此测试程序使用。我不能确定,但​​我的钱就是那个问题的来源。 C:\ WINDOWS \ system32中的副本的版本号为6.2.9200.16660,于2013年8月14日在我的机器上创建。

案件结案。

答案 1 :(得分:50)

我不知道为什么它不起作用“任何更多”,但我认为Environment.Exit执行待定的终结器。 Environment.FailFast没有。

可能是(由于一些奇怪的原因)你有奇怪的待定终结者必须在之后运行,导致这种情况发生。

答案 2 :(得分:6)

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

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

我不确定你在这里要做什么。为什么要从Windows窗体应用程序返回退出代码?通常,控制台应用程序使用退出代码。

  

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

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

答案 3 :(得分:1)

我在我们的应用中发现了同样的问题,我们已使用以下构造解决了这个问题:

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