C# C# Konsolenanwendung -> Cancel Close Event

Ghost_Rider_R

Lieutenant
Registriert
Nov. 2009
Beiträge
752
Hallo zusammen,

ich suche nach einem Codesnippet für deine C# 2.0 Anwendung, welche das Close Event beim Drücken vom X oben rechts abfängt. In einer Windows Forms Anwendung gibt es ja e.Cancel, bei einer Consolenanwendung scheint es anders zu funktionieren.

Es gibt viele Snippets im Internet, jedoch greifen Sie das Event nur auf aber brechen dieses nicht ab.

Kann mit da jemand vielleicht behilflich sein?

Vielen Dank Viele Grüße Ruff
 
Probier mal einen EventHandler für "AppDomain.CurrentDomain.ProcessExit"
 
der wird leider nicht ausgeführt. Es gibt ja Events welche dann aufgerufen werden, jedoch weiß ich nicht wie ich die Events anschließend abbrechen kann, da es kein e.Cancel gibt
 
@Umbel Ja da hast du natürlich recht, da möchte ich ja eigentlich auch machen. Ich möchte durch abbrechen darauf reagieren :-) und das schließen damit verhindern.

An dem Punkt war ich schon und genau hier komm ich nicht weiter. Wenn das X gedrückt wird dann springt er in die ConsoleCtrlCheck Methode in welcher das Kommentar // TODO: implement exit handler routine steht. Aber wie brech ich das Event dann genau ab?
 
Deine Konsolenanwendung ist ein Childprozess der NT-Konsole. Wenn das Konsolenfenster geschlossen wird, wird der zur Konsole gehörende Prozess beendet und dessen Kinder mit. Da kannst du nichts machen, außer einen Zombie zu erzeugen. Der wird dann aber kurze Zeit später auch zwangsbeendet.

€: Du könntest genausogut folgendes fragen:

Wenn das Win32 Subsystem herunterfährt, wird mein Win32-Prozess beendet. Wie fange ich das ab, damit mein Programm weiter läuft, obwohl der Computer aus ist?

Wenn das Konsolenfenster geschlossen wird, wird die entsprechende Instanz des Subsystems beendet. Das kannst du nicht "abfangen".
 
Zuletzt bearbeitet:
...ok verstehe. Dann könnte ich da ja noch lange suchen. Vielen Dank für die Information.
 
Mhm also im .NET Framework 3.5 gibt es eine Möglichkeit den Knopf auszugrauen
Ich werde morgen bei der Arbeit mal schauen wie ich das realisiert habe.
 
hier ein Beispiel:

Imports System.Console

Module Main

Private Declare Function DeleteMenu Lib "user32" (ByVal pMenu As Integer, ByVal pPosition As Integer, ByVal pFlags As Integer) As Boolean
Private Declare Function GetForegroundWindow Lib "user32" () As Integer
Private Declare Function GetSystemMenu Lib "user32" (ByVal pHwnd As Integer, ByVal pRevert As Boolean) As Integer
Private Declare Function GetWindow Lib "user32" (ByVal pHwnd As Integer, ByVal pCmd As Integer) As Integer
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal pHwnd As Integer, ByVal pSpace As String, ByVal pCount As Integer) As Integer

Sub Main()
AddHandler Console.CancelKeyPress, AddressOf QuitHandler
DeleteMenu(GetSystemMenu(ObtainWindowHandle(Title), False), 6, 1024)
ReadLine()
End Sub

Private Sub QuitHandler(ByVal sender As Object, ByVal e As ConsoleCancelEventArgs)
e.Cancel = True
End Sub

Private Function ObtainWindowHandle(ByVal lpstrCaption As String) As Integer
Dim intLength As Integer
Dim strSpace As String

Dim intHwnd As Integer = GetForegroundWindow
While intHwnd <> 0
strSpace = Space(255)
intLength = GetWindowText(intHwnd, strSpace, 255)

If Len(Trim(strSpace)) <> 0 And Asc(Trim(strSpace)) <> 0 Then
If CType(InStr(Left(strSpace, intLength), lpstrCaption), Boolean) Then
Return intHwnd
End If
End If
intHwnd = GetWindow(intHwnd, 2)
End While

Return 0
End Function

End Module
 
asdfman schrieb:
Deine Konsolenanwendung ist ein Childprozess der NT-Konsole. Wenn das Konsolenfenster geschlossen wird, wird der zur Konsole gehörende Prozess beendet und dessen Kinder mit. Da kannst du nichts machen, außer einen Zombie zu erzeugen. Der wird dann aber kurze Zeit später auch zwangsbeendet.

€: Du könntest genausogut folgendes fragen:

Wenn das Win32 Subsystem herunterfährt, wird mein Win32-Prozess beendet. Wie fange ich das ab, damit mein Programm weiter läuft, obwohl der Computer aus ist?

Wenn das Konsolenfenster geschlossen wird, wird die entsprechende Instanz des Subsystems beendet. Das kannst du nicht "abfangen".

Ist das wirklich so? Ich war der Meinung, daß ein Prozess durch igendwelche Systemaufrufe sich quasi von der zugehörigen Konsole "detachen" kann und dann ohne die Konsole weiterlaufen kann.

EDIT: Ich meine, ein bereits laufender Prozess kann sich durch geeignete Systemaufrufe praktisch zu einer Art daemon-Prozess machen. Aber die Details sind mir ohne Nachlesen nicht geläufig.
 
Zuletzt bearbeitet:
..also wenns dazu eine Alternativlösung gibt dann würde ich die gerne Erfahren. Ich möchte einfach verhindern, dass die Anwendung beendet werden kann durch den Benutzer. Alternativ müsste ich halt den Weg über eine GUI gehen, welche dann halt wie eine Console aussieht, was ich aber eher als Bastellösung ansehen würde...
 
Ruff_Ryders_R schrieb:
..also wenns dazu eine Alternativlösung gibt dann würde ich die gerne Erfahren. Ich möchte einfach verhindern, dass die Anwendung beendet werden kann durch den Benutzer.

Na, das kannst du auf keinen Fall verhindern. Der Benutzer kann immer noch den TaskManager öffnen und deinen Prozess einfach wegballern.
 
...wenn das die einzige Möglichkeit ist, dann würde mir das so vollkommen ausreichen :-)
 
Hab mal etwas für dich Zusammengetragen und vereinfacht:

NativeMethods.cs (Namespace kannst du natürlich anpassen):
PHP:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    class NativeMethods
    {
        [DllImport("Kernel32")]
        public static extern bool SetConsoleCtrlHandler(HandlerRoutine handler, bool add);

        public delegate bool HandlerRoutine(CtrlTypes ctrlType);

        public enum CtrlTypes
        {
            CTRL_C_EVENT = 0,
            CTRL_BREAK_EVENT,
            CLOSE_EVENT,
            LOGOFF_EVENT = 5,
            SHUTDOWN_EVENT
        }


        [DllImport("user32.dll")]
        static extern bool EnableMenuItem(IntPtr hMenu, uint uIdEnableItem, uint uEnable);
        [DllImport("user32.dll")]
        static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

        internal const UInt32 SC_CLOSE = 0xF060;
        internal const UInt32 MF_ENABLED = 0x00000000;
        internal const UInt32 MF_GRAYED = 0x00000001;
        internal const UInt32 MF_DISABLED = 0x00000002;
        internal const uint MF_BYCOMMAND = 0x00000000;

        public static void EnableCloseButton(bool bEnabled)
        {
            IntPtr hSystemMenu = GetSystemMenu(Process.GetCurrentProcess().MainWindowHandle, false);
            EnableMenuItem(hSystemMenu, SC_CLOSE, MF_ENABLED | (bEnabled ? MF_ENABLED : MF_GRAYED));
        }
    }
}

Und das ganze anwenden:
PHP:
using System;

namespace ConsoleApplication1
{
    class Program
    {
        static NativeMethods.HandlerRoutine _consoleHandler;

        static void Main(string[] args)
        {
            //register event
            _consoleHandler = ConsoleCtrlCheck;
            NativeMethods.SetConsoleCtrlHandler(_consoleHandler, true);

            //disable close button
            NativeMethods.EnableCloseButton(false);

            while (true)
            {
                Console.ReadKey(true);
            }
        }

        private static bool ConsoleCtrlCheck(NativeMethods.CtrlTypes ctrlType)
        {
            switch (ctrlType)
            {
                case NativeMethods.CtrlTypes.CTRL_C_EVENT:
                    Console.WriteLine("CTRL+C received, shutting down");
                    break;

                case NativeMethods.CtrlTypes.CTRL_BREAK_EVENT:
                    Console.WriteLine("CTRL+BREAK received, shutting down");
                    break;

                case NativeMethods.CtrlTypes.CLOSE_EVENT:
                    Console.WriteLine("Program being closed, shutting down");
                    break;

                case NativeMethods.CtrlTypes.LOGOFF_EVENT:
                case NativeMethods.CtrlTypes.SHUTDOWN_EVENT:
                    Console.WriteLine("User is logging off!, shutting down");
                    break;
            }

            return true; //or false to allow closing
        }
    }
}

Zumindest die Anwendung sollte selbst erklärend sein, du kannst dann ja im switch je nachdem, wodurch geschlossen werden soll das beenden auch erlauben (z.B. bei Shutdown/LogOff solltest du das tun, da du das sonst blockierst..).
 
...also ich hab das ganze mal nochmal eben reingehackt. Das Problem an der Sache ist, dass man zwar
in die Methode reinspringt wenn die Anwendung geschlossen ist, aber man kann (oder ich weiß zumindest nicht wie)
das Schließen nicht abbrechen.

return true; //or false to allow closing

Egal ob true oder false gesetzt wird, die Anwendung wird trotzdem geschlossen. Oder mach ich etwas falsch?
 
Zurück
Oben