22 Stimmen

Erkennen, wenn die Konsolenanwendung geschlossen/abgeschaltet wird?

Ich wollte einen sicheren Ausgang für meine Konsolenanwendung machen, die unter Linux mit Mono laufen wird, aber ich kann keine Lösung finden, um zu erkennen, ob ein Signal an sie gesendet wurde oder der Benutzer ctrl+c gedrückt hat.

Unter Windows gibt es die Kernel-Funktion SetConsoleCtrlHandler, die diese Aufgabe übernimmt, aber unter Mono funktioniert das nicht.

Wie erhalte ich ein Schließen-Ereignis auf meiner Konsole Anwendung, um es sicher beenden?

13voto

skolima Punkte 30692

Sie müssen Folgendes verwenden Mono.UnixSignal gibt es ein gutes Beispiel, das von Jonathan Pryor veröffentlicht wurde: http://www.jprl.com/Blog/archive/development/mono/2008/Feb-08.html

Es gibt auch ein kürzeres Beispiel auf der Mono-Seite: FAQ / Technik / Fragen zum Betriebssystem / Signalverarbeitung :

// 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); });
    }});

13voto

James Punkte 725

Als Beispiel für die Bereitstellung einer Unix- und Windows-Implementierung siehe unten. Beachten Sie, dass Sie die Mono.Posix dll auch einbinden können, wenn Sie Visual Studio verwenden.

Ich habe auch das SIGTERM-Signal hinzugefügt, da dieses von systemd in Unix beim Stoppen/Neustart Ihrer Anwendung als Dienst ausgelöst wird.

Schnittstelle, um ein Exit-Ereignis darzustellen

public interface IExitSignal
{
    event EventHandler Exit;
}

Unix-Implementierung

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);
            }

        });
    }

}

Windows-Implementierung

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;
    }

}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X