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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18036863/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 11:06:33  来源:igfitidea点击:

Why does Environment.Exit() not terminate the program any more?

c#.netwindows

提问by Hans Passant

This is something I discovered just a few days ago, I got confirmation that it isn't just limited to my machine from this question.

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

The easiest way to repro it is by starting a Windows Forms application, add a button and write this code:

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

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

The program fails afterthe Exit() statement executes. On Windows Forms you get "Error creating window handle".

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

Enabling unmanaged debugging makes it somewhat clear what's going on. The COMmodal loop is executing and allows a WM_PAINT message to be delivered. That's fatal on a disposed form.

启用非托管调试可以清楚地了解正在发生的事情。在COM模式循环正在执行,并允许待递送WM_PAINT消息。这对已处理的表单来说是致命的。

The only facts I've gathered so far are:

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

  • It isn't just limited to running with the debugger. This also fails without one. Rather poorly as well, the WER crash dialog shows up twice.
  • It doesn't have anything to do with the bitness of the process. The wow64 layer is pretty notorious, but an AnyCPU build crashes the same way.
  • It doesn't have anything to do with the .NET version, 4.5 and 3.5 crash the same way.
  • The exit code doesn't matter.
  • Calling Thread.Sleep() before calling Exit() doesn't fix it.
  • This happens on the 64-bit version of Windows 8, and Windows 7 does not seem to be affected the same way.
  • This should be relatively new behavior, I haven't seen this before. I see no relevant updates delivered through Windows Update, albeit that the update history isn't accurate on my machine any more.
  • This is grossly breaking behavior. You would write code like this in an event handler for AppDomain.UnhandledException, and it crashes the same way.
  • 它不仅限于使用调试器运行。这也失败了。同样糟糕的是,WER 崩溃对话框出现了两次
  • 它与过程的位数无关。wow64 层非常臭名昭著,但 AnyCPU 构建也会以同样的方式崩溃。
  • 它与 .NET 版本没有任何关系,4.5 和 3.5 以同样的方式崩溃。
  • 退出代码无关紧要。
  • 在调用 Exit() 之前调用 Thread.Sleep() 并不能修复它。
  • 这种情况发生在 64 位版本的 Windows 8 上,而 Windows 7 似乎不会受到同样的影响。
  • 这应该是相对较新的行为,我以前从未见过。我看不到通过Windows Update提供的相关更新,尽管更新历史记录在我的机器上不再准确。
  • 这是严重的破坏行为。您可以在 AppDomain.UnhandledException 的事件处理程序中编写这样的代码,它会以同样的方式崩溃。

I'm particularly interested in what you could possibly do to avoid this crash. Particularly the AppDomain.UnhandledException scenario stumps me; there are not a lot of ways to terminate a .NET program. Please do note that calling Application.Exit() or Form.Close() are not valid in an event handler for UnhandledException, so they are not workarounds.

我对您可能采取的措施来避免这次崩溃特别感兴趣。尤其是 AppDomain.UnhandledException 场景让我很难过;终止 .NET 程序的方法并不多。请注意,调用 Application.Exit() 或 Form.Close() 在 UnhandledException 的事件处理程序中无效,因此它们不是解决方法。



UPDATE: Mehrdad pointed out that the finalizer thread could be part of the problem. I think I'm seeing this and am also seeing some evidence for the 2 second timeout that the CLR gives the finalizer thread to finish executing.

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

The finalizer is inside NativeWindow.ForceExitMessageLoop(). There's an IsWindow() Win32 function there that roughly corresponds with the code location, offset 0x3c when looking at the machine code in 32-bit mode. It seems that IsWindow() is deadlocking. I cannot get a good stack trace for the internals however, the debugger thinks the P/Invokecall just returned. This is hard to explain. If you can get a better stack trace then I'd love to see it. Mine:

终结器位于 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

Nothing above the ForceExitMessageLoop call, unmanaged debugger enabled.

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

采纳答案by Hans Passant

I contacted Microsoft about this problem and that seemed to have paid off. At least I'd like to think it did :). Although I didn't get a confirmation of a resolution back from them, the Windows group is difficult to contact directly and I had to use an intermediary.

我就这个问题联系了微软,这似乎得到了回报。至少我想它确实做到了:)。虽然我没有从他们那里得到解决方案的确认,但很难直接联系到 Windows 小组,我不得不通过中间人。

An update delivered through Windows Update solved the problem. The noticeable 2 second delay before the crash is no longer present, strongly suggesting that the IsWindow() deadlock got solved. And the program shuts down cleanly and reliably. The update installed patches for Windows Defender, wdboot.sys, wdfilter.sys, tcpip.sys, rpcrt4.dll, uxtheme.dll, crypt32.dll and wintrust.dll

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

Uxtheme.dll is the odd-duck out. It implements the Visual Styles theming API and is used by this test program. I can't be sure, but my money is on that one as the source of the problem. The copy in C:\WINDOWS\system32 has version number 6.2.9200.16660, created on August 14th, 2013 on my machine.

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

Case closed.

案件结案。

回答by Joe

This doesn't explain why it's happening, but I wouldn't call Environment.Exitin a button event handler like your sample - instead close the main form as suggested in rene's answer.

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

As for an AppDomain.UnhandledExceptionhandler, maybe you could just set Environment.ExitCoderather than calling Environment.Exit.

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

I'm not sure what you're trying to achieve here. Why do you want to return an exit code from a Windows Forms application? Normally exit codes are used by console applications.

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

I'm particularly interested in what you could possibly do to avoid this crash Calling Environment.Exit() is required to prevent the WER dialog from showing.

我对您可能采取的措施避免此崩溃特别感兴趣 需要调用 Environment.Exit() 来防止 WER 对话框显示。

Do you have a try/catch in the Main method? For Windows Forms applications I always have a try/catch around the message loop as well as the unhandled exception handlers.

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

回答by user541686

I don't know why it doesn't work "any more", but I think Environment.Exitexecutes pending finalizers. Environment.FailFastdoesn't.

我不知道为什么它不工作“更多”,但我认为Environment.Exit执行挂起的终结。Environment.FailFast没有。

It might be that (for some bizarre reason) you have weird pending finalizers that must run afterward, causing this to happen.

可能是(出于某种奇怪的原因)您有奇怪的待定终结器必须在之后运行,导致这种情况发生。

回答by Hans Passant

I've found same problem in our app, we have resolved it with the following construct:

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

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