但是,在Windows 8.1下进行的任何测试中,我总是得到CloseReason.UserClosing的原因。但是在这种情况下(与普通的CloseReason.UserClosing相比),我有大约0.2秒的时间运行用户代码后,我的程序被终止!
这是Windows 8.1的新行为吗?
是的,我看到了这个问题。这是一个Windows的变化,之前的任务管理器直接向窗口发送WM_CLOSE通知。现在它发出与使用关闭按钮(WM_SYSCOMMAND,SC_CLOSE)相同的命令,或按Alt+F4或使用系统菜单关闭窗口。因此,Winforms无法区分任务管理器和用户关闭窗口之间的区别,你将得到CloseReason.UserClosing。
接下来会发生预期的情况,如果你没有快速响应关闭命令,那么任务管理器将使用TerminateProcess()函数强制结束你的程序。
请记住,当用户通过任务管理器中止你的程序时,试图保存数据是不好的实践。如果你的程序出现故障,用户通常会使用这个功能,你不能真正信任数据,你可能会写入垃圾数据。现在,由于你的保存代码被中止,高概率会出现部分写入的文件或数据库数据不再可用。
没有简单的解决方法,Windows很可能不会修补以恢复旧行为。非常重要的是,你以事务方式保存数据,这样如果保存代码中止,就不会破坏有价值的数据。对于文件数据,请使用File.Replace()函数,对于数据库写入,请使用数据库事务。
检测这种情况的一种不完美的方法是使用Form.Deactivate和Activate事件。如果你看到Deactivate事件并且FormClosing事件触发,则很有可能另一个程序正在终止你的程序。
但通常处理这种情况的方法是常见的,如果用户在不保存数据的情况下结束程序,则会显示一个对话框询问是否保存数据。任务管理器确保不会进一步执行此操作。
另一种确定任务管理器何时关闭程序的解决方案是检查主窗体或其任何控件是否具有焦点。当您通过任务管理器关闭应用程序时,该应用程序没有焦点,而如果您通过关闭按钮或Alt + F4关闭,则该应用程序具有焦点。我使用了一个简单的if检查:
private void MyForm_Closing(object sender, FormClosingEventArgs e)
{
if (this.ContainsFocus)
{
// Put user close code here
}
}
Message.LParam
有关于这个的信息...但是不太可靠。 - Sriram Sakthivel