In der Windows API untersuche ich, wie die Funktion GetMessage
tatsächlich funktioniert. Ich habe 3 Implementierungen der Windows-Nachrichtenschleife gesehen und möchte sie erkunden.
Zum Zeitpunkt des Schreibens dieses Posts dies Der MSDN-Artikel beschreibt, was ich für den richtigen Weg zur Implementierung der Nachrichtenschleife halte.
%Vor%
Auf der GetMessage
Funktionsseite , Sehe ich diese Implementierung:
Zuletzt hat die Visual Studio-Dokumentation diese Implementierung als Teil ihrer Win32-Anwendungsdemonstration.
%Vor%
Kurz gesagt, die Implementierung # 3 ignoriert Fehler, die von GetMessage
zurückgegeben werden, funktioniert aber ansonsten genauso wie die erste Implementierung. Das heißt, sie verarbeiten alle Nachrichten für den aktuellen Thread. Und wenn die Funktion GetMessage
0
zurückgibt, enden die Schleifen.
Da ich Implementierung # 2 vor # 1 gefunden habe, dachte ich, dass sie komplett ist. Ich habe jedoch festgestellt, dass GetMessage
nicht 0
zurückgibt, wenn die Nachricht WM_QUIT
über PostQuitMessage
Dies führte zu ein wenig Verwirrung, bis ich Implementierung Nr. 1 fand und sie testete. Der Unterschied zwischen den ersten beiden Implementierungen ist der zweite Parameter für GetMessage
. In # 2 wird die hWnd
angegeben, die gemäß der GetMessage
-Dokumentation lautet:
Ein Handle für das Fenster, dessen Nachrichten abgerufen werden sollen. Das Fenster muss zum aktuellen Thread gehören.
In # 1 ist NULL
, was zu diesem Auszug gehört:
Wenn hWnd NULL ist, ruft GetMessage Nachrichten für jedes Fenster ab, das zum aktuellen Thread gehört, und alle Nachrichten in der Nachrichtenwarteschlange des aktuellen Threads, deren Hwnd-Wert NULL ist (siehe MSG-Struktur). Wenn also hWnd NULL ist, werden sowohl die Fenstermeldungen als auch die Threadnachrichten verarbeitet.
Beim Testen mit NULL
gibt die Funktion GetMessage
0
zurück, wenn die Nachricht WM_QUIT
verarbeitet wird und die Schleife erfolgreich beendet wird.
Auch wenn PostQuitMessage
von der Callback-Funktion eines bestimmten Fensters aufgerufen wird, gehört WM_QUIT
tatsächlich zum Fenster oder dem aktuellen Thread? Basierend auf dem Testen dieser drei Implementierungen scheint es mit dem aktuellen Thread verknüpft zu sein.
Wenn mit dem Thread verknüpft, wenn es sinnvoll oder angebracht ist, ein gültiges hWnd
als Parameter für GetMessage
zu verwenden? Eine solche Nachrichtenschleife wäre nicht in der Lage, 0
als Reaktion auf WM_QUIT
zurückzugeben. Gibt es also eine andere Möglichkeit, die Nachrichtenschleife zu beenden?
GetMessage
PostQuitMessage
WM_QUIT
Nachricht Nach dem MSDN-Dokument von WM_QUIT
:
Die WM_QUIT Nachricht ist nicht mit einem Fenster verknüpft und wird daher niemals durch eine Fensterprozedur empfangen werden. Es wird abgerufen nur durch die Funktionen GetMessage oder PeekMessage.
Da WM_QUIT
keinem Fenster zugeordnet ist und die Übergabe eines HWND
an GetMessage()
nur die mit diesem Fenster verknüpften Nachrichten abruft, wird letzteres nie WM_QUIT
per Entwurf erhalten.
Wenn Sie ein HWND
an GetMessage()
übergeben möchten, würden Sie dies in einer allgemeinen Nachrichtenschleife für eine Anwendung nicht tun. Es gibt jedoch Situationen, in denen Sie Nachrichten pumpen möchten, während etwas in der Benutzeroberfläche stattfindet, und sich nur mit Nachrichten befassen, die mit einem bestimmten Fenster verknüpft sind.
WM_QUIT
ist relevant für einen Thread, nicht für ein einzelnes Fenster. Beachten Sie das Fehlen eines Parameters hwnd
für PostQuitMessage()
. Es gibt keine Möglichkeit, dass es window-spezifisch sein kann, da es keine Möglichkeit gibt, zu bestimmen, in welchem Fenster die Nachricht erzeugt werden soll.
WM_QUIT
ist eigentlich keine echte Nachricht. Wenn Sie PostQuitMessage()
aufrufen, wird im Status der Nachrichtenwarteschlange ein internes Flag gesetzt, dass WM_QUIT
angefordert wurde. Dies wird automatisch von GetMessage()
oder PeekMessage()
zu einem bestimmten Zeitpunkt in der Zukunft generiert (oft sofort, aber wenn die Warteschlange andere gepostete Nachrichten enthält, werden diese zuerst verarbeitet).
Dies wird auf Raymond Chens Blog näher erläutert. Das enthält auch das folgende Zitat:
Als weiteres spezielles Verhalten wird die generierte WM_QUIT-Nachricht umgangen Die Nachrichtenfilter wurden an GetMessage und PeekMessage übergeben Funktionen. Wenn das interne Flag "Nachricht beenden" gesetzt ist, dann Sie erhalten eine WM_QUIT-Nachricht, sobald die Warteschlange ruhig wird, unabhängig welchen Filter du passierst.
Dies deutet darauf hin, dass Ihre Beobachtungen falsch sind, und dass GetMessage()
in Ihrem obigen Beispiel # 2 0 zurückgeben soll, nachdem PostQuitMessage()
aufgerufen wurde, obwohl ein Filterparameter angegeben wurde.
Im Allgemeinen sollten Sie Nachrichtenfilter nur verwenden, wenn Sie eine bestimmte Notwendigkeit dafür haben (z. B. möchten Sie speziell eine Nachricht abrufen, die in einem bestimmten Fenster veröffentlicht wurde). In den meisten Fällen sollten diese Parameter für die normale Funktion der Benutzeroberfläche auf 0 gesetzt sein.
Tags und Links c++ windows winapi message-queue