Informationen zu Meldungen und Meldungswarteschlangen
Im Gegensatz zu MS-DOS-basierten Anwendungen Windows anwendungen ereignisgesteuert. Sie führen keine expliziten Funktionsaufrufe (z. B. C-Laufzeitbibliotheksaufrufe) aus, um Eingaben zu erhalten. Stattdessen warten sie, bis das System eingaben kann.
Das System übergibt alle Eingaben für eine Anwendung an die verschiedenen Fenster in der Anwendung. Jedes Fenster verfügt über eine Funktion, die als Fensterprozedur bezeichnet wird, die das System aufruft, wenn es Eingaben für das Fenster enthält. Die Fensterprozedur verarbeitet die Eingabe und gibt die Steuerung an das System zurück. Weitere Informationen zu Fenster-Prozeduren finden Sie unter Fenster prozeduren.
Wenn ein Fenster der obersten Ebene länger als mehrere Sekunden nicht mehr auf Nachrichten reagiert, betrachtet das System das Fenster als nicht reagierend. In diesem Fall blendet das System das Fenster aus und ersetzt es durch ein ingeordnetes Fenster, das über die gleiche Z-Reihenfolge, Position, Größe und visuelle Attribute verfügt. Dadurch kann der Benutzer es verschieben, seine Größe ändern oder sogar die Anwendung schließen. Dies sind jedoch die einzigen verfügbaren Aktionen, da die Anwendung tatsächlich nicht reagiert. Im Debuggermodus generiert das System kein ingesenkte Fenster.
In diesem Abschnitt werden die folgenden Themen erläutert:
- Windows Nachrichten
- Nachrichtentypen
- Nachrichtenrouting
- Nachrichtenbehandlung
- Nachrichtenfilterung
- Posten und Senden von Nachrichten
- Nachrichten deadlocks
- Senden von Nachrichten
- Abfragen von Nachrichten
Windows-Meldungen
Das System übergibt Eingaben in Form einer Meldung an eine Fensterprozedur. Nachrichten werden sowohl vom System als auch von anwendungen generiert. Das System generiert bei jedem Eingabeereignis eine Meldung, z. B. wenn der Benutzer ein-, mit der Maus bewegt oder auf ein Steuerelement klickt, z. B. eine Bildlaufleiste. Das System generiert auch Meldungen als Reaktion auf Änderungen im System, die von einer Anwendung verursacht werden, z. B. wenn eine Anwendung den Pool der Systemschriftartressourcen ändert oder die Größe eines seiner Fenster ändert. Eine Anwendung kann Nachrichten generieren, um ihre eigenen Fenster an die Ausführung von Aufgaben oder die Kommunikation mit Fenstern in anderen Anwendungen zu richten.
Das System sendet eine Nachricht an eine Fensterprozedur mit einem Satz von vier Parametern: einem Fensterhand handle, einem Nachrichtenbezeichner und zwei Werten, die als Meldungsparameter bezeichnet werden. Das Fensterhand handle identifiziert das Fenster, für das die Nachricht vorgesehen ist. Das System verwendet sie, um zu bestimmen, welche Fensterprozedur die Nachricht empfangen soll.
Ein Nachrichtenbezeichner ist eine benannte Konstante, die den Zweck einer Nachricht identifiziert. Wenn eine Fensterprozedur eine Nachricht empfängt, wird ein Nachrichtenbezeichner verwendet, um zu bestimmen, wie die Nachricht zu verarbeiten ist. Beispielsweise teilt der Nachrichtenbezeichner WM _ PAINT der Fensterprozedur mit, dass sich der Clientbereich des Fensters geändert hat und neu gepaint werden muss.
Nachrichtenparameter geben Daten oder den Speicherort der Daten an, die von einer Fensterprozedur beim Verarbeiten einer Nachricht verwendet werden. Die Bedeutung und der Wert der Nachrichtenparameter hängen von der Nachricht ab. Ein Message-Parameter kann eine ganze Zahl, gepackte Bitflags, einen Zeiger auf eine Struktur mit zusätzlichen Daten und so weiter enthalten. Wenn eine Nachricht keine Nachrichtenparameter verwendet, werden sie in der Regel auf NULL festgelegt. Eine Fensterprozedur muss den Nachrichtenbezeichner überprüfen, um zu bestimmen, wie die Meldungsparameter interpretiert werden sollen.
Nachrichtentypen
In diesem Abschnitt werden die beiden Arten von Nachrichten beschrieben:
System-Defined Nachrichten
Das System sendet oder sendet eine systemdefinierte Nachricht, wenn es mit einer Anwendung kommuniziert. Sie verwendet diese Meldungen, um die Vorgänge von Anwendungen zu steuern und Eingaben und andere Informationen für die Verarbeitung von Anwendungen zur Verfügung zu stellen. Eine Anwendung kann auch systemdefinierte Nachrichten senden oder posten. Anwendungen verwenden diese Meldungen im Allgemeinen, um den Betrieb von Steuerelementfenstern zu steuern, die mithilfe von vorab registrierten Fensterklassen erstellt wurden.
Jede systemdefinierte Nachricht verfügt über einen eindeutigen Nachrichtenbezeichner und eine entsprechende symbolische Konstante (definiert in den SDK-Headerdateien (Software Development Kit), die den Zweck der Nachricht angeben. Beispielsweise fordert die WM _ PAINT-Konstante an, dass ein Fenster seinen Inhalt zeichnet.
Symbolische Konstanten geben die Kategorie an, zu der systemdefinierte Nachrichten gehören. Das Präfix der Konstante identifiziert den Fenstertyp, der die Nachricht interpretieren und verarbeiten kann. Im Folgenden finden Sie die Präfixe und die zugehörigen Nachrichtenkategorien.
Allgemeine Fenstermeldungen decken eine Vielzahl von Informationen und Anforderungen ab, einschließlich Meldungen für Maus- und Tastatureingaben, Menü- und Dialogfeldeingaben, Fenstererstellung und -verwaltung sowie dynamische Daten Exchange (DDE).
Application-Defined Nachrichten
Eine Anwendung kann Nachrichten erstellen, die von ihren eigenen Fenstern oder für die Kommunikation mit Fenstern in anderen Prozessen verwendet werden. Wenn eine Anwendung eigene Nachrichten erstellt, muss die Fensterprozedur, die sie empfängt, die Nachrichten interpretieren und eine entsprechende Verarbeitung bereitstellen.
Nachrichtenbezeichnerwerte werden wie folgt verwendet:
- Das System reserviert Nachrichtenbezeichnerwerte im Bereich 0x0000 bis 0x03FF (der Wert von WM _ USER – 1) für systemdefinierte Nachrichten. Anwendungen können diese Werte nicht für private Nachrichten verwenden.
- Werte im Bereich 0x0400 (der Wert von WM _ USER) bis 0x7FFF sind für Nachrichtenbezeichner für private Fensterklassen verfügbar.
- Wenn Ihre Anwendung als Version 4.0 markiert ist, können Sie Nachrichtenbezeichnerwerte im Bereich 0x8000 (WM _ APP) über 0xBFFF für private Nachrichten verwenden.
- Das System gibt einen Nachrichtenbezeichner im Bereich 0xC000 bis 0xFFFF zurück, wenn eine Anwendung die RegisterWindowMessage-Funktion aufruft, um eine Nachricht zu registrieren. Der von dieser Funktion zurückgegebene Nachrichtenbezeichner ist im gesamten System garantiert eindeutig. Die Verwendung dieser Funktion verhindert Konflikte, die auftreten können, wenn andere Anwendungen denselben Nachrichtenbezeichner für unterschiedliche Zwecke verwenden.
Nachrichtenrouting
Das System verwendet zwei Methoden, um Nachrichten an eine Fensterprozedur weiterzuleiten: das Posten von Nachrichten an eine Warteschlange mit erstem In, die als Nachrichtenwarteschlange bezeichnet wird, ein systemdefiniertes Speicherobjekt, das Nachrichten vorübergehend speichert, und das Senden von Nachrichten direkt an eine Fensterprozedur.
Nachrichten, die an eine Nachrichtenwarteschlange gesendet werden, werden als Nachrichten in der Warteschlange bezeichnet. Dies sind in erster Linie das Ergebnis von Benutzereingaben, die über die Maus oder Tastatur eingegeben wurden, z. B. WM _ MOUSEMOVE, WM _ LBUTTONDOWN, WM _ KEYDOWNund WM _ CHAR. Andere Nachrichten in der Warteschlange umfassen timer-, paint- und quit-Meldungen: WM _ TIMER, WM _ PAINTund WM _ QUIT. Die meisten anderen Nachrichten, die direkt an eine Fensterprozedur gesendet werden, werden als nicht queued-Nachrichten bezeichnet.
Nachrichten in der Warteschlange
Das System kann eine beliebige Anzahl von Fenstern gleichzeitig anzeigen. Um Maus- und Tastatureingaben an das entsprechende Fenster weiterzuleiten, verwendet das System Nachrichtenwarteschlangen.
Das System verwaltet eine einzelne Systemnachrichtenwarteschlange und eine threadspezifische Nachrichtenwarteschlange für jeden GUI-Thread. Um den Mehraufwand beim Erstellen einer Nachrichtenwarteschlange für Nicht-GUI-Threads zu vermeiden, werden zunächst alle Threads ohne Nachrichtenwarteschlange erstellt. Das System erstellt nur dann eine threadspezifische Nachrichtenwarteschlange, wenn der Thread zum ersten Mal eine der spezifischen Benutzerfunktionen aufruft. Keine GUI-Funktionsaufrufe führen zur Erstellung einer Nachrichtenwarteschlange.
Wenn der Benutzer die Maus bewegt, auf die Maustasten klickt oder auf die Tastatur tippt, konvertiert der Gerätetreiber für die Maus oder Tastatur die Eingabe in Nachrichten und platziert sie in der Systemnachrichtenwarteschlange. Das System entfernt die Nachrichten einzeln aus der Systemnachrichtenwarteschlange, überprüft sie, um das Zielfenster zu bestimmen, und sendet sie dann an die Nachrichtenwarteschlange des Threads, der das Zielfenster erstellt hat. Die Nachrichtenwarteschlange eines Threads empfängt alle Maus- und Tastaturmeldungen für die vom Thread erstellten Fenster. Der Thread entfernt Nachrichten aus seiner Warteschlange und weist das System an, sie zur Verarbeitung an die entsprechende Fensterprozedur zu senden.
Mit Ausnahme der WM _ PAINT-Nachricht, der WM _ TIMER-Nachricht und der WM _ QUIT-Nachricht sendet das System immer Nachrichten am Ende einer Nachrichtenwarteschlange. Dadurch wird sichergestellt, dass ein Fenster seine Eingabenachrichten in der richtigen FIFO-Sequenz (First In, First Out) empfängt. Die WM _ PAINT-Nachricht, die WM _ TIMER-Nachricht und die WM _ QUIT-Nachricht werden jedoch in der Warteschlange gespeichert und nur dann an die Fensterprozedur weitergeleitet, wenn die Warteschlange keine anderen Nachrichten enthält. Darüber hinaus werden mehrere WM _ PAINT-Nachrichten für dasselbe Fenster zu einer einzelnen WM _ PAINT-Nachricht kombiniert, wodurch alle ungültigen Teile des Clientbereichs in einem einzigen Bereich konsolidiert werden. Durch das Kombinieren von WM _ PAINT-Nachrichten wird die Anzahl reduziert, mit der ein Fenster den Inhalt des Clientbereichs neu zeichnen muss.
Das System sendet eine Nachricht an die Nachrichtenwarteschlange eines Threads, indem es eine MSG-Struktur auffüllt und diese dann in die Nachrichtenwarteschlange kopiert. Zu den Informationen in MSG gehören: das Handle des Fensters, für das die Nachricht vorgesehen ist, der Nachrichtenbezeichner, die beiden Nachrichtenparameter, die Uhrzeit, zu der die Nachricht gesendet wurde, und die Mauszeigerposition. Ein Thread kann eine Nachricht mithilfe der PostMessage- oder PostThreadMessage-Funktion in seiner eigenen Nachrichtenwarteschlange oder in der Warteschlange eines anderen Threads posten.
Eine Anwendung kann eine Nachricht mithilfe der GetMessage-Funktion aus ihrer Warteschlange entfernen. Um eine Nachricht zu untersuchen, ohne sie aus ihrer Warteschlange zu entfernen, kann eine Anwendung die PeekMessage-Funktion verwenden. Diese Funktion füllt MSG mit Informationen zur Nachricht aus.
Nachdem eine Nachricht aus der Warteschlange entfernt wurde, kann eine Anwendung die DispatchMessage-Funktion verwenden, um das System anweisen, die Nachricht zur Verarbeitung an eine Fensterprozedur zu senden. DispatchMessage verwendet einen Zeiger auf MSG, der durch einen vorherigen Aufruf der GetMessage- oder PeekMessage-Funktion gefüllt wurde. DispatchMessage übergibt das Fensterhandle, den Nachrichtenbezeichner und die beiden Nachrichtenparameter an die Fensterprozedur, übergibt jedoch nicht die Zeit, zu der die Nachricht gesendet wurde, oder die Mauszeigerposition. Eine Anwendung kann diese Informationen abrufen, indem sie die Funktionen GetMessageTime und GetMessagePos aufruft, während eine Nachricht verarbeitet wird.
Ein Thread kann die WaitMessage-Funktion verwenden, um andere Threads zu steuern, wenn keine Nachrichten in der Nachrichtenwarteschlange enthalten sind. Die Funktion hält den Thread an und gibt erst dann zurück, wenn eine neue Nachricht in der Nachrichtenwarteschlange des Threads platziert wird.
Sie können die SetMessageExtraInfo-Funktion aufrufen, um der Nachrichtenwarteschlange des aktuellen Threads einen Wert zuzuordnen. Rufen Sie dann die GetMessageExtraInfo-Funktion auf, um den Wert abzurufen, der der letzten nachricht zugeordnet ist, die von der GetMessage- oder PeekMessage-Funktion abgerufen wurde.
Nicht aus der Queued-Benachrichtigung
Nicht in die Warteschlange eingereihte Nachrichten werden sofort an die Zielfensterprozedur gesendet, wobei die Systemnachrichtenwarteschlange und die Threadnachrichtenwarteschlange umgangen werden. Das System sendet in der Regel Nicht-Queued-Nachrichten, um ein Fenster über Ereignisse zu benachrichtigen, die sich darauf auswirken. Wenn der Benutzer beispielsweise ein neues Anwendungsfenster aktiviert, sendet das System dem Fenster eine Reihe von Nachrichten, einschließlich WM _ ACTIVATE, WM _ SETFOCUSund WM _ SETCURSOR. Diese Meldungen benachrichtigen das Fenster, dass es aktiviert wurde, dass die Tastatureingabe an das Fenster weitergeleitet wird und dass der Mauszeiger innerhalb der Rahmen des Fensters bewegt wurde. Nicht in Queued-Nachrichten können auch dann entstehen, wenn eine Anwendung bestimmte Systemfunktionen aufruft. Beispielsweise sendet das System die WM _ WINDOWPOSCHANGED-Nachricht, nachdem eine Anwendung die SetWindowPos-Funktion verwendet, um ein Fenster zu verschieben.
Einige Funktionen, die Nicht-Queued-Nachrichten senden, sind BroadcastSystemMessage, BroadcastSystemMessageEx, SendMessage, SendMessageTimeoutund SendNotifyMessage.
Nachrichtenverarbeitung
Eine Anwendung muss Nachrichten entfernen und verarbeiten, die an die Nachrichtenwarteschlangen ihrer Threads gesendet werden. Eine Singlethreadanwendung verwendet in der Regel eine Nachrichtenschleife in ihrer WinMain-Funktion, um Nachrichten zu entfernen und zur Verarbeitung an die entsprechenden Fensterprozeduren zu senden. Anwendungen mit mehreren Threads können eine Nachrichtenschleife in jedem Thread enthalten, der ein Fenster erstellt. In den folgenden Abschnitten wird beschrieben, wie eine Nachrichtenschleife funktioniert, und die Rolle einer Fensterprozedur erläutert:
Nachrichtenschleife
Eine einfache Nachrichtenschleife besteht aus einem Funktionsaufruf für jede dieser drei Funktionen: GetMessage, TranslateMessageund DispatchMessage. Beachten Sie Folgendes: Wenn ein Fehler auftritt, gibt GetMessage –1 zurück, sodass spezielle Tests erforderlich sind.
MSG msg;
BOOL bRet;
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Die GetMessage-Funktion ruft eine Nachricht aus der Warteschlange ab und kopiert sie in eine Struktur vom Typ MSG. Sie gibt einen Wert ungleich 0 (null) zurück, es sei denn, die WM _ QUIT-Nachricht wird gefunden. In diesem Fall wird FALSE zurückgegeben, und die Schleife wird beendet. In einer Singlethreadanwendung ist das Beenden der Nachrichtenschleife häufig der erste Schritt beim Schließen der Anwendung. Eine Anwendung kann ihre eigene Schleife beenden, indem sie die PostQuitMessage-Funktion verwendet, in der Regel als Reaktion auf die WM _ DESTROY-Nachricht im Fensterprozedur des Hauptfensters der Anwendung.
Wenn Sie ein Fensterhandle als zweiten Parameter von GetMessageangeben, werden nur Nachrichten für das angegebene Fenster aus der Warteschlange abgerufen. GetMessage kann auch Nachrichten in der Warteschlange filtern und nur die Nachrichten abrufen, die innerhalb eines angegebenen Bereichs liegen. Weitere Informationen zum Filtern von Nachrichten finden Sie unter Nachrichtenfilterung.
Die Nachrichtenschleife eines Threads muss TranslateMessage enthalten, wenn der Thread Zeicheneingaben von der Tastatur empfangen soll. Jedes Mal, wenn der Benutzer eine Taste drückt, generiert das System Virtual Key-Nachrichten (WM _ KEYDOWN und WM _ KEYUP). Eine Virtual Key-Nachricht enthält einen Code mit virtuellen Schlüsseln, der angibt, welche Taste gedrückt wurde, aber nicht deren Zeichenwert. Um diesen Wert abzurufen, muss die Nachrichtenschleife TranslateMessage enthalten, die die Virtual Key-Nachricht in eine Zeichennachricht (WM _ CHAR) übersetzt und wieder in die Anwendungsnachrichtenwarteschlange platziert. Die Zeichennachricht kann dann bei einer nachfolgenden Iteration der Nachrichtenschleife entfernt und an eine Fensterprozedur gesendet werden.
Die DispatchMessage-Funktion sendet eine Nachricht an die Fensterprozedur, die dem in der MSG-Struktur angegebenen Fensterhandle zugeordnet ist. Wenn das Fensterhandle HWND _ TOPMOST ist, sendet DispatchMessage die Nachricht an die Fensterprozwischenvorgänge aller Fenster der obersten Ebene im System. Wenn das Fensterhandle NULL ist, führt DispatchMessage nichts mit der Nachricht aus.
Der Hauptthread einer Anwendung startet seine Nachrichtenschleife, nachdem die Anwendung initialisiert und mindestens ein Fenster erstellt wurde. Nach dem Start ruft die Nachrichtenschleife weiterhin Nachrichten aus der Nachrichtenwarteschlange des Threads ab und verteilt sie an die entsprechenden Fenster. Die Nachrichtenschleife endet, wenn die GetMessage-Funktion die WM _ QUIT-Nachricht aus der Nachrichtenwarteschlange entfernt.
Für eine Nachrichtenwarteschlange ist nur eine Nachrichtenschleife erforderlich, auch wenn eine Anwendung viele Fenster enthält. DispatchMessage verteilt die Nachricht immer an das richtige Fenster. Dies liegt daran, dass jede Nachricht in der Warteschlange eine MSG-Struktur ist, die das Handle des Fensters enthält, zu dem die Nachricht gehört.
Sie können eine Nachrichtenschleife auf verschiedene Weise ändern. Beispielsweise können Sie Nachrichten aus der Warteschlange abrufen, ohne sie an ein Fenster zu senden. Dies ist nützlich für Anwendungen, die Nachrichten posten, die kein Fenster angeben. Sie können GetMessage auch anweisen, nach bestimmten Nachrichten zu suchen und andere Nachrichten in der Warteschlange zu belassen. Dies ist nützlich, wenn Sie die übliche FIFO-Reihenfolge der Nachrichtenwarteschlange vorübergehend umgehen müssen.
Eine Anwendung, die Zugriffstasten verwendet, muss Tastaturnachrichten in Befehlsmeldungen übersetzen können. Zu diesem Zweck muss die Nachrichtenschleife der Anwendung einen Aufruf der TranslateAccelerator-Funktion enthalten. Weitere Informationen zu Tastenkombinationen finden Sie unter Tastenkombinationen.
Wenn ein Thread ein modusloses Dialogfeld verwendet, muss die Meldungsschleife die IsDialogMessage-Funktion enthalten, damit das Dialogfeld Tastatureingaben empfangen kann.
Fensterprozedur
Eine Fensterprozedur ist eine Funktion, die alle an das Fenster gesendeten Nachrichten empfängt und verarbeitet. Jede Fensterklasse verfügt über eine Fensterprozedur, und jedes Fenster, das mit dieser Klasse erstellt wird, verwendet dieselbe Fensterprozedur, um auf Nachrichten zu reagieren.
Das System sendet eine Nachricht an eine Fensterprozedur, indem die Nachrichtendaten als Argumente an die Prozedur übergeben werden. Die Fensterprozedur führt dann eine entsprechende Aktion für die Nachricht aus. es überprüft den Nachrichtenbezeichner und verwendet während der Verarbeitung der Nachricht die von den Nachrichtenparametern angegebenen Informationen.
Eine Fensterprozedur ignoriert in der Regel keine Meldung. Wenn keine Nachricht verarbeitet wird, muss sie zur Standardverarbeitung zurück an das System gesendet werden. Die Fensterprozedur ruft dazu die DefWindowProc-Funktion auf, die eine Standardaktion ausführt und ein Meldungsergebnis zurückgibt. Die Fensterprozedur muss diesen Wert dann als eigenes Meldungsergebnis zurückgeben. Die meisten Fensterprozeduren verarbeiten nur wenige Nachrichten und übergeben die anderen durch Aufrufen von DefWindowProc an das System.
Da eine Fensterprozedur von allen Fenstern gemeinsam genutzt wird, die zur gleichen Klasse gehören, kann sie Nachrichten für mehrere verschiedene Fenster verarbeiten. Um das spezifische Fenster zu identifizieren, das von der Nachricht betroffen ist, kann eine Fensterprozedur das Fensterhandle untersuchen, das mit einer Nachricht übergeben wird. Weitere Informationen zu Fensterprozessen finden Sie unter Window Procedures.
Nachrichtenfilterung
Eine Anwendung kann bestimmte Nachrichten auswählen, die aus der Nachrichtenwarteschlange abgerufen werden sollen (während andere Nachrichten ignoriert werden), indem die Funktion GetMessage oder PeekMessage verwendet wird, um einen Nachrichtenfilter anzugeben. Der Filter ist ein Bereich von Nachrichtenbezeichnern (angegeben durch einen ersten und letzten Bezeichner), ein Fensterhandle oder beides. GetMessage und PeekMessage verwenden einen Nachrichtenfilter, um auszuwählen, welche Nachrichten aus der Warteschlange abgerufen werden sollen. Die Nachrichtenfilterung ist nützlich, wenn eine Anwendung die Nachrichtenwarteschlange nach Nachrichten durchsuchen muss, die später in der Warteschlange eintreffen. Es ist auch nützlich, wenn eine Anwendung Eingabenachrichten (Hardwarenachrichten) verarbeiten muss, bevor gesendete Nachrichten verarbeitet werden.
Die Konstanten WM _ KEYFIRST und WM _ KEYLAST können als Filterwerte verwendet werden, um alle Tastaturmeldungen abzurufen. Die WM _ MOUSEFIRST- und WM _ MOUSELAST-Konstanten können verwendet werden, um alle Mausmeldungen abzurufen.
Jede Anwendung, die Nachrichten filtert, muss sicherstellen, dass eine Nachricht, die den Nachrichtenfilter erfüllt, bereitgestellt werden kann. Wenn eine Anwendung beispielsweise in einem Fenster, das keine Tastatureingabe empfängt, nach einer WM _ CHAR-Nachricht filtert, gibt die GetMessage-Funktion nicht zurück. Dadurch wird die Anwendung effektiv "hängen".
Veröffentlichen und Senden von Nachrichten
Jede Anwendung kann Nachrichten veröffentlichen und senden. Wie das System sendet eine Anwendung eine Nachricht, indem sie sie in eine Nachrichtenwarteschlange kopiert und eine Nachricht sendet, indem die Nachrichtendaten als Argumente an eine Fensterprozedur übergeben werden. Zum Posten von Nachrichten verwendet eine Anwendung die PostMessage-Funktion. Eine Anwendung kann eine Nachricht senden, indem sie die SendMessage-, BroadcastSystemMessage-, SendMessageCallback-, SendMessageTimeout-, SendNotifyMessage-oder SendDlgItemMessage-Funktion aufruft.
Posten von Nachrichten
Eine Anwendung sendet in der Regel eine Nachricht, um ein bestimmtes Fenster zum Ausführen einer Aufgabe zu benachrichtigen. PostMessage erstellt eine MSG-Struktur für die Nachricht und kopiert die Nachricht in die Nachrichtenwarteschlange. Die Nachrichtenschleife der Anwendung ruft schließlich die Nachricht ab und verteilt sie an die entsprechende Fensterprozedur.
Eine Anwendung kann eine Nachricht posten, ohne ein Fenster anzugeben. Wenn die Anwendung beim Aufrufen von PostMessageein NULL-Fensterhandle zur Verfügung stellt, wird die Nachricht an die Warteschlange gesendet, die dem aktuellen Thread zugeordnet ist. Da kein Fensterhandle angegeben ist, muss die Anwendung die Nachricht in der Nachrichtenschleife verarbeiten. Dies ist eine Möglichkeit, eine Nachricht zu erstellen, die für die gesamte Anwendung und nicht für ein bestimmtes Fenster gilt.
Gelegentlich können Sie eine Nachricht an alle Fenster der obersten Ebene im System senden. Eine Anwendung kann eine Nachricht an alle Fenster der obersten Ebene senden, indem PostMessage aufgerufen und HWND _ TOPMOST im hwnd-Parameter angegeben wird.
Ein häufiger Programmierfehler besteht darin, davon auszugehen, dass die PostMessage-Funktion immer eine Nachricht sendet. Dies gilt nicht, wenn die Nachrichtenwarteschlange voll ist. Eine Anwendung sollte den Rückgabewert der PostMessage-Funktion überprüfen, um zu ermitteln, ob die Nachricht gesendet wurde, und, falls nicht, die Nachricht erneut posten.
Senden von Nachrichten
Eine Anwendung sendet in der Regel eine Nachricht, um eine Fensterprozedur zur sofortigen Ausführung einer Aufgabe zu benachrichtigen. Die SendMessage-Funktion sendet die Nachricht an die Fensterprozedur, die dem angegebenen Fenster entspricht. Die Funktion wartet, bis die Fensterprozedur die Verarbeitung abgeschlossen hat, und gibt dann das Meldungsergebnis zurück. Übergeordnete und untergeordnete Fenster kommunizieren häufig, indem Nachrichten miteinander gesendet werden. Beispielsweise kann ein übergeordnetes Fenster, das über ein Bearbeitungssteuerelement als untergeordnetes Fenster verfügt, den Text des Steuerelements festlegen, indem eine Nachricht an das Steuerelement gesendet wird. Das Steuerelement kann das übergeordnete Fenster über Änderungen an dem Text benachrichtigen, der vom Benutzer ausgeführt wird, indem Nachrichten an das übergeordnete Element gesendet werden.
Die SendMessageCallback-Funktion sendet auch eine Nachricht an die Fensterprozedur, die dem angegebenen Fenster entspricht. Diese Funktion gibt jedoch sofort zurück. Nachdem die Meldung von der Fensterprozedur verarbeitet wurde, ruft das System die angegebene Rückruffunktion auf. Weitere Informationen zur Rückruffunktion finden Sie in der SendAsyncProc-Funktion.
Gelegentlich können Sie eine Nachricht an alle Fenster der obersten Ebene im System senden. Wenn die Anwendung beispielsweise die Systemzeit ändert, muss sie alle Fenster der obersten Ebene über die Änderung benachrichtigen, indem eine WM _ TIMECHANGE-Nachricht gesendet wird. Eine Anwendung kann eine Nachricht an alle Fenster der obersten Ebene senden, indem SendMessage aufgerufen und HWND _ TOPMOST im hwnd-Parameter angegeben wird. Sie können eine Nachricht auch an alle Anwendungen senden, indem Sie die BroadcastSystemMessage-Funktion aufrufen und BSM _ APPLICATIONS im lpdwRecipients-Parameter angeben.
Mithilfe der Funktion InSendMessage oder InSendMessageEx kann eine Fensterprozedur bestimmen, ob eine von einem anderen Thread gesendete Nachricht verarbeitet wird. Diese Funktion ist nützlich, wenn die Nachrichtenverarbeitung vom Ursprung der Nachricht abhängt.
Nachrichten-Deadlocks
Ein Thread, der die SendMessage-Funktion aufruft, um eine Nachricht an einen anderen Thread zu senden, kann erst ausgeführt werden, wenn die Fensterprozedur, die die Nachricht empfängt, zurückgegeben wird. Wenn der empfangende Thread die Steuerung während der Verarbeitung der Nachricht zurückgibt, kann der sendende Thread nicht weiter ausgeführt werden, da er auf die Rückgabe von SendMessage wartet. Wenn der empfangende Thread an dieselbe Warteschlange wie der Absender angefügt ist, kann dies zu einem Anwendungsde deadlock führen. (Beachten Sie, dass Journalhooks Threads an dieselbe Warteschlange anfügen.)
Beachten Sie, dass der empfangende Thread die Steuerung nicht explizit ergeben muss. Das Aufrufen einer der folgenden Funktionen kann dazu führen, dass ein Thread die Steuerung implizit ergibt.
- DialogBox
- DialogBoxIndirect
- DialogBoxIndirectParam
- DialogBoxParam
- GetMessage
- Messagebox
- PeekMessage
- SendMessage
Um potenzielle Deadlocks in Ihrer Anwendung zu vermeiden, sollten Sie die SendNotifyMessage- oder SendMessageTimeout-Funktionen verwenden. Andernfalls kann eine Fensterprozedur ermitteln, ob eine empfangene Nachricht von einem anderen Thread gesendet wurde, indem die Funktion InSendMessage oder InSendMessageEx aufgerufen wird. Bevor beim Verarbeiten einer Nachricht eine der Funktionen in der vorherigen Liste aufgerufen wird, sollte die Fensterprozedur zuerst InSendMessage oder InSendMessageEx aufrufen. Wenn diese Funktion TRUE zurückgibt, muss die Fensterprozedur die ReplyMessage-Funktion vor jeder Funktion aufrufen, die bewirkt, dass der Thread die Steuerung liefert.
Senden von Nachrichten
Jede Nachricht besteht aus einem Nachrichtenbezeichner und zwei Parametern, wParam und lParam. Der Nachrichtenbezeichner ist ein eindeutiger Wert, der den Zweck der Nachricht angibt. Die Parameter stellen zusätzliche Nachrichteninformationen bereit, aber der wParam-Parameter ist im Allgemeinen ein Typwert, der weitere Informationen über die Nachricht bereitstellt.
Eine Nachrichtenübertragung ist einfach das Senden einer Nachricht an mehrere Empfänger im System. Verwenden Sie zum Übertragen einer Nachricht aus einer Anwendung die BroadcastSystemMessage-Funktion, und geben Sie die Empfänger der Nachricht an. Anstatt einzelne Empfänger anzugeben, müssen Sie mindestens einen Empfängertyp angeben. Diese Typen sind Anwendungen, installierbare Treiber, Netzwerktreiber und Gerätetreiber auf Systemebene. Das System sendet Broadcastnachrichten an alle Member jedes angegebenen Typs.
Das System überträgt Nachrichten in der Regel als Reaktion auf Änderungen, die innerhalb von Gerätetreibern auf Systemebene oder zugehörigen Komponenten vorgenommen werden. Der Treiber oder die zugehörige Komponente überträgt die Nachricht an Anwendungen und andere Komponenten, um sie über die Änderung zu benachrichtigen. Die für Datenträgerlaufwerke zuständige Komponente sendet z. B. immer dann eine Nachricht, wenn der Gerätetreiber für das Diskettenlaufwerk eine Medienänderung erkennt, z. B. wenn der Benutzer einen Datenträger in das Laufwerk einfügt.
Das System überträgt Nachrichten in dieser Reihenfolge an Empfänger: Gerätetreiber auf Systemebene, Netzwerktreiber, installierbare Treiber und Anwendungen. Dies bedeutet, dass Gerätetreiber auf Systemebene immer die erste Möglichkeit erhalten, auf eine Nachricht zu reagieren, wenn sie als Empfänger ausgewählt werden. Innerhalb eines bestimmten Empfängertyps erhält kein Treiber garantiert eine bestimmte Nachricht vor einem anderen Treiber. Dies bedeutet, dass eine Nachricht, die für einen bestimmten Treiber vorgesehen ist, über einen global eindeutigen Nachrichtenbezeichner verfügen muss, damit sie von keinem anderen Treiber versehentlich verarbeitet wird.
Sie können Nachrichten auch an alle Fenster der obersten Ebene übertragen, indem Sie HWND _ BROADCAST in der SendMessage-, SendMessageCallback-, SendMessageTimeout-oder SendNotifyMessage-Funktion angeben.
Anwendungen empfangen Nachrichten über die Fensterprozedur ihrer Fenster der obersten Ebene. Nachrichten werden nicht an untergeordnete Fenster gesendet. Dienste können Nachrichten über eine Fensterprozedur oder deren Dienststeuerungshandler empfangen.
Hinweis
Gerätetreiber auf Systemebene verwenden eine verwandte Funktion auf Systemebene, um Systemnachrichten zu übertragen.
Abfragen von Nachrichten
Sie können eigene benutzerdefinierte Nachrichten erstellen und verwenden, um Aktivitäten zwischen Ihren Anwendungen und anderen Komponenten im System zu koordinieren. Dies ist besonders nützlich, wenn Sie eigene installierbare Treiber oder Gerätetreiber auf Systemebene erstellt haben. Ihre benutzerdefinierten Nachrichten können Informationen zu und von Ihrem Treiber und den Anwendungen enthalten, die den Treiber verwenden.
Verwenden Sie eine Abfragemeldung, um Empfänger nach der Berechtigung zum Ausführen einer bestimmten Aktion abzufragen. Sie können eigene Abfragenachrichten generieren, indem Sie den BSF _ QUERY-Wert im dwFlags-Parameter festlegen, wenn Sie BroadcastSystemMessageaufrufen. Jeder Empfänger der Abfragenachricht muss TRUE zurückgeben, damit die Funktion die Nachricht an den nächsten Empfänger sendet. Wenn ein Empfänger BROADCAST _ QUERY _ DENY zurückgibt, wird die Übertragung sofort beendet, und die Funktion gibt eine Null zurück.