控制台,ctrl+c vs 关闭按钮点击

Console, ctrl+c vs close button click

当我在控制台中单击 ctrl+c window 时,会引发事件并且应用程序可以执行一些应该在退出前执行的代码。

然而,当我点击[X]关闭按钮时,事件也被引发,但在很短的时间内,我的应用程序被强行关闭 - 当'end execution'事件仍在进行中。

是否可以在windows强行关闭应用程序之前设置更长的超时时间?

编辑:

即时设置:

  [DllImport("Kernel32.dll")]
  static extern bool SetConsoleCtrlHandler(ControlEventHandler e, bool add);

  public delegate void ControlEventHandler(ConsoleEvent consoleEvent);

当我在控制台 window 上单击 ctrl+c 时,我收到:CTRL_C,我可以在 mu 事件处理程序中处理代码。

当我点击 [x] 关闭按钮时,我收到 CTRL_CLOSE 标志,我也可以处理处理程序,但只能持续 1-2 秒。然后控制台 windwo 消失了...

Is it possible to set longer timeout before windows will forcibly close app?

很遗憾,没有。从 Windows Vista 开始,在控制台 window 自动关闭之前,您在收到 CTRL_CLOSE_EVENT 后只有 10 秒左右的宽限期。如果在 10 秒过去后您还没有退出处理程序,那么您的进程将被毫不客气地终止。 (显然,如果你 return 更早地从 handler 那里得到,你将不会得到完整的 10 秒。)

据我所知,这是更大的设计策略的一部分,以确保应用程序不能凌驾于用户的意愿之上。 Older versions of the SDK documentation spoke of a dialog box that would appear if the process didn't respond within a certain time-out period, but all mention of that is gone from the current version of the SDK documentation。该对话框在 Vista 中变为 MIA,它不再存在。这可能与应用程序也无法再阻止系统关闭这一事实有关。

这不会影响您按下 Ctrl+C,因为这会引发不同的信号 — CTRL_C_EVENT。与 Ctrl+Break 相同,引发 CTRL_BREAK_EVENT。但据我从文档中得知,CTRL_CLOSE_EVENTCTRL_LOGOFF_EVENTCTRL_SHUTDOWN_EVENT 只是 notifications,给你一个清理的机会在你被终止之前。无法阻止终止或延长宽限期。

我只能想到一种解决方法,那就是禁用控制台 window 本身的关闭按钮。我看到您使用的是 C#,因此需要一些 P/Invoke:

[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();

[DllImport("user32.dll")]
static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

[DllImport("user32.dll")]
static extern bool DeleteMenu(IntPtr hMenu, uint uPosition, uint uFlags);

private const uint MF_BYCOMMAND = 0x0;
private const uint SC_CLOSE     = 0xF060;

void DisableConsoleCloseButton()
{
    IntPtr hWnd = GetConsoleWindow();
    if (hWnd != IntPtr.Zero)
    {
        IntPtr hMenu = GetSystemMenu(hWnd, false);
        if (hMenu != IntPtr.Zero)
        {
            DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
        }
    }
}

如果您走这条路,您显然需要为用户提供一些从您的应用程序中关闭控制台的方法 window。在 Win32 领域,该功能将调用 FreeConsole 函数来关闭它,但我敢打赌它包含在 .NET 类 之一中。太久了,我记不起它叫什么了。