Laden...

Anwendung ohne sichtbares Fenster soll beim ShutDown eine Aktion durchführen

Erstellt von mdo vor 10 Jahren Letzter Beitrag vor 10 Jahren 3.667 Views
M
mdo Themenstarter:in
14 Beiträge seit 2014
vor 10 Jahren
Anwendung ohne sichtbares Fenster soll beim ShutDown eine Aktion durchführen

Hallo!

Das Problem ist schnell erklärt, nur eine Lösung finde ich nicht...

Eine simple Applikation mit einem MainForm. Auf der Form gibt es einen Button um die Form zu verstecken. Mit .Hide() oder visible = false, oder wie auch immer.
Im Hintergrund arbeitet ein Thread irgendwelches Zeugs ab. Um genau zu sein, es ist ein Listener, der Anfragen von einem anderen Programm entgegen nimmt und jeweils entsprechend in einem extra Thread verarbeitet.

Die Applikation soll unsichtbar laufen, bis das System heruntergefahren wird. Passiert das, so soll sie nur schnell noch ihren "Müll" im Temp-Ordner aufräumen. Dieses Aufräumen habe ich im Form_Closing-Event angesiedelt. Und hier ist das Problem...

Denn wenn das Fenster der Applikation nicht sichtbar ist, wird das Form_Closing-Event offensichtlich nicht gefeuert. Der Prozess scheint einfach gekillt zu werden, wenn das System herunterfahren will. Auch eine MessageBox im Form_Closing hilft nicht. Habe auch schon Application.Exit-Event mit ner mbox versehen, bringt auch nichts...

Kurzum, ich habe eine Applikation, welche im Hintergrund arbeitet (also unsichtbar sein soll), aber dennoch auf den Shutdown von Windows reagieren soll.

Hat hier jemand eine Idee wie ich das machen kann ohne daraus einen Dienst zu bauen?

Danke!

Z
403 Beiträge seit 2007
vor 10 Jahren

Hallo mdo,

Application.ApplicationExit Event MSDN

Grüße

André

M
mdo Themenstarter:in
14 Beiträge seit 2014
vor 10 Jahren

Hi, TheGear!

Danke für die fixe Antwort!
Du meinst also, ich soll den AppContext vom Form hin zu nem eigenen wechseln? Hm, daran hatte ich noch nie gedacht. Werde das sofort mal versuchen!
Vorab also schonmal danke! 😉

M
mdo Themenstarter:in
14 Beiträge seit 2014
vor 10 Jahren

Also, ich hab die Form jetzt komplett ersetzt und meinen eigenen AppContext gebaut. Dort habe ich ein Application.Exit implementiert. Dort wird eine mbox aufgerufen.

Bringt nur leider nix. 😦

Windows-Shutdown->Prozess wird einfach gekickt... Keine mbox erscheint.

T
156 Beiträge seit 2012
vor 10 Jahren

Hallo mdo,

du solltest vielleicht einmal den betreffenden Code posten.

Viele Grüße,
telfa

M
mdo Themenstarter:in
14 Beiträge seit 2014
vor 10 Jahren

Joa, das sind ein paar 1000 Zeilen...
Aber es lässt sich auf das folgende reduzieren:

static class Program
    {
        /// <summary>
        /// Der Haupteinstiegspunkt für die Anwendung.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new CAppContext());
        }
    }
class CAppContext : ApplicationContext
    {
        public CAppContext()
        {
            Application.ApplicationExit += new EventHandler(Application_ApplicationExit);

            //Start listener async...
        }

        void Application_ApplicationExit(object sender, EventArgs e)
        {
            MessageBox.Show("Test");
        }
    }

Das ist jetzt die Variante mit dem eigenen AppContext.

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo telfa,

die ersten Treffer von Google-Suche nach shutdown-ereignis c# sollten verschiedene Möglichkeiten aufzeigen, z.B. SystemEvents.SessionEnding oder AppDomain.CurrentDomain.ProcessExit.

Ob du zu diesem Zeitpunkt noch eine MessageBox anzeigen kannst, ist fraglich, aber das Löschen von Dateien sollte möglich sein.

herbivore

M
mdo Themenstarter:in
14 Beiträge seit 2014
vor 10 Jahren

Hi!
Google habe ich auch schon bemüht, aber gerade dieses SystemEvents.SessionEnding kommt nicht in Frage, da das Programm nicht zwingend mit dem angemeldeten Benutzer ausgeführt wird.

Und AppDomain.CurrentDomain.ProcessExit ist auch nicht praktikabel. Das ist hier schön ausgeführt:
AppDomain.ProcessExit is not guaranteed to be called

Habe das eben trotzdem nochmal versucht:

class CAppContext : ApplicationContext
    {
        public CAppContext()
        {
            Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
            AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);
            //Start listener async...
        }

        void CurrentDomain_ProcessExit(object sender, EventArgs e)
        {
            MessageBox.Show("Test");
        }

        void Application_ApplicationExit(object sender, EventArgs e)
        {
            MessageBox.Show("Test");
        }
    }

Ohne Erfolg... 😦

edit:
Um die MessageBox noch aus dem Spiel zu nehmen, habe ich mal eine alternative Bestätigung ins Sample eingebaut:

class CAppContext : ApplicationContext
    {
        private string m_File = "C:\\Temp\\Test.test";
        public CAppContext()
        {
            StreamWriter sw = new StreamWriter(m_File);          
            sw.Close();

            Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
            AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);
            //Start listener async...
        }

        void CurrentDomain_ProcessExit(object sender, EventArgs e)
        {
            AlternateConfirmation();
            MessageBox.Show("Test");
        }

        void Application_ApplicationExit(object sender, EventArgs e)
        {
            AlternateConfirmation();
            MessageBox.Show("Test");
        }

        private void AlternateConfirmation()
        {
            File.Delete(m_File);
        }
    }
49.485 Beiträge seit 2005
vor 10 Jahren

Hallo mdo,

ich sage mal so: Was du über die o.g. oder eine ähnliche Google-Suche findest, ist das, was im Netz bekannt ist. Unwahrscheinlich, dass hier jemand etwas weiß, was dort nicht zu finden ist.

Wenn du eine Lösung findest, poste sie bitte hier, für andere, die später auf den Thread stoßen.

herbivore

M
mdo Themenstarter:in
14 Beiträge seit 2014
vor 10 Jahren

Hmpf... Sag doch sowas nicht. 😦
Die "Lösung" die mir bekannt ist, ist das ganze in einen Dienst zu packen. Aber das versuche ich ja zu umgehen. 😦

Z
403 Beiträge seit 2007
vor 10 Jahren

Hallo mdo,

es durchaus möglich das MessageBox'en an der Stelle nicht mehr erstellt werden können.
Versuch es mal mit Logging, um zu prüfen ob die Events augeführt werden.

Grundsätzlich hat deine Anwendung nur eine bestimmte Zeit den Shutdown zu verzögern.
Alles danach wird gekillt, falls nicht verhindert und falls es doch verhindert wird, erscheint der tolle Dialog das die Anwendung ein Herunterfahren/Neustarten verhindert.

Edit: Hier hab ich noch was gefunden: dotnet-snippet Meldung beim Abmelden

André

M
mdo Themenstarter:in
14 Beiträge seit 2014
vor 10 Jahren

Hallo TheGear!

Die MessageBox habe ich ja mit der alternativen Löschung einer Temp-Datei bereits aus dem Spiel genommen (siehe mein letztes Code-Snippet). Leider wird die Datei nicht gelöscht. 😦

Dein letzter Link hat leider auch ein grundsätzliches Problem:

Das Handle muss von einem gültigem Fenster stammen, sonst geht es nicht.

Da ich kein gültiges Handle habe...

Das Problem ist, soweit habe ich das nachvollzogen, dass Windows die Applikation nicht über die Nachrichtenschleife über das Beenden informiert (zB mit Process.CloseMainWindow), sondern ein hartes "Kill" ausführt.

Das lässt sich auch gut im Process-Explorer nachvollziehen. Sobald es kein sichtbares (also gültiges) Fenster in der Anwendung gibt, kann ich nichtmehr per Window->Close das Hauptfenster und damit den Process "gracefully" beenden, sondern mir bleibt nur noch die Möglichkeit eines harten Kills. 😦

Z
403 Beiträge seit 2007
vor 10 Jahren

Hallo mdo,

die einzige, aber dafür unsaubere Lösung, die mir noch einfällt, wäre ein unsichtbares Form und damit meine ich nicht Visible = false, sondern beispielsweise ein (rahmenloses) Fenster mit der Größe von 0 * 0.

Das ist allerdings eine theoretische Überlegung und ich weiß nicht ob das funktioniert 🙂

Ansonsten musst du überlegen, das anders zu lösen, z.B. bei start der Anwendung prüfen was liegen geblieben ist und dann säubern.

André

M
mdo Themenstarter:in
14 Beiträge seit 2014
vor 10 Jahren

Hallo TheGear!

Hehe, ja. Über ein fensterloses Pixel-Form habe ich auch schon nachgedacht, aber kleiner wie 1x1 geht glaube ich nicht. xD

Das ist mir dann doch ein bissl zu "dreckig". 😛

Dein zweiter Vorschlag ist genau das, was ich jetzt umgesetzt habe. Es ist zwar nicht so schön, dass eine Applikation beim Start aufräumt, aber derzeit einfach die Lösung mit dem kleinsten Aufwand.

Mittelfristig muss das aber geändert werden. Ich würde ja gerne noch andere Dinge am "Ende" erledigen, als aufzuräumen. Zum Beispiel eine Statusmeldung an einen Server, etc...

Wahrscheinlich bleibt mir nur ein Dienst übrig... Dann wird es aber langsam kompliziert, denn das Teil soll auch auf Servern mit mehreren parallelen User-Sessions rennen...

Hmpf...