我需要通过单击控制台的退出按钮和任何其他组合键来调用一些函数来停止某些进程。 我尝试使用 SetConsoleCtrlHandler 方法,但通过此处理程序调用的函数没有时间完成,因为仅 5 秒后,主进程就会自动关闭。 有没有一个解决方案可以确保关闭控制台后调用的每个方法都有足够的时间完成而不是只有 5 秒?
下面是我正在使用的代码:
using System.Runtime.InteropServices;
namespace ConsoleApp1
{
public class Test
{
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(SetConsoleCtrlEventHandler handler, bool add);
private delegate bool SetConsoleCtrlEventHandler(CtrlType sig);
private enum CtrlType
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT = 1,
CTRL_CLOSE_EVENT = 2,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT = 6
}
private static bool Handler(CtrlType signal)
{
switch (signal)
{
case CtrlType.CTRL_BREAK_EVENT:
case CtrlType.CTRL_C_EVENT:
case CtrlType.CTRL_LOGOFF_EVENT:
case CtrlType.CTRL_SHUTDOWN_EVENT:
case CtrlType.CTRL_CLOSE_EVENT:
Console.WriteLine("Closing");
// TODO Cleanup resources
while (true) { Thread.Sleep(100); }
Environment.Exit(0);
return false;
default:
return false;
}
}
public static void Main(string[] args)
{
// Register the handler
SetConsoleCtrlHandler(Handler, true);
while (true)
{
Thread.Sleep(50);
}
}
}
}
所以这里的主要问题是你的控制台实际上在清理发生之前被强制终止。控制台只有这么多时间来进行任何类型的清理。
您可以通过在单独的线程中执行此操作来解决此问题,但您需要确保不会发生无限循环或冲突。
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace ConsoleApp1
{
public class Test
{
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(SetConsoleCtrlEventHandler handler, bool add);
private delegate bool SetConsoleCtrlEventHandler(CtrlType sig);
private enum CtrlType
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT = 1,
CTRL_CLOSE_EVENT = 2,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT = 6
}
private static ManualResetEvent _exitEvent = new ManualResetEvent(false);
private static bool Handler(CtrlType signal)
{
switch (signal)
{
case CtrlType.CTRL_C_EVENT:
case CtrlType.CTRL_BREAK_EVENT:
case CtrlType.CTRL_LOGOFF_EVENT:
case CtrlType.CTRL_SHUTDOWN_EVENT:
case CtrlType.CTRL_CLOSE_EVENT:
Console.WriteLine("Closing... Starting cleanup.");
// Start cleanup in a new thread
Thread cleanupThread = new Thread(Cleanup);
cleanupThread.Start();
// Doesn't exit b4 cleanup finishes
_exitEvent.WaitOne();
Console.WriteLine("Cleanup completed. Exiting.");
Environment.Exit(0);
return true;
default:
return false;
}
}
// Does the cleanup
private static void Cleanup()
{
// resource cleanup here
Thread.Sleep(7000); // Simulate long task (e.g. 7 seconds)
_exitEvent.Set(); // Signal that cleanup is done
}
public static void Main(string[] args)
{
// Register the handler
SetConsoleCtrlHandler(Handler, true);
Console.WriteLine("Application is running. Press Ctrl+C to exit.");
while (true)
{
Thread.Sleep(50); // Simulates the work
}
}
}
}