大约有12人正在使用此应用程序,但我们只想允许4通过传统方法关闭应用程序(Alt + F4,文件>退出,关闭)
如果使用任何其他方法(TaskManager,WindowsShutdown)或其中一个允许的用户关闭应用程序,我们需要执行一些清理(关闭一些连接通道)
private void formClosing(object sender, FormClosingEventArgs e)
{
// If a user is allowed to close the application, an empty file (filename)
// will be in the root directory of the application.
if(e.CloseReason == CloseReason.UserClosing && !File.Exists("filename"))
{
e.Cancel = true;
return;
}
// Cleanup
}
Run Code Online (Sandbox Code Playgroud)
如果用户(不允许关闭)尝试通过传统方法关闭应用程序,则尝试使用任务管理器关闭CloseReason枚举似乎不会自行重置,从而导致任务管理器弹出提示强制关闭,从而阻止清理申请.
这是一个错误,或者我错过了什么,会在FormClosing事件被取消后重置CloseReason.
在研究WinForms的运行方式时,.NET Reflector是您的朋友.
Form类有一个名为closeReason的内部字段,在生成您在Closing事件中检查的事件参数时使用.这个内部字段设置在我可以找到的四个不同的地方.这些是...
1,Form.Close()方法设置closeReason = UserClosing.
这是有道理的,因为手动调用Form.Close()方法通常是某些用户操作的结果,例如用户选择了File-> Exit菜单选项.显然,这是一个用户操作.
2,WM_SYSCOMMAND(SC_CLOSE)设置closeReason = UserClosing.
该WndProc中的的形式处理SC_CLOSE通过设置系统命令closeReason到UserClosing和让默认的窗口过程执行和关闭应用程序.这是有道理的,因为当用户按下窗口关闭chrome按钮或从右键单击标题栏选择关闭选项时发送此SC_CLOSE.两者都是用户操作,因此将closeReason设置为UserClosing显示正确.
3,WndProc WM_CLOSE
使用closeReadon = TaskManagerClosing 处理消息(0x10)
WM_CLOSE
由任务管理器和其他应用程序发送以关闭窗口,如果closeReason当前等于None,则将其更新为TaskManagerClosing.请注意这个问题,只有当它是None时才会更新,因为我觉得这对你来说是一个问题.
4,WndProc使用closeReason = WindowsShutDown处理消息0x11和0x16
这不是很有趣,因为您不关心这种情况,但它只是关闭消息的标准处理.
因此,您遇到的核心问题是,当您取消Closing事件时,closeReason不会重置为None.因此,如果在取消后发生,则上面的第3点将永远不会正确地将值更新为TaskManagerClosing.由于closeReasson是内部字段,因此无法直接更新.但你可以作弊,这是我过去用过的一种方法.您需要使用反射来访问内部字段,然后在事件处理程序中设置Cancel = true时将其重置为None.
我没有测试过这段代码但是你需要的东西......
PropertyInfo pi = typeof(Form).GetProperty("CloseReason",
BindingFlags.Instance |
BindingFlags.SetProperty |
BindingFlags.NonPublic);
pi.SetValue(this, CloseReason.None, null);
Run Code Online (Sandbox Code Playgroud)