Post von Windows - Windows-Nachrichten empfangen ohne Umwege


 Zum vorherigen AbschnittZum nächsten Abschnitt Windows und Post?
Hinweis: Ich empfehle Ihnen, zuvor das Subclassing-Tutorial zu lesen, falls Sie dies nicht bereits getan haben. Dann können Sie den folgenden Textabschnitt auch überspringen und müssen sich nicht mehr erklären lassen, wann und warum Windows interne Nachrichten an seine Programme versendet.

Damit eine Interaktion mit dem Benutzer und einem Programm möglich ist, versendet Windows einzelne "Nachrichten" an alle laufenden Programme, mit Hilfe derer es sich mit den einzelnen Anwendungen verständigt. Diese Nachrichten werden immer verschickt, wenn ein Ereignis innerhalb des Programms eintritt, also beispielsweise eine Mausbewegung, ein Mausklick oder auch ein Redraw-Befehl der Windows-Oberfläche.


 Zum vorherigen AbschnittZum nächsten Abschnitt Ohne API geht's nicht
Bei Visual Basic, einer ereignisorientierten Sprache, werden diese Nachrichten im Hintergrund automatisch ausgewertet und die entsprechenden Ereignisse ausgelöst. Als VB-Programmierer muss man sich also nicht um die Windows-Post kümmern, Visual Basic erledigt diese Aufgabe für Sie.

Es gibt jedoch Fälle, in denen eine selbstgebaute Nachrichtenbehandlung besser und vor allem schneller von statten geht. Hier wird mit Hilfe einer API-Funktion nachgeschaut, ob es eine Nachricht zu bearbeiten gibt. Sollte dies nicht der Fall sein, wird z.B. das nächste Bild gezeichnet. Jedoch wird dadurch der Standard-Nachrichtenmechanismus ausgeschaltet. Das heißt, dass das Programm nicht mehr "normal" beendet werden kann. Um es zu beenden, muss auf eine weitere API-Funktion zugegriffen werden.

Der Message-Handler muss in die "Sub Main()"-Prozedur eingebaut werden. Hierbei ist zu beachten, dass die Anwendung ihre Ausführung bei "Sub Main()" beginnt (konfigurierbar in den Projekt-Eigenschaften).
Es folgen alle API-Funktionen, Typdeklarationen und Konstanten, die benötigt werden:

Public Declare Function PeekMessage Lib "user32" Alias "PeekMessageA" (lpMsg As msg, ByVal hwnd As Long, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long

Public Declare Function DispatchMessage Lib "user32" Alias "DispatchMessageA" (lpMsg As msg) As Long

Public Declare Function TranslateMessage Lib "user32" (lpMsg As msg) As Long

Public Declare Sub PostQuitMessage Lib "user32" (ByVal nExitCode As Long)

Public Type msg
   hwnd As Long
   message As Long
   wParam As Long
   lParam As Long
   time As Long
   pt As POINTAPI
End Type

Public Type POINTAPI
   X As Long
   Y As Long
End Type

Public Const PM_REMOVE = &H1
Public Const WM_QUIT = &H12

Zur Erklärung:

 Zum vorherigen AbschnittZum nächsten Abschnitt Automatisch vs. manuell - Wer ist schneller?
Jetzt sollte Ihnen alles nötige bekannt sein. Erstellen wir nun also zuerst den Pseudocode einer "Nachrichtenverarbeitungsschleife":

Sub Main()
   Do
      'Gibt es eine Nachricht in der Warteschlange?
      'Ja:
      '   Ist es WM_QUIT?
      '   Ja:
      '      Programmende (Exit Do)
      '   Nein:
      '      Soll die Nachricht an das Programm gesendet werden?
      '      Ja:
      '         TranslateMessage aufrufen
      '         DispatchMessage aufrufen
      '      Nein:
      '         andere Auswertung (optional)
      'Nein:
      '   Keine Nachricht in der Warteschlange. Programm steckt solange in der Schleife.
   Loop 'Endlosschleife
   
   'Programm beenden
End Sub

TranslateMessage und DispatchMessage werden dazu benötigt, um die "normalen" Event-Handler beim Ereignis ausführen zu können. Soll das Programm nach einem Tastendruck beendet werden wird so die Form_KeyPress-Prozedur ausgeführt. In diese Prozedur wird die PostQuitMessage-Prozedur eingebaut. Jetzt kann man das Programm bei Tastendruck beenden. Hier ein Beispielprogramm:

Sub Main()
   Dim tMsg As msg
   
   Load Form1 'Optional; Nur wenn ein Formular angezeigt werden soll.
   Form1.Show 'Optional
   
   Do
      If PeekMessage(tMsg, 0, 0, 0, PM_REMOVE) Then
         If tMsg.message = WM_QUIT Then Exit Do
         
         'Hier werden alle Nachrichten weitergeleitet.
         TranslateMessage tMsg
         DispatchMessage tMsg
      Else
         'andere Auswertung
      End If
   Loop
   
   Unload Form1 'Nur wenn Form1 zuvor geladen wurde
End Sub

Viele Spiele verwenden diese Technik, um eine bessere Framerate zu erzielen. Dies geschieht einfach, indem ein neues Bild gezeichnet wird, wenn es keine Nachricht zu verarbeiten gibt. Dadurch wird das Bild sehr viel öfter gezeichnet und die Framerate erhöht sich.


Quellen: VB-Empire.de.vu, SHADOWare.de
Letzte Änderung: 18.07.2001
©2001 by SHADOWare, Thomas Bachem