FormClosingEventArgs.CloseReason中的错误?

我要求的要求

大约有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 } 

问题

如果用户(不允许关闭)尝试通过传统方法关闭应用程序,则尝试使用任务管理器关闭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。

FormWndProc通过将closeReason设置为UserClosing来处理SC_CLOSE系统命令,并让默认窗口proc执行并关闭应用程序。 这是有道理的,因为当用户按下窗口关闭chrome按钮或从右键单击标题栏选择关闭选项时发送此SC_CLOSE 。 两者都是用户操作,因此将closeReason设置为UserClosing似乎是正确的。

3, WndProc使用closeReadon = TaskManagerClosing处理消息WM_CLOSE (0x10)

任务管理器和其他应用程序发送WM_CLOSE以关闭窗口,如果closeReason当前等于None,则将其更新为TaskManagerClosing 。 请注意这个问题,只有当它是None时才更新它,因为我觉得这对你来说是一个问题。

4, WndProc使用closeReason = WindowsShutDown处理消息0x11和0x16

这不是很有趣,因为您不关心这种情况,但它只是关闭消息的标准处理。

因此,您遇到的核心问题是,当您取消Closing事件时, closeReason不会重置为None 。 因此,如果在取消后发生,则上面的第3点将永远不会正确地将值更新为TaskManagerClosing 。 由于closeReasson是内部字段,因此无法直接更新。 但你可以作弊,这是我过去用过的一种方法。 您需要使用reflection来访问内部字段,然后在事件处理程序中设置Cancel = true时将其重置为None

我没有测试过这段代码但是你需要的东西……

 PropertyInfo pi = typeof(Form).GetProperty("CloseReason", BindingFlags.Instance | BindingFlags.SetProperty | BindingFlags.NonPublic); pi.SetValue(this, CloseReason.None, null); 

我认为如果由任务管理员(即操作系统……他是’大老板’)启动你的进程就不能让你的进程无法关闭,你可以否认它就像关闭你的程序一样没有意义。

接下来最好的事情是记录应用程序的状态,然后使用一些启动选项实例化您的进程的另一个实例,以接管您离开的状态。 操作系统会终止您的进程,但您将立即启动另一个进程。

此外,如果用户点击应用程序列表中的TaskManager“转到进程”,并从那里结束进程,我认为你根本不会收到任何事件…

也许最好是你有一个在幕后运行的Windows服务,并跟踪一个实例正在运行。 这样,用户可能不会意识到这样的进程存在,因为它不是他们的应用程序,并且您可以使用它来跟踪应用程序关闭。