代码之家  ›  专栏  ›  技术社区  ›  Slipfish

FormClosingEventArgs.CloseReason中的错误?

  •  6
  • Slipfish  · 技术社区  · 15 年前

    我面临的要求

    大约有12个人正在使用此应用程序,但我们只希望允许4个人通过传统方法关闭应用程序(alt+f4,file>exit,close)

    如果使用任何其他方法(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
    }
    

    问题

    如果用户(不允许关闭)尝试通过传统方法关闭应用程序,则尝试使用任务管理器关闭 密切接触 枚举本身似乎没有重置,因此导致任务管理器弹出提示强制关闭,从而阻止应用程序清理。

    问题

    这是一个bug,还是我丢失了一些东西,这些东西将重置 密切接触 合拢 事件已取消。

    2 回复  |  直到 14 年前
        1
  •  6
  •   Deanna superuser    14 年前

    .NET Reflector是您了解WinForms操作方式的朋友。

    窗体类有一个名为 密切接触 当生成您在 关闭 事件。这个内部字段设置在我能找到的四个不同的地方。这些是……

    1, form.close()方法设置closeReason=userClosing。

    这就相当于手动调用 表单() 方法通常是某些用户操作的结果,例如 文件&出口 用户正在选择菜单选项。显然,这是一个用户操作。

    2, wm_syscommand(sc_close)设置closeReason=userClosing。

    这个 窗口过程 形式 处理 Sc-关闭 通过设置 密切接触 用户关闭 让默认窗口进程执行并关闭应用程序。这是有道理的 Sc-关闭 当用户按下窗口关闭Chrome按钮或从右键单击标题栏中选择关闭选项时发送。两者都是用户操作,因此设置 密切接触 用户关闭 显示正确。

    三, wndproc处理消息 WM_CLOSE (0x10)with closereadon=任务管理关闭

    麦密 由任务管理器和其他应用程序发送以关闭窗口,如果 密切接触 当前等于 没有 它更新到 任务管理结束 . 请注意,此问题只有在以下情况下才会更新 没有 我认为这对你来说是个问题。

    4, wndproc处理消息0x11和0x16,closeReason=windowsShutdown

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

    所以你的核心问题是 密切接触 被重置回 没有 当你取消 关闭 事件。因此,上述第3点永远不会将值正确更新为 任务管理结束 如果是在你取消之后。由于closereson是一个内部字段,因此不能直接更新它。但你可以作弊,这是我过去用过的一种方法。您需要使用反射来访问内部字段,然后将其重置为 没有 当你设置 取消=真 在事件处理程序中。

    我没有测试过这段代码,但是你需要一些……

    PropertyInfo pi = typeof(Form).GetProperty("CloseReason",
                                               BindingFlags.Instance |
                                               BindingFlags.SetProperty |
                                               BindingFlags.NonPublic);
    
    pi.SetValue(this, CloseReason.None, null);
    
        2
  •  0
  •   veljkoz Danko Valkov    15 年前

    我认为如果进程是由任务管理器启动的(即,操作系统…他是一个“大老板”,你不能否认这一点,就像关闭你的程序一样。

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

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

    如果您有一个在后台运行的Windows服务,并且跟踪实例的运行情况,那么最好是这样。这样,用户可能不会意识到这样的进程存在,因为它不是他们的应用程序,您可以使用它跟踪应用程序关闭。