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

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

最容易的方法是通过启动一个Windows窗体应用程序,添加一个button并写下如下代码:

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

Exit()语句执行程序失败。 在Windows窗体上,您会看到“创build窗口句柄时出错”。

启用不受pipe理的debugging使得有点清楚发生了什么事情。 COM模式循环正在执行,并允许传递WM_PAINT消息。 这是致命的处置forms。

我迄今为止收集的唯一事实是:

  • 它不仅限于使用debugging器运行。 没有一个也是失败的。 WER崩溃对话也显示了两次
  • 这与这个过程的缺点没有任何关系。 wow64图层是非常臭名昭着的,但是一个AnyCPU构build崩溃了同样的方式。
  • 它与.NET版本没有任何关系,4.5和3.5以同样的方式崩溃。
  • 退出代码无关紧要。
  • 在调用Exit()之前调用Thread.Sleep()不能修复它。
  • 这发生在64位版本的Windows 8上,而Windows 7似乎也没有受到同样的影响。
  • 这应该是比较新的行为,我以前没有见过。 我看不到通过Windows更新提供的相关更新 ,尽pipe更新历史在我的机器上不再是准确的。
  • 这是严重的打破行为。 您可以在AppDomain.UnhandledException的事件处理程序中编写这样的代码,并以相同的方式崩溃。

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


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

终结器在NativeWindow.ForceExitMessageLoop()中。 这里有一个IsWindow()Win32函数,大致对应于代码位置,在32位模式下查看机器代码时偏移0x3c。 看来IsWindow()是死锁的。 我不能得到一个好的内部堆栈跟踪,但是debugging器认为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调用,非托pipedebugging器启用。

我联系了微软这个问题,似乎已经得到了回报。 至less我想这样做:)。 虽然我没有得到他们的决议确认,但Windows组很难直接联系,我不得不使用中间人。

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

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

案件结案。

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

这可能是(有一些奇怪的原因)你有怪异悬挂终结者必须运行后,造成这种情况发生。

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

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

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

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

Main方法中有try / catch吗? 对于Windows窗体应用程序,我总是围绕消息循环以及未处理的exception处理程序进行try / catch。