【问题标题】:Console, ctrl+c vs close button click控制台,ctrl+c 与关闭按钮单击
【发布时间】:2016-06-24 02:11:44
【问题描述】:

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

但是,当我单击 [X] 关闭按钮时,也会引发事件,但在短时间内,我的应用程序被我强行关闭 - 当“结束执行”事件仍在进行中时。

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

编辑:

我设置:

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

  public delegate void ControlEventHandler(ConsoleEvent consoleEvent);

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

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

【问题讨论】:

  • 请出示您的代码。我不认为它正在做你认为它正在做的事情。
  • 你为什么使用互操作而不是:Console.CancelKeyPressmsdn.microsoft.com/en-us/library/…
  • 您无法阻止用户关闭控制台窗口。在程序终止之前,你得到回调来做一些有用的事情,仅此而已。一旦你从回调中返回或花费太长时间来做有用的事情,操作系统就会介入并杀死窗口。功能,而不是错误。
  • @AndyJ:我正在处理现有代码(无法更改,它是只读存储库)。@HansPassant:所以没有选项可以更改 [x] 点击和应用程序终止之间的延迟?

标签: c# windows windows-7


【解决方案1】:

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

很遗憾,没有。从 Windows Vista 开始,在收到CTRL_CLOSE_EVENT 之后,控制台窗口自动关闭之前,您只允许有 10 秒左右的宽限期。如果您在 10 秒后还没有退出处理程序,那么您的进程将被毫不客气地终止。 (很明显,如果你更早从处理程序返回,你将无法获得完整的 10 秒。)

据我所知,这是确保应用程序不能超越用户意愿的更大设计策略的一部分。 Older versions of the SDK documentation 谈到如果进程在某个超时期限内没有响应,则会出现一个对话框,但所有提及的内容都从 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 只是通知,让您有机会在被终止之前进行清理。无法阻止终止或延长宽限期。

我只能想到一种解决方法,那就是禁用控制台窗口本身的关闭按钮。我看到您使用的是 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);
        }
    }
}

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

【讨论】:

  • 谢谢。但对我来说,处理程序需要 3 秒,然后应用程序被终止:/
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-12
相关资源
最近更新 更多