Nachrichtenempfang per Fensterfunktion

Ein Programm unter MS-Windows oder Presentation Manager wertet seine Nachrichten im Gegensatz zu GEM nicht direkt aus. Es empfängt zwar in der Hauptfunktion alle Nachrichten. Dies dient aber im Normalfall nur dazu, die WM_QUIT-Nachricht herauszufinden, die ihm mitteilt, daß das Programm beendet werden soll. Diese Nachricht wird vom eigenen Programm an sich selbst versandt, wenn zum Beispiel der entsprechende Menüpunkt vom Benutzer angewählt wurde. Die restlichen Nachrichten werden quasi dem System zurückgegeben. Dieses wird sie nach Fenstern aufgliedern und entsprechend angemeldete Funktionen, die sogenannten Fensterfunktionen, aufrufen.

Die typische Hauptfunktion einer PM-Anwendung enthält die folgenden Funktionsaufrufe:


#define FENSTERKLASSE "FensterKlasse"

HAB ApplikationsHandle;

INT main(VOID)
{
HMQ NachrichtenSchlage;
QMSG Nachricht;

   /* Anmelden der Applikation */
   ApplikationsHandle = WinInitialize( (ULONG) 0);
   /* Erzeugung der Messagepipe */
   NachrichtenSchlange = WinCreateMsgQueue(ApplikationsHandle, 0L);

   /* Anmelden der Fensterfunktion beim System */
   WinRegisterClass (ApplikationsHandle,
            FENSTERKLASSE,
            (PFNWP) FensterFunktion,
            CS_SIZEREDRAW, 0);

   /* Hier erfolgt die Anmeldung des Hauptfensters ... */

   /* Empfangen einer Nachricht */
   while ( WinGetMsg(ApplikationsHandle, &Nachricht, 0L, 0, 0) ) {
      /* Versenden der Nachricht */
      WinDispatchMsg(ApplikationsHandle, &Nachricht);
   }

   /* Hier muss das Hauptfenster wieder abgemeldet werden ... */

   /* Abmelden der Messagepipe */
   WinDestroyMsgQueue(NachrichtenSchlage);
   /* Abmelden der Applikation */
   WinTerminate(ApplikationsHandle);
}

Zunächst ermittelt das Programm mit Hilfe der Funktion WinInitialize das Applikationshandle. Mit diesem erzeugt es eine Warteschlange für die Nachrichten. Als nächstes wird die Fensterfunktion des Applikationsfensters dem Betriebssystem durch das Registrieren der Fensterklasse angemeldet. Die Nachrichten aller Fenster, die später mit der gleichen Fensterklasse angelegt werden, werden an die gleiche Fensterfunktion versandt. Die normalerweise anschließende Erzeugung des Hauptfensters ist hier ausgelassen. Wichtig ist an dieser Stelle, daß die dem System genannte Fensterfunktion die Ereignisse fängt und die eigentlichen Applikationsfunktionen aufruft.

Anschließend läuft das PM-Programm in eine Schleife, die durch das Eintreffen der Nachricht WM_QUIT beendet wird. In dieser Schleife wird jede Nachricht empfangen, die über die Warteschlange der Applikation läuft. Die Funktion WinDispatchMsg gibt die Nachricht quasi dem System zurück, damit dieses die dem betroffenen Fenster zugeordnete Fensterfunktion aufruft.

MRESULT  EXPENTRY  FensterFunktion (
      HWND  FensterHandle,
      ULONG Nachricht,
      MPARAM ErsterNachrichtenParameter,
      MPARAM ZweiterNachrichtenParameter)
{
   switch (Nachricht) {
      case WM_CREATE:
         break;
      case WM_COMMAND:
         break;
      case WM_CONTROL:
         break;
      case WM_PAINT:
         break;
      case WM_SIZE:
            break;
      case WM_CLOSE:
         WinPostMsg(FensterHandle, WM_QUIT , 0, 0);
         break;
   default:
   }
   return WinDefWindowProc (FensterHandle, Nachricht,
            ErsterNachrichtenParameter,
            ZweiterNachrichtenParameter);
}

Die Fensterfunktion besteht also in erster Linie aus einer Fallunterscheidung über den Nachrichtentyp. Hier werden alle vom Programmierer vorgesehen Fälle weiter bearbeitet. Dabei betreffen die Nachrichten WM_COMMAND und WM_CONTROL die applikationsrelevanten Ereignisse wie die Benutzung der Kontrollelemente und Tastendrücke. Aus den Nachrichtenparametern kann das Programm entnehmen, welche Elemente bedient worden sind. Die Nachricht WM_CLOSE wird bei Schließen des Fensters empfangen. Im obigen Beispiel sendet die Fensterfunktion die Nachricht WM_QUIT, die die eigene Ereignisschleife unterbricht und damit das Programm beendet. Eine solche Reaktion zeigt üblicherweise lediglich die Fensterfunktion des Applikationsfensters. Bei anderen Fenstern würden an dieser Stelle eher Funktionen aufgerufen, die sich um das Abspeichern der im Fenster angezeigten Inhalte kümmert. Das System stellt eine Standardfensterfunktion WinDefWindowProc zur Verfügung. Diese ist bereits mit Funktionen ausgestattet, die auf die grundlegenden Ereignisse reagieren. Richtet man ein Fenster ein und gibt WinDefWindowProc als Fensterfunktion an, kann man das Fenster bereits vergrÖßern und bewegen, der Hintergrund wird in der Hintergrundfarbe gesetzt und man kann es schließen. Allerdings laufen alle diese Aktionen am Programm vorbei. Die Fallunterscheidung der eigenen Fensterfunktion filtert also alle Nachrichten aus, die für die Applikation von Interesse sind oder wo das Fenster anders reagieren soll als im Standardfall. Die Standardfensterfunktion wird zum Abschluß der eigenen Fensterfunktion aufgerufen. Dadurch werden alle die Fälle abgedeckt, die der Applikationsprogrammierer nicht bearbeitet. Auch Restaktionen werden dadurch abgefangen. So sollte nach dem Empfang eines Menüereignisses die Standardfensterfunktion aufgerufen werden, da diese das Zurückklappen des Menüs durchführt.

Im Gegensatz zum GEM-Programm zerfällt das Programm in zwei oder mehr Teile, je nachdem, wieviele Fensterfunktionen erforderlich sind. In der Abbildung sieht man, wie in der Initalisierungsphase die Fensterfunktion dem System bekannt gemacht wird. Die Ereignisse werden zwar in der Messageschleife empfangen, führen dort aber nicht zu einer Verarbeitung. Statt dessen werden sie dem System zurückgesandt, das die zugehÖrige Fensterfunktion aufruft. Im Parameter übergibt das System alle Informationen über das Ereignis, so daß die Fensterfunktion die eigentlichen Applikationsfunktionen aufrufen kann, nachdem sie eine Unterscheidung über die Art des Ereignisses durchgeführt hat. Die Abmeldung erfolgt dann wieder über das Hauptprogramm, sobald es die Nachricht zum Verlassen des Programms gesehen hat.

Den C-Programmierer werden die durchweg in Großbuchstaben geschriebenen Typen im Listing verwundern. Dies deutet bereits darauf hin, daß sie durch den Präprozessor definiert sind. Der Grund dieses Vorgehens hat etwas mit der Architektur des PCs zu tun. Er besitzt mehrere Speichermodelle, deren Zeiger entsprechend unterschiedlich groß sind. Wird unter MS-Windows eine Systemfunktion aufgerufen, deren Parameter ein Zeiger ist, muß dieser über den gesamten Speicherbereich reichen, da die Systemfunktion und die Applikation an den entgegengesetzten Orten des Speichers liegen kÖnnen. Durch die Definition der Typen in den Headerdateien wird zudem erreicht, daß trotz Typenänderungen in der Schnittstelle eine Quellcode-Kompatibilität aufrecht erhalten werden kann.


Inhaltsverzeichnis (C) Copyright 1993-1999 Arnold Willemer