c# - ¿Detectar cuando la aplicación de la consola se está cerrando?
mono console (2)
Como ejemplo de cómo proporcionar una implementación de Unix y Windows, vea a continuación. Tenga en cuenta que aún puede incluir la dll Mono.Posix cuando usa Visual Studio.
También he agregado la señal SIGTERM porque esta se activa por systemd en unix al detener / reiniciar su aplicación como un servicio.
Interfaz para exponer un evento de salida.
public interface IExitSignal
{
event EventHandler Exit;
}
Implementacion Unix
public class UnixExitSignal : IExitSignal
{
public event EventHandler Exit;
UnixSignal[] signals = new UnixSignal[]{
new UnixSignal(Mono.Unix.Native.Signum.SIGTERM),
new UnixSignal(Mono.Unix.Native.Signum.SIGINT),
new UnixSignal(Mono.Unix.Native.Signum.SIGUSR1)
};
public UnixExitSignal()
{
Task.Factory.StartNew(() =>
{
// blocking call to wait for any kill signal
int index = UnixSignal.WaitAny(signals, -1);
if (Exit != null)
{
Exit(null, EventArgs.Empty);
}
});
}
}
Implementación de Windows
public class WinExitSignal : IExitSignal
{
public event EventHandler Exit;
[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
}
/// <summary>
/// Need this as a member variable to avoid it being garbage collected.
/// </summary>
private HandlerRoutine m_hr;
public WinExitSignal()
{
m_hr = new HandlerRoutine(ConsoleCtrlCheck);
SetConsoleCtrlHandler(m_hr, true);
}
/// <summary>
/// Handle the ctrl types
/// </summary>
/// <param name="ctrlType"></param>
/// <returns></returns>
private bool ConsoleCtrlCheck(CtrlTypes ctrlType)
{
switch (ctrlType)
{
case CtrlTypes.CTRL_C_EVENT:
case CtrlTypes.CTRL_BREAK_EVENT:
case CtrlTypes.CTRL_CLOSE_EVENT:
case CtrlTypes.CTRL_LOGOFF_EVENT:
case CtrlTypes.CTRL_SHUTDOWN_EVENT:
if (Exit != null)
{
Exit(this, EventArgs.Empty);
}
break;
default:
break;
}
return true;
}
}
Quería hacer una salida segura para mi aplicación de consola que se ejecutará en Linux usando mono, pero no puedo encontrar una solución para detectar si se le envió una señal o si el usuario presionó ctrl + c.
En Windows, está la función del kernel SetConsoleCtrlHandler que hace el trabajo pero que no funciona en mono.
¿Cómo obtengo un evento de cierre en la aplicación de mi consola para salir de él con seguridad?
Mono.UnixSignal
usar Mono.UnixSignal
, hay una buena muestra publicada por Jonathan Pryor: http://www.jprl.com/Blog/archive/development/mono/2008/Feb-08.html
También hay un ejemplo más corto en la página Mono: Preguntas frecuentes / Preguntas técnicas / sobre el sistema operativo / Manejo de señales :
// Catch SIGINT and SIGUSR1
UnixSignal[] signals = new UnixSignal [] {
new UnixSignal (Mono.Unix.Native.Signum.SIGINT),
new UnixSignal (Mono.Unix.Native.Signum.SIGUSR1),
};
Thread signal_thread = new Thread (delegate () {
while (true) {
// Wait for a signal to be delivered
int index = UnixSignal.WaitAny (signals, -1);
Mono.Unix.Native.Signum signal = signals [index].Signum;
// Notify the main thread that a signal was received,
// you can use things like:
// Application.Invoke () for Gtk#
// Control.Invoke on Windows.Forms
// Write to a pipe created with UnixPipes for server apps.
// Use an AutoResetEvent
// For example, this works with Gtk#
Application.Invoke (delegate () { ReceivedSignal (signal); });
}});