Mit FireMonkey auf Windows-Messages reagieren

Vor einer Weile stand ich vor folgendem Problem. Ich möchte wenn Windows heruntergefahren wird eine bestimmte Aktion in meiner Anwendung ausführen (falls diese gerade noch läuft). Seitens Windows gibt eine Windows-Message (WM_QUERYENDSESSION). Standardmäßig kann Firemonkey ja nicht auf solche Messages reagieren. Nach ein wenig suchen, habe ich allerdings eine Möglichkeit gefunden. Diese möchte ich euch in diesem Artikel zeigen.

Eigentlich ist es ganz einfach und es sind nur ein paar Zeilen Code notwendig. Dies funktioniert außerdem nicht nur mit Firemonkey, sondern man kann diese Funktionalität auch einfach in einer VCL-Anwendung in eine Unit einbinden, welche keinen eigenen Handle zum empfangen von Messages hat.
Handel hier wären wir auch schon beim Problem der ganzen Sache. Da Firemonkey keinen wirklichen Handles hat, können standardmäßig keine Windows-Messages empfangen werden. Deshalb müssen wir uns um einen solchen Handle kümmern. Ich habe einfach mal eine neue Firemonkey-Anwendung angelegt. Im Hauptdialog definiere ich mir einen Handle und eine Funktion, die die Windows-Message verarbeiten soll:

	// Daten
	HWND m_hMessageHandle;

	// Funktionen
	void __fastcall WndMethod(Winapi::Messages::TMessage &Msg);

Im Konstruktor „erzeugen“ wir uns dann einen entsprechenden Handle und geben an welche Funktion ausgeführt werden soll falls eine Message emfpangen wird:

this->m_hMessageHandle = AllocateHWnd(this->WndMethod);

Im Destruktor muss der Handle natürlich wieder freigegeben werden:

	DeallocateHWnd(this->m_hMessageHandle);

Nun fehlt nur noch die Implementierung der „Verarbeitungs“-Funktion:

void __fastcall TFormMain::WndMethod(Winapi::Messages::TMessage &Msg)
{
	if (Msg.Msg == MY_MESSAGE)
		ShowMessage("Message empfangen!");
}
//---------------------------------------------------------------------------

Um zu testen ob alles auch so funktioniert wie erwartet, habe ich einfach einen Button auf die Form gelegt. Dieser Button sendet eine (eigene definierte) Message an den Handle meines Fensters. Wie eingangs erwähnt, fängt diese Funktion aber z. B. auch Messages wie WM_QUERYENDSESSION ab, damit beim beenden von Windows noch eine Aktion durchgeführt werden kann:

// Eigene Message
#define MY_MESSAGE WM_USER + 1
//---------------------------------------------------------------------------

#define MY_MESSAGE WM_USER + 1
//---------------------------------------------------------------------------

Hier kann das fertige Projekt (welches mit dem C++ Builder XE7 erstellt wurde) heruntergeladen werden!

Du hast Fragen, Anregungen, o. ä.? Ich freue mich wenn du einen Kommentar hinterlässt!

Kommentare

  1. Wow, vielen Dank, System.Classes.AllocateHWnd muss man erstmal kennen 😉

    Ich würde, bei FMX, vorschlagen bei WM_ENDSESSION einfach nur System.Halt() zu sagen. Dann werden die Unit-Finalisierungen, Klassen-Destruktoren (Gibt es die in C++ überhaupt?) und Formulare (inkl. OnSaveState-Ereignis) ordentlich heruntergefahren und man kann seinen normalen Arbeitsablauf beibehalten.

    1. Hallo,
      schön das ich dir helfen konnte. Ich denke es kommt immer auf den Anwendungsfall an, aber wieso System.Halt() wo dies zu einem „abnormalen“ Abbruch des Programms führt und nicht Application.Terminate() oder Exit() welches das Programm normal „herunterfährt“?

      Gruß,

      Chris

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.