Die Nachrichtenschleife


In der Nachrichtenschleife werden alle Nachrichten gesammelt. Wird das Fenster geschlossen, liefert "GetMessage" den Wert "WM_DESTROY". Dies Nachricht wird an die Fensterfunktion "WndProc" weitergeleitet und dort mit "PostQuitMessage(0);" beantwortet. Dadurch wird in "GetMessage" der Rückgabewert Null (false) erzeugt, der die while-Schleife beendet und das Programm dann tatsächlich beendet.:

while GetMessage(msg,0,0,0) do
  begin
    TranslateMessage(msg);
    DispatchMessage(msg);
  end;

An dieser Stelle soll Ihnen ein Auszug aus der Hilfe den Umgang mit "GetMessage" verdeutlichen:

BOOL GetMessage(
  LPMSG lpMsg,         // address of structure with message
  HWND hWnd,           // handle of window
  UINT wMsgFilterMin,  // first message
  UINT wMsgFilterMax   // last message
);

Ist hWnd auf Null gesetzt, erhält die Funktion die Nachrichten aller Fenster, die zum aufrufenden Thread gehören. Mit Hilfe von wMsgFilterMin und wMsgFilterMax kann man die eingehenden Nachrichten filtern.

Zu Testzwecken kommentieren wir die beiden Zeilen im Schleifenrumpf des Beispielprogramms einfach mal aus und beobachten das Ergebnis. Wir stellen fest, dass unser Programm gar nicht mehr reagiert. Wie sollte es auch? "GetMessage" fängt zwar die Nachrichten ab, kann sie aber (mangels Funktionen) nicht weiterreichen. Es findet keine Verarbeitung der Nachrichten statt, und das Programm hängt in der Endlosschleife fest.
Wir brauchen also zumindest die Funktion "DispatchMessage", denn diese gibt die Nachrichten geordnet an die Fensterfunktion weiter. "TranslateMessage" übersetzt virtuelle Tastaturcodes. Da wir in unserem Beispiel aber keine Tastatureingaben verarbeiten, könnten wir ebenso gut auf diese Funktion verzichten.

Die Msg-Struktur ist die Schnittstelle zu den Windows-Nachrichten. Innerhalb dieser Struktur befinden sich alle notwendigen Informationen, die die Nachricht beschreiben. Sie sehen dies sehr schön in der Funktion "WndProc", wo auf die verschiedenen Nachrichten reagiert wird. Schauen Sie sich doch bitte einmal diesen Auszug aus der besagten Funktion an:

WM_LBUTTONDOWN:
  begin
    ahdc := GetDC(hWnd);
    xPos := LoWord(lParam);
    ypos := HiWord(lParam);
    wvsprintf(buffer, 'Fensterhandle: %d',  PChar(@hWnd));
    wvsprintf(buffer1, ', Message: %d', PChar(@uMsg));
    lstrcat(buffer, buffer1);
    wvsprintf(buffer1, ', wParam: %d', PChar(@wParam));
    lstrcat(buffer, buffer1);
    wvsprintf(buffer1, ', LoWord(lParam) x-Pos: %d', PChar(@xpos));
    lstrcat(buffer, buffer1);
    wvsprintf(buffer1, ', HiWord(lParam) y-Pos: %d', PChar(@ypos));
    lstrcat(buffer, buffer1);
    TextOut(ahdc, 20, 20, buffer, Length(buffer));
    ReleaseDC(hWnd, ahdc);
  end

Hier wird auf die Nachricht reagiert, die beim Klick der linken Maustaste im Anwendungsbereich des Fensters entsteht. Als Ergebnis sehen Sie ein paar numerische Werte, von denen offensichtlich nur "Message" immer den gleichen Wert hat. 513 in diesem Fall, was anscheinend mit der Nachricht "WM_LBUTTONDOWN" identisch ist. Testen Sie es und ersetzen Sie im o.g. Quellcode den Bezeichner der Nachricht durch den numerischen Wert "513". Das Programm funktioniert danach weiterhin, denn tatsächlich entspricht dieser numerische Wert der Nachricht "WM_LBUTTONDOWN".

Windows scheint also nur aus Zahlen zu bestehen, die allerdings zum einfacheren Programmieren in der Unit "windows.pas" als Konstanten definiert sind. Sie sollten allerdings der Versuchung widerstehen, die numerischen Werte zu verwenden. Es ist nämlich nie ausgeschlossen, dass in einer künftigen Version von Windows ganz andere Werte benutzt werden. Sie können zwar davon ausgehen, dass (um bei Delphi zu bleiben) Borland in diesem Fall eine angepasste Version der betroffenen Units veröffentlichen würde, aber das bezieht sich ja nur auf die Werte für die Konstanten. Wenn in Ihrem Programm aber der numerische Wert steht, können Ihre Units so aktuell wie nur möglich sein. Das Programm wird trotzdem nicht mehr wie gewohnt funktionieren.

Um auf das Beispiel mit der linken Maustaste zurückzukommen: Starten Sie bitte das Beispielprogramm und drücken Sie die linke Maustaste mehrmals. Halten Sie dazu bitte auch die rechte Maustaste oder STRG oder Shift gedrückt und beobachten Sie den Wert von wParam. Sie werden feststellen, dass sich dieser ändert, je nachdem, welche zusätzliche Taste Sie noch gedrückt halten.
Das erlaubt Ihnen die ganz gezielte Abarbeitung unter verschiedenen Bedingungen. Der Wert von wParam muss also nicht immer Eins sein. Wenn Sie z.B. Shift und die linke Maustaste drücken, würde das Ergebnis Fünf sein. Die Hilfe gibt Ihnen genauere Informationen, für uns soll noch eine Erweiterung interessant sein. Ändern wir den o.g. Code also einmal so ab, dass er die Informationen nur noch liefert, wenn der Anwender sowohl die linke Maustaste als auch Shift drückt:

WM_LBUTTONDOWN:
  if(MK_LBUTTON or MK_SHIFT = wParam) then
  begin
    // usw.
  end;