任务管理器中的“结束任务”总是设置为关闭原因为用户关闭。

8
我想记录客户尝试强制关闭应用程序的行为。我知道没有机会捕获进程终止。但是,通过主窗体关闭事件,可以通过'CloseReason.TaskManagerClosing'原因获取信息。
但是,在Windows 8.1下进行的任何测试中,我总是得到CloseReason.UserClosing的原因。但是在这种情况下(与普通的CloseReason.UserClosing相比),我有大约0.2秒的时间运行用户代码后,我的程序被终止!
这是Windows 8.1的新行为吗?
2个回答

9

是的,我看到了这个问题。这是一个Windows的变化,之前的任务管理器直接向窗口发送WM_CLOSE通知。现在它发出与使用关闭按钮(WM_SYSCOMMAND,SC_CLOSE)相同的命令,或按Alt+F4或使用系统菜单关闭窗口。因此,Winforms无法区分任务管理器和用户关闭窗口之间的区别,你将得到CloseReason.UserClosing。

接下来会发生预期的情况,如果你没有快速响应关闭命令,那么任务管理器将使用TerminateProcess()函数强制结束你的程序。

请记住,当用户通过任务管理器中止你的程序时,试图保存数据是不好的实践。如果你的程序出现故障,用户通常会使用这个功能,你不能真正信任数据,你可能会写入垃圾数据。现在,由于你的保存代码被中止,高概率会出现部分写入的文件或数据库数据不再可用。

没有简单的解决方法,Windows很可能不会修补以恢复旧行为。非常重要的是,你以事务方式保存数据,这样如果保存代码中止,就不会破坏有价值的数据。对于文件数据,请使用File.Replace()函数,对于数据库写入,请使用数据库事务。

检测这种情况的一种不完美的方法是使用Form.Deactivate和Activate事件。如果你看到Deactivate事件并且FormClosing事件触发,则很有可能另一个程序正在终止你的程序。

但通常处理这种情况的方法是常见的,如果用户在不保存数据的情况下结束程序,则会显示一个对话框询问是否保存数据。任务管理器确保不会进一步执行此操作。


Hans,Message.LParam 有关于这个的信息...但是不太可靠。 - Sriram Sakthivel
谢谢,我并不打算在程序关闭时保存数据。我正在寻找一种可靠的方法来记录当我的应用程序以异常方式终止时的情况。客户经常告诉我们他们没有杀死进程,但我非常确定他们这样做了...因为在任何其他情况下,每个步骤都会被详细记录。 - dannyyy
1
记录De/Activate事件是一个很好的解决方案。 - Hans Passant

0

另一种确定任务管理器何时关闭程序的解决方案是检查主窗体或其任何控件是否具有焦点。当您通过任务管理器关闭应用程序时,该应用程序没有焦点,而如果您通过关闭按钮或Alt + F4关闭,则该应用程序具有焦点。我使用了一个简单的if检查:

private void MyForm_Closing(object sender, FormClosingEventArgs e)
{
    if (this.ContainsFocus)
    {
        // Put user close code here
    }
}

如果用户最小化一个程序,然后通过鼠标上下文菜单(右键单击任务面板上的最小化应用程序)关闭它,则“ContainsFocus”仍保持为“false”。因此它并不是真正有用的。 - Rekshino

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接