如何避免强行终止控制台应用程序?
How to avoid force kill to stop a console application?
我需要能够按需正常关闭控制台应用程序。
使用此 post 我能够在收到 CTRL 事件时控制退出。
然而,我无法使用 taskkill 按需停止应用程序。
如果我尝试命令:
taskkill /im myapp
它响应:
ERROR: The process "MyApp.exe" with PID 23296 could not be
terminated. Reason: This process can only be terminated forcefully
(with /F option).
基于添加到此 post 和 detecting-console-application-exit-in-c 的许多贡献,我构建了以下帮助程序,以在 taskkill 信号时优雅地停止控制台应用程序,但也可在任何其他关闭控制信号时停止:
public class StopController : Form, IMessageFilter
{
//logger
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
static private CancellationTokenSource cancellationTokenSource;
public StopController(CancellationTokenSource cancellationTokenSource)
{
StopController.cancellationTokenSource = cancellationTokenSource;
System.Windows.Forms.Application.AddMessageFilter(this);
SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.WindowState = FormWindowState.Minimized;
this.ShowInTaskbar = false;
}
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == 16)
{
log.Warn("Receiveing WF_Close event. Cancel was fired.");
cancellationTokenSource.Cancel();
}
return true;
}
public static void Activate(CancellationTokenSource cancellationTokenSource)
{
Task.Run(() => Application.Run(new StopController(cancellationTokenSource)));
}
#region unmanaged
//must be static.
private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
{
// Put your own handler here
switch (ctrlType)
{
case CtrlTypes.CTRL_C_EVENT:
log.Warn("CTRL+C received!. Cancel was fired.");
cancellationTokenSource.Cancel();
break;
case CtrlTypes.CTRL_BREAK_EVENT:
log.Warn("CTRL+BREAK received!. Cancel was fired.");
cancellationTokenSource.Cancel();
break;
case CtrlTypes.CTRL_CLOSE_EVENT:
log.Warn("Program being closed!. Cancel was fired.");
cancellationTokenSource.Cancel();
break;
case CtrlTypes.CTRL_LOGOFF_EVENT:
case CtrlTypes.CTRL_SHUTDOWN_EVENT:
log.Warn("User is logging off!. Cancel was fired.");
cancellationTokenSource.Cancel();
break;
default:
log.Warn($"unknow type {ctrlType}");
break;
}
return true;
}
// Declare the SetConsoleCtrlHandler function
// as external and receiving a delegate.
[DllImport("Kernel32")]
public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add);
// A delegate type to be used as the handler routine
// for SetConsoleCtrlHandler.
public delegate bool HandlerRoutine(CtrlTypes CtrlType);
// An enumerated type for the control messages
// sent to the handler routine.
public enum CtrlTypes
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT,
CTRL_CLOSE_EVENT,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT
}
#endregion
}
用法:
StopController.Activate(cancellationTokenSource);
无需更改为windows申请。
我需要能够按需正常关闭控制台应用程序。
使用此 post 我能够在收到 CTRL 事件时控制退出。 然而,我无法使用 taskkill 按需停止应用程序。
如果我尝试命令:
taskkill /im myapp
它响应:
ERROR: The process "MyApp.exe" with PID 23296 could not be terminated. Reason: This process can only be terminated forcefully (with /F option).
基于添加到此 post 和 detecting-console-application-exit-in-c 的许多贡献,我构建了以下帮助程序,以在 taskkill 信号时优雅地停止控制台应用程序,但也可在任何其他关闭控制信号时停止:
public class StopController : Form, IMessageFilter
{
//logger
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
static private CancellationTokenSource cancellationTokenSource;
public StopController(CancellationTokenSource cancellationTokenSource)
{
StopController.cancellationTokenSource = cancellationTokenSource;
System.Windows.Forms.Application.AddMessageFilter(this);
SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.WindowState = FormWindowState.Minimized;
this.ShowInTaskbar = false;
}
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == 16)
{
log.Warn("Receiveing WF_Close event. Cancel was fired.");
cancellationTokenSource.Cancel();
}
return true;
}
public static void Activate(CancellationTokenSource cancellationTokenSource)
{
Task.Run(() => Application.Run(new StopController(cancellationTokenSource)));
}
#region unmanaged
//must be static.
private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
{
// Put your own handler here
switch (ctrlType)
{
case CtrlTypes.CTRL_C_EVENT:
log.Warn("CTRL+C received!. Cancel was fired.");
cancellationTokenSource.Cancel();
break;
case CtrlTypes.CTRL_BREAK_EVENT:
log.Warn("CTRL+BREAK received!. Cancel was fired.");
cancellationTokenSource.Cancel();
break;
case CtrlTypes.CTRL_CLOSE_EVENT:
log.Warn("Program being closed!. Cancel was fired.");
cancellationTokenSource.Cancel();
break;
case CtrlTypes.CTRL_LOGOFF_EVENT:
case CtrlTypes.CTRL_SHUTDOWN_EVENT:
log.Warn("User is logging off!. Cancel was fired.");
cancellationTokenSource.Cancel();
break;
default:
log.Warn($"unknow type {ctrlType}");
break;
}
return true;
}
// Declare the SetConsoleCtrlHandler function
// as external and receiving a delegate.
[DllImport("Kernel32")]
public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add);
// A delegate type to be used as the handler routine
// for SetConsoleCtrlHandler.
public delegate bool HandlerRoutine(CtrlTypes CtrlType);
// An enumerated type for the control messages
// sent to the handler routine.
public enum CtrlTypes
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT,
CTRL_CLOSE_EVENT,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT
}
#endregion
}
用法:
StopController.Activate(cancellationTokenSource);
无需更改为windows申请。