在.NET中,当您对windows服务进行编程时,您可以处理外部请求以停止,这样您就可以推迟并完成一些处理,而不是直接终止进程。
当计划任务试图停止控制台应用程序时,是否有类似的情况?任务调度器中的设置具有";如果运行中的任务在被请求时没有停止,则强制其停止";"设置"选项卡下的选项。对我来说,这意味着它首先请求停止进程,并在终止它之前给它一个机会。我确实看到一些内容引用了任务调度程序,如果应用程序在3分钟后没有完成,它就会终止它。
如果.NET中没有内置的功能来处理停止请求,那么我们是否可以利用Windows API外部功能,如Windows消息等?
根据此处的描述:https://learn.microsoft.com/en-us/windows/win32/api/taskschd/nf-taskschd-itasksettings-get_allowhardterminate
获取或设置一个布尔值,该值指示任务计划程序服务可以使用TerminateProcess终止任务。服务将尝试通过发送WM_close通知来关闭正在运行的任务,如果任务没有响应,则只有当此属性设置为true时,任务才会终止。
Task Scheduler将首先向程序的主窗口发送一条WM_CLOSE
消息。如果这不起作用;"硬终止";,则该过程将使用CCD_ 2来终止。
对于控制台程序,任务调度程序将尝试关闭其控制台窗口。默认情况下,当控制台窗口关闭时,或者当按下Ctrl+C或Ctrl+Break时,控制台程序将立即终止。如果要处理这些事件,可以使用SetConsoleCtrlHandler
添加一个处理程序函数。
.NET有Console.CancelKeyPress
事件,它可以处理Ctrl+C和Ctrl+Break按下,并且它实际上在后台使用了SetConsoleCtrlHandler
。但是,它只处理CTRL_C_EVENT
和CTRL_BREAK_EVENT
,因此关闭控制台窗口等事件仍然不被处理。
下面是我的示例,它使用SetConsoleCtrlHandler
来处理控制台应用程序中的退出事件。
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace TestConsoleExit
{
internal class Program
{
enum CtrlType : int
{
CtrlCEvent,
CtrlBreakEvent,
CtrlCloseEvent,
CtrlLogoffEvent,
CtrlShutdownEvent
}
delegate bool HandlerRoutine(CtrlType dwCtrlType);
[DllImport("kernel32")]
static extern bool SetConsoleCtrlHandler(HandlerRoutine HandlerRoutine, bool Add);
static void Main(string[] args)
{
SetConsoleCtrlHandler(ExitHandler, true);
for (; ; )
{
Console.ReadLine();
}
}
static bool ExitHandler(CtrlType ctrlType)
{
Console.WriteLine();
Console.WriteLine(ctrlType);
if (ctrlType == CtrlType.CtrlCEvent || ctrlType == CtrlType.CtrlBreakEvent)
{
// you can return true to cancel exiting when handling Ctrl+C and Ctrl+Break
return true;
}
else
{
// you cannot cancel exiting in other events, but you can delay it for a few seconds
Thread.Sleep(3000);
return false;
}
}
}
}
请注意,任务调度器只给程序大约一秒钟的时间来完成对WM_CLOSE
或CTRL_CLOSE_EVENT
的处理。一秒钟后,您的程序将终止。