Schreiben der Fensterprozedur
Die Funktion DispatchMessage ruft die Fensterprozedur des Fensters auf, das das Ziel der Nachricht ist. Die Fensterprozedur weist die folgende Signatur auf.
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
Es gibt vier Parameter:
- hwnd ist ein Handle für das Fenster.
- uMsg ist der Nachrichtencode; Beispielsweise gibt die Nachricht WM_SIZE an, dass die Größe des Fensters geändert wurde.
- wParam und lParam enthalten zusätzliche Daten, die sich auf die Nachricht beziehen. Die genaue Bedeutung hängt vom Kontext ab.
LRESULT ist ein ganzzahliger Wert, den das Programm an Windows zurückgibt. Er enthält die Antwort Ihres Programms auf eine bestimmte Nachricht. Die Bedeutung dieses Werts hängt vom Nachrichtencode ab. CALLBACK ist die Aufrufkonvention für die Funktion.
Eine typische Fensterprozedur ist einfach eine große switch-Anweisung, die den Nachrichtencode einschaltet. Fügen Sie Fälle für jede Nachricht hinzu, die Sie behandeln möchten.
switch (uMsg)
{
case WM_SIZE: // Handle window resizing
// etc
}
Zusätzliche Daten für die Nachricht sind in den Parametern lParam und wParam enthalten. Bei beiden Parametern handelt es sich um ganzzahlige Werte mit der Größe einer Zeigerbreite (32 Bits oder 64 Bit). Die Bedeutung der einzelnen hängt vom Nachrichtencode (uMsg) ab. Für jede Nachricht müssen Sie den Nachrichtencode suchen und die Parameter in den richtigen Datentyp umwandeln. In der Regel handelt es sich bei den Daten entweder um einen numerischen Wert oder um einen Zeiger auf eine Struktur. Einige Nachrichten enthalten keine Daten.
In der Dokumentation für die Meldung WM_SIZE wird beispielsweise Folgendes angegeben:
- wParam ist ein Flag, das angibt, ob das Fenster minimiert, maximiert oder die Größe geändert wurde.
- lParam enthält die neue Breite und Höhe des Fensters als 16-Bit-Werte, die in eine 32- oder 64-Bit-Zahl gepackt sind. Sie müssen einige Bitverschiebungen durchführen, um diese Werte zu erhalten. Glücklicherweise enthält die Headerdatei WinDef.h Hilfsmakros, die dies tun.
Eine typische Fensterprozedur verarbeitet Dutzende von Nachrichten, sodass sie ziemlich lang werden kann. Eine Möglichkeit, Ihren Code modularer zu gestalten, besteht darin, die Logik für die Verarbeitung jeder Nachricht in einer separaten Funktion zu platzieren. Wandeln Sie in der Fensterprozedur die Parameter wParam und lParam in den richtigen Datentyp um, und übergeben Sie diese Werte an die Funktion. Um beispielsweise die Meldung WM_SIZE zu behandeln, würde die Fensterprozedur wie folgt aussehen:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_SIZE:
{
int width = LOWORD(lParam); // Macro to get the low-order word.
int height = HIWORD(lParam); // Macro to get the high-order word.
// Respond to the message:
OnSize(hwnd, (UINT)wParam, width, height);
}
break;
}
}
void OnSize(HWND hwnd, UINT flag, int width, int height)
{
// Handle resizing
}
Die Makros LOWORD und HIWORD erhalten die 16-Bit-Werte für Breite und Höhe von lParam. Die Fensterprozedur extrahiert die Breite und Höhe und übergibt diese Werte dann an die OnSize
-Funktion.
Standardnachrichtenbehandlung
Wenn Sie eine bestimmte Nachricht in Ihrer Fensterprozedur nicht verarbeiten, übergeben Sie die Nachrichtenparameter direkt an die Funktion DefWindowProc. Diese Funktion führt die Standardaktion für die Nachricht aus, die je nach Nachrichtentyp variiert.
return DefWindowProc(hwnd, uMsg, wParam, lParam);
Vermeiden von Engpässen in Ihrer Fensterprozedur
Während die Fensterprozedur ausgeführt wird, blockiert sie alle anderen Nachrichten für Fenster, die im selben Thread erstellt wurden. Vermeiden Sie daher eine lange Verarbeitung innerhalb Ihrer Fensterprozedur. Angenommen, Ihr Programm öffnet eine TCP-Verbindung und wartet unbegrenzt, bis der Server antwortet. Wenn Sie dies innerhalb der Fensterprozedur tun, antwortet Ihre Benutzeroberfläche erst, wenn die Anforderung abgeschlossen ist. Während dieser Zeit kann das Fenster Keine Maus- oder Tastatureingaben verarbeiten, sich selbst neu auffüllen oder sogar schließen.
Stattdessen sollten Sie die Arbeit in einen anderen Thread verschieben, indem Sie eine der in Windows integrierten Multitaskingfunktionen verwenden:
- Erstellen Sie einen neuen Thread.
- Verwenden von Threadpools.
- Verwenden Sie asynchrone E/A-Aufrufe.
- Verwenden Sie asynchrone Prozeduraufrufe.