Frage zu IMessageFilter

Nil18

Erfahrenes Mitglied
Hallo Leute!

Habe hier ein Problem mit dem IMessageFilter. Und zwar, tritt das Event einfach nicht ein, obwohl der Code eigentlich stimmen sollte.

Ich poste einfach mal den Code und hoffe Ihr könnt mir sagen was ich falsch mache.

Vielen Dank im Voraus!

C#:
 public class MyOwnMFilter : IMessageFilter
    {
        const int WM_QUERYENDSESSION = 0x11;

        /// <summary>
        /// Event, daß nun die App abedreht werden soll, weil Abmeldung stattfindet (für Timer)
        /// </summary>
        public static event System.ComponentModel.CancelEventHandler ApplicationShouldExit = null;

        #region IMessageFilter Member
        public bool PreFilterMessage(ref Message m)
        {
            //Wenn abmelden, neustarten, herunterfahren
            if (m.Msg == WM_QUERYENDSESSION)
            {    
                System.ComponentModel.CancelEventArgs args = new System.ComponentModel.CancelEventArgs();
                args.Cancel = false;

                if (ApplicationShouldExit != null)
                    ApplicationShouldExit(this,args);

                //Neustart, Herunterfahren, Abmelden abbrechen
                if (args.Cancel)
                {
                    return true;
                }
                else
                {
                    //Sicherheitshalber
                    Application.Exit();
                }
            }
            return false;
        }
        #endregion
    }

In der Main Methode steht dann:
C#:
 MyOwnMFilter myfilter = new MyOwnMFilter();
MyOwnMFilter.ApplicationShouldExit += new System.ComponentModel.CancelEventHandler(MyOwnMFilter_ApplicationShouldExit);
Application.AddMessageFilter(myfilter);
Application.ApplicationExit += new EventHandler(Application_ApplicationExit);

Und dann noch die Methode:
C#:
        //Wird bei jedem SignOffEvent durchgeführt ...
        static void MyOwnMFilter_ApplicationShouldExit(object sender, System.ComponentModel.CancelEventArgs e)
        {
            DoCleanup();
        }

C#:
        static void Application_ApplicationExit(object sender, EventArgs e)
        {
            DoCleanup();
        }

Es funktioniert einfach nicht :(
In DoCleanup(); befindet sich NUR eine MessageBox sowie ein Stop(); für einen Timer...

BITTE um Hilfe!
 
Zuletzt bearbeitet:
Hi Nil!

Also ich bin noch nicht darauf gekommen, einen Messagefilter dafür zu verwenden. ;-) Das muss ich auch mal ausprobieren, sobald ich zu hause bin.

Ich sehe auf Anhieb keinen Fehler in deinem Code. Auch das Beispiel auf TheCodeProject schaut nicht anders aus.
Using IMessageFilter to create a generic filter for operating system events

Ich mach es immer eigentlich immer in dem MainForm meiner Anwendungen. Da funktioniert das immer. Ich weiß ehrlich gesagt nicht, warum ausgerechnet der MessageFilter dieses Event nicht bekommen sollte. Versuchs daher mal im MainForm deiner Anwendung.
[thread=213150]Das runterfahren des PC's abfangen - Thread[/thread]

Wenn Du Timer & Threads laufen hast, dann schließe sie nicht nur explizit durch das abgreifen gewisser Events. Sondern implementiere zusätzlich das IDisposable Interface für die Objekte, die diese Dinge verwalten. So gehst Du immer auf Nummer sicher, dass diese Dinge beim Beenden der Anwendung geschlossen werden, auch wenn mal das entsprechende Event aus irgend welchen Gründen nicht geworfen wurde.
Implementing IDisposable and the Dispose Pattern Properly
 
Mahlzeit cosmo!

Danke erstmal für die Antwort!
Und du hattest wiedermal recht, genau darin lag nämlich der Fehler.
Ich hatte eine Windows Forms Anwendung, aber keine Form ;)
Denk nicht ich bin doof, ich hab die Form absichtlich gelöscht, weil ich wollte dass das Programm unsichtbar im Hintergrund läuft, aber kein Windows Dienst ist.

Nunja, jedenfalls hab ich eine Form hinzugefügt und die Msg ausgeben lassen.
Und siehe da, eine Form bekommt ganz andere Messages, als eine ... Windows Form Anwendung ohne Windows Form :p

Na jedenfalls, ich hab die Form hinzugefügt und einfach ShowInTaskbar auf false gestzt, Opacity auf 0% etc ... nun ist das Programm genauso unsichtbar und es funktioniert auch die IMessageFilter Methode.

Ein "Problem" gibts allerdings noch...
In der Methode die beim LogOff-Event aufgerufen wird (DoCleanup), schalte ich den Timer ab.
Wenn der Benutzer nun aber auf Abmelden geht und dann auf "abbrechen" (weil irgend ein Programm das Abmelden gerade verhindert), wird das abmelden abgebrochen, aber mein Timer stoppt trotzdem.
Das ist ein kleines Problem für das ich keine Lösung finde, aber so dramatisch nun auch wieder nicht :)

Danke nochmal!
 
Zuletzt bearbeitet:
Ein "Problem" gibts allerdings noch...
In der Methode die beim LogOff-Event aufgerufen wird (DoCleanup), schalte ich den Timer ab.
Wenn der Benutzer nun aber auf Abmelden geht und dann auf "abbrechen" (weil irgend ein Programm das Abmelden gerade verhindert), wird das abmelden abgebrochen, aber mein Timer stoppt trotzdem.
Das ist ein kleines Problem für das ich keine Lösung finde, aber so dramatisch nun auch wieder nicht :)

Danke nochmal!
Welche Methode meinst Du? MyOwnMFilter_ApplicationShouldExit? Die wird doch eh aufgerufen sobald sich jemand abmelden will.

Jetzt stellt sich mir die Frage, warum Du das Abmelden überhaupt feststellen willst, obwohl Du laut deines Codes lediglich den Timer in der Ereignisbehandlung von ApplicationShouldExit schließt. Das kannst demzufolge auch in dem Event Application.Exit machen. Das wird nämlich gefeuert, wenn sich die Anwendung beendet. Also nachdem das WM_QUERYENDSESSION Event ausgelöst wurde.

Deinen MessageFilter für dieses Event kannst zB verwenden:
  • Um den aktuellen Nutzer zu fragen, ob er was speichern oder gar den Abmeldevorgang abbrechen will.
  • Deine Anwendung eine Tray-Anwendung ist, die sich bei einem Klick auf das X minimiert und das nicht tun soll, wenn die aktuelle Session beendet wird. Also der Abmeldevorgang sonst abgebrochen werden würde, wenn das System versucht die Anwendung zu beenden.
  • Oder aber deine Anwendung das Abmelden generell verhindern will.

Wenn Du lediglich wichtige Resourcen beim Beenden schließen willst, reicht es also aus, dass in dem Application.Exit Event oder in der jeweiligen IDisposable Implementation auszuführen.
 
Zuletzt bearbeitet:
Ne cosmo, ich wollt nur einfach mal was neues ausprobieren ;)
Sicher häts ein einfaches Exit Event auch getan, aber das hab ich dann wieder ausgebaut :p

Das einzige Prob wie gesagt is nun, dass wenn der Benutzer auf Abmelden geht, in meinem Programm der Timer gestoppt wird. Falls ein anderes Programm das Abmelden aber verhindert ist der Timer in meinem Prog aus, obwohl es schlussendlich weiter läuft.
Und das is doof ... aber nicht so dringend.

Wie gesagt, das Interface wollt ich einfach mal ausprobieren, und es funktioniert jetzt auch prima :)
 
Wenn Du's jetzt ausgebaut hast und den Timer in Application.Exit schließt, sollte der Timer doch eigentlich nur geschlossen werden, wenn die Anwendung beendet wird. Und nicht wenn das Beenden der aktuellen Windows Session abgebrochen wird. Entweder Application.Exit wird gefeuert und danach das Prog beendet oder nicht. Ich verstehe dein Problem gerade nicht. Verstehe ich von deinem Problem evtl. was falsch? :confused:

Also in dem Fall kommt ja IMO nur noch ein einzige Möglichkeit in Frage. -> IDisposable. Dann musst Du dich mit den Events gar nicht mehr herum schlagen. ;)
 
Ich verwende ja nicht Application.Exit sondern immer noch meine MyOwnMFilter_ApplicationShouldExit Methode.
Und da schaltet sich der Timer (meines Wissens nach) auch ab.
Keine Ahnung warum, aber scheinbar wird das immer gefeuert sobald man vor hat sich abzumelden.

Du immer mit deinem IDisposable :p
Meinst du quasi es reicht, den Timer NICHT zu stoppen sondern ihm einfach ein IDisposable zu verpassen?
 
Habe Dir doch schon gesagt, dass Du nicht dein ApplicationShouldExit Event verwenden sollst, sondern Application.Exit. ApplicationShouldExit wird ja immer ausgelöst, sobald der User die Session beenden will. Application.Exit hingegen nur, wenn das Programm unwiderruflich beendet wird.

IDisposable solltest generell immer für solche Dinge implementieren, damit diese Dinge auch 100% beendet werden. Und wenn Du den Dispose Pattern ordnungsgemäß implemetiert hast, rufst die Dispose Implementation sowieso explizit im Destruktor der Klasse auf. Der Destuktor wird nämlich aufgerufen, wenn das Objekt zerstört wird, also beim Beenden des Programms. ;)
 
Hoi!

Dachte mir ich probier das jetzt mal aus und siehe da ...
Wenn die Applikation durch ein Abmeldeverfahren beendet wird, wird das Application.ApplicationExit Event nicht gefeuert!

Tja, dann bleib ich wohl beim ApplicationShouldExit und bin zufrieden das es funktioniert ;)
 
Aber trotzdem nicht so, wie es eigentlich sollte. Mit IDisposable erreichst das was eigentlich mit Application.Exit erreicht werden sollte. Dann hast läufst auch keine Gefahr, dass dein Timer irrtümlich beendet wird. ;)
 

Neue Beiträge

Zurück