Shutdown WM_QUERYENDSESSION
-
Hallo Zusammen,
das Thema wurde ja schon mehrfach behandelt, jedoch ist mir einiges noch nicht ganz klar. Mein Programm soll vor dem Herunterfahren noch bestimmten Code abarbeiten. Diesen habe ich im OnClose()-Ereignis der Form1 integriert.
Mit dem Code von http://www.c-plusplus.net/forum/viewtopic-var-t-is-39152.html reagiere ich auf WM_QUERYENDSESSION:
in unit1.h
protected: BEGIN_MESSAGE_MAP VCL_MESSAGE_HANDLER(WM_QUERYENDSESSION, TMessage, OnShutdown) END_MESSAGE_MAP(TForm) void __fastcall OnShutdown(TMessage & Msg);
in unit1.cpp
void __fastcall TForm1::OnShutdown(TMessage &Msg) { TObject:: Dispatch(&Msg); Form1->Close(); }
Hier wird Form1 geschlossen und somit auch mein Code abgearbeitet. Das funktioniert auch soweit aber hier meine Fragen.
1. Muss der Code in der .h unbedingt unter protected aufgeführt sein oder wäre auch public oder private ok?2. Was bedeutet "TObject:: Dispatch(&Msg)" eigentlich genau? Sollte ich lieber "Form1->Close()" vor diesem Aufruf einfügen?
3. Muss meine Anwendung noch in irgendwelcher Weise unbedingt auf das WM_QUERYENDSESSION antworten? Wenn ja mit welchem Code?
4. Sollte ich anstelle WM_QUERYENDSESSION lieber WM_ENDSESSION verwenden? Wenn ja, warum?
Danke im Voraus!
-
Hallo,
um das zu testen, habe ich mal zwei Apps aufgesetzt. Eine mit deinem Code und eine, die diese erste App beendet.
Aber erst zu deinen Fragen:
1. Es reicht, wenn die MessageMap als private deklariert wird.WinAPI-Help schrieb:
The DispatchMessage function dispatches a message to a window procedure. It is typically used to dispatch a message retrieved by the GetMessage function.
Allerdings sollte es heissen:
TForm:: Dispatch(&Msg); // warum TObject ?
3. Die zu beendende Application muss ein true zurücksenden. Daher sicher auch DispatchMessage
WinAPI-Help schrieb:
WM_QUERYENDSESSION : Return Values
If an application can terminate conveniently, it should return TRUE; otherwise, it should return FALSE.4. Nein. Das macht die App:
WinAPI-Help schrieb:
Windows NT: When an application returns TRUE for this message, it receives the WM_ENDSESSION message and it is terminated, regardless of how the other applications respond to the WM_QUERYENDSESSION message.
Hier der Code für die 2. App als Buttonklick:
void __fastcall TForm1::Button1Click(TObject *Sender) { HWND hWnd = FindWindow("TFormExitTest", "FormExitTest"); if ( NULL != hWnd) { int ret = SendMessage( hWnd, WM_QUERYENDSESSION, (WPARAM) 0, (LPARAM) ENDSESSION_LOGOFF); // im Erfolgsfall ist ret = true (1) } } //---------------------------------------------------------------------------
mfg
kpeteredit: noch zu 2:
Sollte ich lieber "Form1->Close()" vor diesem Aufruf einfügen?
Halte ich nicht für richtig.
Im Falle eines Endes der Windows session sollen ja alle Apps ihr WM_ENDSESSION senden.
Das geht dann sicher nicht mehr, wenn du dein Programm vorher terminierst (Form->Close()).
-
Zu Punkt 4:
Mit WM_QUERYENDSESSION fragt Windows erstmal nacheinander alle Applikationen ab, ob Windows herunterfahren (oder sich der User ausloggen) darf.
(Bis Windows XP (und Server 2003) konnte so jeder App je nach Antwort den Shutdown blockieren. Ab Windows Vista geht das so nicht mehr, dafür gibt es andere Methoden.)Erst mit WM_ENDSESSION (und WPARAM=TRUE) wird der Shutdown (oder User-Logoff) tatsächlich eingeleitet!
Danach bleiben der Applikation noch 5 Sekunden um irgendwas in die Wege zu leiten (z.B. letzte Einstellungen sichern), um dann die Nachricht mit Wert 0 zu quittieren.Es ist gar nicht nötig zusätzlich die Fenster zu schließen usw. Diese werden sowieso aus dem Speicher gekillt.
Zu Punkt 3:
Für gewöhnlich soll auf WM_QUERYENDSESSION mit TRUE geantwortet werden (bzw. die Funktion DefWindowProc() macht das so automatisch).
Für gewöhnlich soll auf WM_ENDSESSION mit 0 geantwortet werden.HTH,
Martin
-
Hallo,
ok, mein Code sieht jetzt wie folgt aus:
private: BEGIN_MESSAGE_MAP VCL_MESSAGE_HANDLER(WM_QUERYENDSESSION, TMessage, OnShutdown) END_MESSAGE_MAP(TForm) void __fastcall OnShutdown(TMessage & Msg);
void __fastcall TForm1::OnShutdown(TMessage &Msg) { TForm:: Dispatch(&Msg); Form1->Close(); }
Aber so richtig habe ich noch nicht verstanden, wie ich genau auf das Ereignis WM_QUERYENDSESSION den Wert True zurücksenden kann. kpeter, du hattest geschrieben ...Daher sicher auch DispatchMessage. Reicht das schon aus?
Martin hatte geschrieben Für gewöhnlich soll auf WM_QUERYENDSESSION mit TRUE geantwortet werden (bzw. die Funktion DefWindowProc() macht das so automatisch).
Wie und wo verwende ich diese Funktion? Was ist besser?
Das mit der 2. App hat bei mir irgendwie nicht funktioniert.
Sorry, wenn ich das noch nicht ganz verstanden habe.Gruß
-
gert_mue schrieb:
...Wie und wo verwende ich diese Funktion?
WM_QUERYENDSESSION steht in deiner MessageMap als zu bearbeitende Nachricht.
Die Abarbeitung durch dein Prog passiert in OnShutdown. Machen musst du also nix weiter.Die Verwendung von DefWindowProc ist in VCL-Anwendungen meines Wissen unüblich. Also TForm:: Dispatch(&Msg); ist schon o.k.
mfg
kpeter
-
Ok, vielen Dank für die Antworten.
Da weis ich jetzt das ich den Code richtig anwende.Gruß