我最近刚刚发现了这个问题,我从这个问题得到了验证,证实这不仅仅局限于我的电脑。
最简单的重现方法是启动一个Windows Forms应用程序,添加一个按钮,并编写以下代码:
private void button1_Click(object sender, EventArgs e) {
MessageBox.Show("yada");
Environment.Exit(1); // Kaboom!
}
程序在执行Exit()语句后失败。在Windows表单中,你会收到“创建窗口句柄错误”的报错信息。
启用非托管调试使情况有所好转。COM模态循环正在执行并允许传递WM_PAINT消息。这对于Disposed(已释放)的窗体来说是致命的。
到目前为止,我收集到的唯一事实是:
- 这不仅仅限于在调试器中运行。没有调试器时也会失败,而且表现得相当糟糕,WER崩溃对话框出现了两次。
- 与进程的位数无关。wow64层非常臭名昭著,但是AnyCPU版本的程序也会以同样的方式崩溃。
- 与.NET版本无关,4.5和3.5以同样的方式崩溃。
- 退出代码并不重要。
- 在调用Exit()之前调用Thread.Sleep()不能修复它。
- 这在Windows 8的64位版本上发生,而Windows 7似乎没有受到同样的影响。
- 这应该是相对较新的行为,我以前没有见过这种情况。尽管我的电脑上更新历史记录不准确,但我没有看到有任何相关的Windows Update更新发布。
- 这是极其糟糕的行为。你会在AppDomain.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调用之上没有任何内容,启用了非托管调试器。
这是在64位版本的Windows 8上发生的
Hans已经这么说了! - Parimal RajExit(0)
的这种行为,更改ExitCode
并没有帮助。现在我改用Process.GetCurrentProcess().Kill()
,没有任何问题,可以正常工作。 - Sriram Sakthivel