Informationen zu Meldungen und Meldungswarteschlangen
Im Gegensatz zu MS-DOS-basierten Anwendungen sind Windows-basierte Anwendungen ereignisgesteuert. Sie führen keine expliziten Funktionsaufrufe (z. B. C-Laufzeitbibliotheksaufrufe) aus, um Eingaben zu erhalten. Stattdessen warten sie, bis das System eingaben an sie weitergibt.
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 über Eingaben für das Fenster verfügt. Die Fensterprozedur verarbeitet die Eingabe und gibt die Steuerung an das System zurück. Weitere Informationen zu Fensterprozeduren finden Sie unter Fensterprozeduren.
Wenn ein Fenster der obersten Ebene länger als mehrere Sekunden lang nicht mehr auf Nachrichten reagiert, wird das Fenster vom System als nicht reagiert betrachtet. In diesem Fall blendet das System das Fenster aus und ersetzt es durch ein Geisterfenster, das die gleichen Z-Reihenfolge, Position, Größe und visuellen Attribute aufweist. Dadurch kann der Benutzer die Anwendung verschieben, seine Größe ändern oder die Anwendung sogar schließen. Dies sind jedoch die einzigen verfügbaren Aktionen, da die Anwendung tatsächlich nicht reagiert. Im Debuggermodus generiert das System kein Geisterfenster.
In diesem Abschnitt werden die folgenden Themen behandelt:
- Windows-Nachrichten
- Nachrichtentypen
- Nachrichtenrouting
- Nachrichtenbehandlung
- Nachrichtenfilterung
- Posten und Senden von Nachrichten
- Nachrichten-Deadlocks
- Senden von Nachrichten
- Abfragen von Nachrichten
Windows-Meldungen
Das System übergibt die Eingabe in Form einer Nachricht 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 eingibt, die Maus bewegt oder auf ein Steuerelement wie eine Bildlaufleiste klickt. Das System generiert auch Nachrichten 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 ihrer Fenster ändert. Eine Anwendung kann Nachrichten generieren, um ihre eigenen Fenster anweisen, Aufgaben auszuführen oder mit Fenstern in anderen Anwendungen zu kommunizieren.
Das System sendet eine Nachricht mit einem Satz von vier Parametern an eine Fensterprozedur: ein Fensterhandle, einen Nachrichtenbezeichner und zwei Werte, die als Nachrichtenparameter bezeichnet werden. Das Fensterhandle 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 verarbeitet werden soll. Beispielsweise teilt der Nachrichtenbezeichner WM_PAINT der Fensterprozedur mit, dass sich der Clientbereich des Fensters geändert hat und neu gezeichnet werden muss.
Nachrichtenparameter geben Daten oder den Speicherort der Daten an, die von einer Fensterprozedur bei der Verarbeitung einer Nachricht verwendet werden. Die Bedeutung und der Wert der Nachrichtenparameter hängen von der Nachricht ab. Ein Nachrichtenparameter kann eine ganze Zahl, gepackte Bitflags, einen Zeiger auf eine Struktur mit zusätzlichen Daten usw. enthalten. Wenn eine Nachricht keine Nachrichtenparameter verwendet, werden diese in der Regel auf NULL festgelegt. Eine Fensterprozedur muss den Nachrichtenbezeichner überprüfen, um zu bestimmen, wie die Nachrichtenparameter 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. Es verwendet diese Nachrichten, um die Vorgänge von Anwendungen zu steuern und Eingaben und andere Informationen für Anwendungen bereitzustellen, die verarbeitet werden sollen. 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 des Software Development Kit), die den Zweck der Nachricht angibt. Beispielsweise fordert die WM_PAINT konstante Anforderungen an, dass ein Fenster seinen Inhalt zeichnet.
Symbolische Konstanten geben die Kategorie an, zu der systemdefinierte Nachrichten gehören. Das Präfix der Konstante gibt den Typ des Fensters an, das die Nachricht interpretieren und verarbeiten kann. Im Folgenden werden die Präfixe und die zugehörigen Nachrichtenkategorien aufgeführt.
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 dynamischer Datenaustausch (DDE).
Application-Defined-Nachrichten
Eine Anwendung kann Nachrichten erstellen, die von ihren eigenen Fenstern oder zur 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 (wert von WM_USER) bis 0x7FFF sind für Nachrichtenbezeichner für private Fensterklassen verfügbar.
- Wenn Ihre Anwendung mit Version 4.0 gekennzeichnet ist, können Sie Nachrichtenbezeichnerwerte im Bereich 0x8000 (WM_APP) bis 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 garantiert im gesamten System 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 Senden von Nachrichten an eine first-in-, first-out-Warteschlange, die als Nachrichtenwarteschlange bezeichnet wird, ein systemdefiniertes Speicherobjekt, das Nachrichten vorübergehend speichert, und das Senden von Nachrichten direkt an eine Fensterprozedur.
Nachrichten, die in einer Nachrichtenwarteschlange bereitgestellt werden, werden als Nachricht in der Warteschlange bezeichnet. Diese sind hauptsächlich das Ergebnis von Benutzereingaben, die über die Maus oder Tastatur eingegeben werden, z. B. WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_KEYDOWN und WM_CHAR Nachrichten. Andere Nachrichten in der Warteschlange umfassen die Timer-, Paint- und Quit-Nachrichten: WM_TIMER, WM_PAINT und WM_QUIT. Die meisten anderen Nachrichten, die direkt an eine Fensterprozedur gesendet werden, werden als nicht in die Warteschlange gestellte 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 alle Threads zunächst 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 zum Erstellen einer Nachrichtenwarteschlange.
Wenn der Benutzer die Maus bewegt, auf die Maustasten klickt oder auf die Tastatur eingibt, 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, untersucht sie, um das Zielfenster zu bestimmen, und stellt sie dann in die Nachrichtenwarteschlange des Threads, der das Zielfenster erstellt hat. Die Nachrichtenwarteschlange eines Threads empfängt alle Maus- und Tastaturnachrichten für die fenster, die vom Thread erstellt wurden. 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 postet das System immer Nachrichten am Ende einer Nachrichtenwarteschlange. Dadurch wird sichergestellt, dass ein Fenster seine Eingabemeldungen 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 beibehalten 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 in einer einzelnen WM_PAINT Nachricht kombiniert, wodurch alle ungültigen Teile des Clientbereichs in einem einzelnen Bereich konsolidiert werden. Durch das Kombinieren WM_PAINT Nachrichten wird die Anzahl der Wiederholungen reduziert, mit denen ein Fenster den Inhalt des Clientbereichs neu zeichnen muss.
Das System sendet eine Nachricht in die Nachrichtenwarteschlange eines Threads, indem eine MSG-Struktur gefüllt und dann in die Nachrichtenwarteschlange kopiert wird. Informationen in MSG umfassen: das Handle des Fensters, für das die Nachricht vorgesehen ist, den Nachrichtenbezeichner, die beiden Nachrichtenparameter, den Zeitpunkt der Veröffentlichung der Nachricht und die Mauscursorposition. 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 der Warteschlange entfernen. Um eine Nachricht zu untersuchen, ohne sie aus der 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 anzuweisen, die Nachricht zur Verarbeitung an eine Fensterprozedur zu senden. DispatchMessage verwendet einen Zeiger auf MSG , der von einem vorherigen Aufruf der GetMessage - oder PeekMessage-Funktion ausgefüllt wurde. DispatchMessage übergibt das Fensterhandle, den Nachrichtenbezeichner und die beiden Nachrichtenparameter an die Fensterprozedur, verstreicht jedoch nicht den Zeitpunkt, zu dem die Nachricht gepostet wurde, oder die Mauszeigerposition. Eine Anwendung kann diese Informationen abrufen, indem sie während der Verarbeitung einer Nachricht die Funktionen GetMessageTime und GetMessagePos aufruft .
Ein Thread kann die WaitMessage-Funktion verwenden, um anderen Threads die Kontrolle zu übergeben, wenn er keine Nachrichten in seiner Nachrichtenwarteschlange enthält. Die Funktion hält den Thread an und gibt erst zurück, wenn eine neue Nachricht in die Nachrichtenwarteschlange des Threads eingefügt 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 warteschlangenierte Nachrichten
Nicht in die Warteschlange stehenden Nachrichten werden sofort an die Zielfensterprozedur gesendet, wobei die Systemnachrichtenwarteschlange und die Threadnachrichtenwarteschlange umgangen werden. Das System sendet in der Regel nicht warteschlangenfreie 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_SETFOCUS und WM_SETCURSOR. Diese Meldungen benachrichtigen das Fenster, dass es aktiviert wurde, dass die Tastatureingabe an das Fenster weitergeleitet wird und dass der Mauscursor innerhalb der Rahmen des Fensters bewegt wurde. Nicht warteschlangenierte Nachrichten können auch auftreten, wenn eine Anwendung bestimmte Systemfunktionen aufruft. Beispielsweise sendet das System die WM_WINDOWPOSCHANGED-Nachricht , nachdem eine Anwendung die SetWindowPos-Funktion verwendet hat, um ein Fenster zu verschieben.
Einige Funktionen, die Nachrichten ohne Warteschlange senden, sind BroadcastSystemMessage, BroadcastSystemMessageEx, SendMessage, SendMessageTimeout und SendNotifyMessage.
Nachrichtenbehandlung
Eine Anwendung muss Nachrichten entfernen und verarbeiten, die an die Nachrichtenwarteschlangen ihrer Threads gesendet wurden. 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 in jedem Thread, der ein Fenster erstellt, eine Nachrichtenschleife enthalten. In den folgenden Abschnitten wird beschrieben, wie eine Nachrichtenschleife funktioniert, und die Rolle einer Fensterprozedur wird erläutert:
Nachrichtenschleife
Eine einfache Nachrichtenschleife besteht aus einem Funktionsaufruf für jede dieser drei Funktionen: GetMessage, TranslateMessage und DispatchMessage. Beachten Sie, dass GetMessage bei einem Fehler –1 zurückgibt, sodass die speziellen 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. Es gibt einen Wert ungleich Null zurück, es sei denn, es wird die WM_QUIT Meldung angezeigt. In diesem Fall wird FALSE zurückgegeben und die Schleife 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 mit der PostQuitMessage-Funktion beenden, in der Regel als Reaktion auf die WM_DESTROY Nachricht in der Fensterprozedur des Standard Fensters der Anwendung.
Wenn Sie ein Fensterhandle als zweiten Parameter von GetMessage angeben, 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. Das System generiert bei jedem Drücken einer Taste virtuelle Schlüsselnachrichten (WM_KEYDOWN und WM_KEYUP). Eine Nachricht mit virtuellen Schlüsseln enthält einen Code für virtuelle Schlüssel, der identifiziert, welche Taste gedrückt wurde, aber nicht ihren Zeichenwert. Um diesen Wert abzurufen, muss die Nachrichtenschleife TranslateMessage enthalten, die die Nachricht mit dem virtuellen Schlüssel 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 Fensterprozeduren aller Fenster der obersten Ebene im System. Wenn das Fensterhandle NULL ist, führt DispatchMessage mit der Nachricht nichts aus.
Der Standard Thread einer Anwendung startet die 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 sendet 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 sendet 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 Arten ändern. Beispielsweise können Sie Nachrichten aus der Warteschlange abrufen, ohne sie an ein Fenster zu verteilen. 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, sodass andere Nachrichten in der Warteschlange verbleiben. Dies ist nützlich, wenn Sie die übliche FIFO-Reihenfolge der Nachrichtenwarteschlange vorübergehend umgehen müssen.
Eine Anwendung, die Zugriffstasten verwendet, muss in der Lage sein, Tastaturnachrichten in Befehlsmeldungen zu übersetzen. Dazu muss die Nachrichtenschleife der Anwendung einen Aufruf der TranslateAccelerator-Funktion enthalten. Weitere Informationen zu Zugriffstasten finden Sie unter Tastaturbeschleunigungen.
Wenn ein Thread ein modusloses Dialogfeld verwendet, muss die Nachrichtenschleife die IsDialogMessage-Funktion enthalten, damit das Dialogfeld Tastatureingaben empfangen kann.
Window-Prozedur
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 wurde, 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 geeignete Aktion für die Nachricht aus. Es überprüft den Nachrichtenbezeichner und verwendet während der Verarbeitung der Nachricht die durch die Nachrichtenparameter angegebenen Informationen.
Eine Fensterprozedur ignoriert in der Regel keine Nachricht. Wenn keine Nachricht verarbeitet wird, muss die Nachricht zur Standardverarbeitung zurück an das System gesendet werden. Die Fensterprozedur ruft dazu die Funktion DefWindowProc auf, die eine Standardaktion ausführt und ein Meldungsergebnis zurückgibt. Die Fensterprozedur muss dann diesen Wert als eigenes Meldungsergebnis zurückgeben. Die meisten Fensterprozeduren verarbeiten nur ein paar Nachrichten und übergeben die anderen an das System, indem Sie DefWindowProc aufrufen.
Da eine Fensterprozedur von allen Fenstern gemeinsam genutzt wird, die derselben Klasse angehören, kann sie Meldungen für mehrere verschiedene Fenster verarbeiten. Um das bestimmte Fenster zu identifizieren, das von der Nachricht betroffen ist, kann eine Fensterprozedur das Fensterhandle untersuchen, das mit einer Nachricht übergeben wird. Weitere Informationen zu Fensterprozeduren finden Sie unter Fensterprozeduren.
Nachrichtenfilterung
Eine Anwendung kann bestimmte Nachrichten auswählen, die aus der Nachrichtenwarteschlange abgerufen werden sollen (während andere Nachrichten ignoriert werden), indem sie die GetMessage - oder PeekMessage-Funktion verwendet, 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 eingetroffen sind. Es ist auch nützlich, wenn eine Anwendung Eingabenachrichten (Hardware) verarbeiten muss, bevor sie bereitgestellte Nachrichten verarbeitet.
Die WM_KEYFIRST - und WM_KEYLAST-Konstanten können als Filterwerte verwendet werden, um alle Tastaturnachrichten abzurufen. Die konstanten WM_MOUSEFIRST und WM_MOUSELAST können verwendet werden, um alle Mausnachrichten abzurufen.
Jede Anwendung, die Nachrichten filtert, muss sicherstellen, dass eine Nachricht, die dem Nachrichtenfilter gerecht wird, gepostet werden kann. Wenn beispielsweise eine Anwendung nach einer WM_CHAR Nachricht in einem Fenster filtert, das keine Tastatureingaben empfängt, wird die GetMessage-Funktion nicht zurückgegeben. Dies "hängt" die Anwendung effektiv.
Posten und Senden von Nachrichten
Jede Anwendung kann Nachrichten posten und senden. Wie das System postet eine Anwendung eine Nachricht, indem sie sie in eine Nachrichtenwarteschlange kopiert, und sendet eine Nachricht, indem sie die Nachrichtendaten als Argumente an eine Fensterprozedur übergibt. Um Nachrichten zu posten, verwendet eine Anwendung die PostMessage-Funktion . Eine Anwendung kann eine Nachricht senden, indem sie die Funktion SendMessage, BroadcastSystemMessage, SendMessageCallback, SendMessageTimeout, SendNotifyMessage oder SendDlgItemMessage aufruft .
Posten von Nachrichten
Eine Anwendung sendet in der Regel eine Nachricht, um ein bestimmtes Fenster zu benachrichtigen, um eine Aufgabe auszuführen. 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 sendet sie an die entsprechende Fensterprozedur.
Eine Anwendung kann eine Nachricht posten, ohne ein Fenster anzugeben. Wenn die Anwendung beim Aufrufen von PostMessage ein NULL-Fensterhandle bereitstellt, 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 posten. Eine Anwendung kann eine Nachricht in allen Fenstern der obersten Ebene veröffentlichen, 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 postet. Dies trifft nicht zu, wenn die Nachrichtenwarteschlange voll ist. Eine Anwendung sollte den Rückgabewert der PostMessage-Funktion überprüfen, um zu bestimmen, ob die Nachricht gepostet wurde, und, falls nicht, sie erneut posten.
Senden von Nachrichten
Eine Anwendung sendet in der Regel eine Nachricht, um eine Fensterprozedur zu benachrichtigen, um eine Aufgabe sofort auszuführen. 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 aneinander 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 am Text benachrichtigen, die vom Benutzer vorgenommen werden, indem es Nachrichten zurück an das übergeordnete Element sendet.
Die SendMessageCallback-Funktion sendet auch eine Nachricht an die Fensterprozedur, die dem angegebenen Fenster entspricht. Diese Funktion gibt jedoch sofort zurück. Nachdem die Fensterprozedur die Nachricht verarbeitet hat, ruft das System die angegebene Rückruffunktion auf. Weitere Informationen zur Rückruffunktion finden Sie in der SendAsyncProc-Funktion .
Gelegentlich möchten Sie möglicherweise 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 sie eine WM_TIMECHANGE Nachricht sendet. Eine Anwendung kann eine Nachricht an alle Fenster der obersten Ebene senden, indem SendMessage aufgerufen und imhwnd-Parameter HWND_TOPMOST angegeben wird. Sie können eine Nachricht auch an alle Anwendungen übertragen, indem Sie die BroadcastSystemMessage-Funktion aufrufen und BSM_APPLICATIONS im parameter lpdwRecipients 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 die Ausführung erst fortsetzen, wenn die Fensterprozedur, die die Nachricht empfängt, zurückgegeben wird. Wenn der empfangende Thread während der Verarbeitung der Nachricht eine Steuerung liefert, kann der sendende Thread die Ausführung nicht fortsetzen, 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 Anwendungs-Deadlock führen. (Beachten Sie, dass Journalhooks Threads an dieselbe Warteschlange anfügen.)
Beachten Sie, dass der empfangende Thread keine explizite Steuerung liefern muss. Das Aufrufen einer der folgenden Funktionen kann dazu führen, dass ein Thread implizit eine Steuerung liefert.
- Dialogfeld
- DialogBoxIndirect
- DialogBoxIndirectParam
- DialogBoxParam
- GetMessage
- Messagebox
- PeekMessage
- SendMessage
Um potenzielle Deadlocks in Ihrer Anwendung zu vermeiden, sollten Sie die Funktionen SendNotifyMessage oder SendMessageTimeout verwenden. Andernfalls kann eine Fensterprozedur bestimmen, ob eine empfangene Nachricht von einem anderen Thread gesendet wurde, indem die Funktion InSendMessage oder InSendMessageEx aufgerufen wird. Bevor eine der Funktionen in der vorherigen Liste während der Verarbeitung einer Nachricht 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 dazu führt, dass der Thread steuerungsgesteuert wird.
Senden von Nachrichten
Jede Nachricht besteht aus einem Nachrichtenbezeichner und den beiden Parametern wParam und lParam. Der Nachrichtenbezeichner ist ein eindeutiger Wert, der den Nachrichtenzweck angibt. Die Parameter stellen zusätzliche Informationen bereit, die nachrichtenspezifisch sind, aber der wParam-Parameter ist im Allgemeinen ein Typwert, der weitere Informationen zur Nachricht bereitstellt.
Eine Nachrichtenübertragung ist einfach das Senden einer Nachricht an mehrere Empfänger im System. Um eine Nachricht aus einer Anwendung zu übertragen, verwenden Sie die BroadcastSystemMessage-Funktion , und geben Sie die Empfänger der Nachricht an. Anstatt einzelne Empfänger anzugeben, müssen Sie einen oder mehrere Empfängertypen 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 sendet in der Regel Nachrichten als Reaktion auf Änderungen, die innerhalb von Gerätetreibern auf Systemebene oder zugehörigen Komponenten vorgenommen werden. Der Treiber oder die zugehörige Komponente sendet die Nachricht an Anwendungen und andere Komponenten, um sie über die Änderung zu informieren. Beispielsweise sendet die für Datenträger zuständige Komponente eine Meldung, 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 sendet Nachrichten in dieser Reihenfolge an Empfänger: Gerätetreiber auf Systemebene, Netzwerktreiber, installierbare Treiber und Anwendungen. Dies bedeutet, dass Gerätetreiber auf Systemebene, wenn sie als Empfänger ausgewählt werden, immer die erste Gelegenheit haben, auf eine Nachricht zu antworten. Innerhalb eines bestimmten Empfängertyps wird garantiert, dass kein Treiber eine bestimmte Nachricht vor einem anderen Treiber empfängt. Dies bedeutet, dass eine Nachricht, die für einen bestimmten Treiber vorgesehen ist, über einen global eindeutigen Nachrichtenbezeichner verfügen muss, damit sie nicht versehentlich von einem anderen Treiber verarbeitet wird.
Sie können Nachrichten auch an alle Fenster der obersten Ebene übertragen, indem Sie HWND_BROADCAST in der Funktion SendMessage, SendMessageCallback, SendMessageTimeout oder SendNotifyMessage angeben.
Anwendungen empfangen Nachrichten über die Fensterprozedur ihrer Fenster auf oberster 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 zugehörige 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 zu den Anwendungen enthalten, die den Treiber verwenden.
Verwenden Sie eine Abfragenachricht, um Empfänger nach der Berechtigung zum Ausführen einer bestimmten Aktion abzufragen. Sie können ihre eigenen Abfragemeldungen generieren, indem Sie den BSF_QUERY-Wert im dwFlags-Parameter festlegen, wenn BroadcastSystemMessage aufgerufen wird. Jeder Empfänger der Abfragenachricht muss TRUE zurückgeben, damit die Funktion die Nachricht an den nächsten Empfänger senden kann. Wenn ein Empfänger BROADCAST_QUERY_DENY zurückgibt, wird die Übertragung sofort beendet, und die Funktion gibt eine Null zurück.