为什么Environment.Exit()不终止程序了吗?(Why does Environment.Exit() not terminate the program anymore?)
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 Winforms application, add a button and write this code:
private void button1_Click(object sender, EventArgs e) { MessageBox.Show("yada"); Environment.Exit(1); // Kaboom! }
The program fails after the Exit() statement executes. On Winforms you get "Error creating window handle".
Enabling unmanaged debugging makes it somewhat clear what's going on. The COM modal loop is executing and allows a WM_PAINT message to be delivered. That's fatal on a disposed form.
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, 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 anymore.
This is grossly breaking behavior, you would write code like this in an event handler for AppDomain.UnhandledException and it crashes the same way.
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.
UPDATE: Mehrdad pointed out that the finalizer thread could be part of the problem. I think I'm seeing this, also seeing some evidence for the 2 second timeout that the CLR give the finalizer thread to finish executing.
The finalizer is inside NativeWindow.ForceExitMessageLoop(). There's an IsWindow() winapi 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 pinvoke call just returned. This is hard to explain. If you can get a better stack trace then I'd love to see it. Mine:
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.
解决方案
I contacted Microsoft about this problem and that seemed to have payed 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.
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
Uxtheme.dll is the odd-duck out, it implements the Visual Styles theming api and is used by this test program. Can't be sure but my money is on that one as the source of the problem. The copy in c:windowssystem32 has version number 6.2.9200.16660, created on August 14th, 2013 on my machine.
Case closed.
这是我发现的短短数天前,我得到了确认,这不是仅仅局限于我的机器从this问题。
最简单的方法来瑞普它是通过启动一个WinForms应用程序,添加一个按钮,写这篇code:
私人无效的button1_Click(对象发件人,EventArgs的){ 的MessageBox.show(亚达); Environment.Exit(1); // KABOOM! }
该计划失败的在的退出()语句执行。在你的WinForms得到错误创建窗口句柄。
启用非托管调试使得它有点清楚这是怎么回事。在COM模式循环正在执行,并允许待递送WM_PAINT消息。这是一个致命的布置形式。
我到目前为止所收集的唯一事实是:
在这不仅仅限于与调试运行。这也失败,没有之一。相当差为好,WER错误对话框显示出来的两次的
在它没有什么做的过程中位数,在WOW64层为pretty的臭名昭著而是值为anycpu构建崩溃的方式相同。
在它没有任何关系的.NET版本,4.5和3.5的崩溃一样。
退出code无所谓。
在调用exit()没有解决之前,调用Thread.sleep()方法。
在这种情况发生在64位版本的Windows 8,Windows 7中似乎并没有受到影响相同的方式。
这应该是比较新的行为,我以前没见过这个。我看到通过Windows Update提供任何相关的更新,尽管该更新历史不是我的机器上准确了。
这是严重断裂的行为,你会写code像这样的事件处理程序AppDomain.UnhandledException和崩溃的方式相同。
我在什么你可能做,以避免这种崩溃特别感兴趣。特别是AppDomain.UnhandledException情况下树桩我,不会有很多的方法来终止一个.NET程序。请大家注意,调用Application.Exit()或Form.Close()是不是在事件处理程序UnhandledException无效,因此它们不是解决方法。
更新:迈赫达德指出,终结器线程可能是问题的一部分。我想我看到这一点,也看到了一些证据,2秒超时的CLR给终结器线程完成执行。
终结里面NativeWindow.ForceExitMessageLoop()。这里有一个IsWindow()函数WINAPI那里,大致相当于用code的位置,当机器code在32位模式下寻找偏移0x3C符号。似乎IsWindow()被死锁。我不能获得良好的堆栈跟踪的内部然而,调试器认为的PInvoke调用刚刚返回。这是很难解释。如果你能得到一个更好的堆栈跟踪话,我很乐意看到它。我的:
System.Windows.Forms.dll的!System.Windows.Forms.NativeWindow.ForceExitMessageLoop()+ 0x3C符号字节 System.Windows.Forms.dll中!System.Windows.Forms.NativeWindow.Finalize()+为0x16字节 [原产于托管过渡] KERNEL32.DLL!@ BaseThreadInitThunk @ 12()+ 0xe字节 ntdll.dll中!___ RtlUserThreadStart @ 8()+ 0x27字节 ntdll.dll中!__ RtlUserThreadStart @ 8()+ 0x1b字节
没有上面的ForceExitMessageLoop电话,非托管调试启用。
解决方案
我联系了微软关于这个问题,而且似乎已经所许关。至少我想,认为它确实:)。虽然我没有得到解决,从他们回来的确认,Windows组难以直接接触,我不得不使用的媒介。
通过Windows Update提供的更新解决了这个问题。飞机坠毁前的显着延迟2秒不再是present,强烈提示IsWindow()的僵局得到解决。而程序关闭干净,可靠。已安装的更新补丁的Windows Defender,wdboot.sys,wdfilter.sys,TCPIP.SYS,Rpcrt4.dll中,的uxtheme.dll,crypt32.dll和wintrust.dll
的Uxtheme.dll是奇数鸭子出来,它实现了视觉样式主题化的API,并使用该测试程序。不能肯定,但我的钱是一个为问题的根源。在C副本: WINDOWS SYSTEM32有版本号6.2.9200.16660,于2013年8月14号在我的机器上创建
结案。