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.
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:
-
TranslateMessage:
Diese Prozedur übersetzt die Windows-Nachrichten. Aus
WM_KEYDOWN- und WM_KEYUP-Nachrichten
werden WM_CHAR- oder
WM_DEADCHAR-Nachrichten. WM_SYSKEYDOWN-
und WM_SYSKEYUP-Nachrichten verwandeln sich zu
WM_SYSCHAR- oder
WM_SYSDEADCHAR-Nachrichten.
-
DispatchMessage:
Diese Prozedur leitet eine Nachricht zum ausführenden Thread weiter.
-
PeekMessage:
Obige Funktion schaut nach, ob sich eine Nachricht in der Nachrichtenwarteschlange
befindet. Wenn ja, wird diese Nachricht in lpMsg gespeichert.
Sollte keine Nachricht vorhanden sein, wird 0 zurückgegeben. Wird der Funktion als
hwnd "0" übergeben, wird jede Nachricht jedes Formulars des
ausführenden Threads behandelt.
-
PostQuitMessage:
Normalerweise wird diese Funktion ausgeführt, wenn das Programm die Nachricht
"WM_DESTROY" in der Warteschlange hat. Es wird die Nachricht
"WM_QUIT" in die Warteschlange gesetzt. Durch diese wird
das Programm beendet.
-
Type msg:
"hwnd" ist das Handle des ausführenden Fensters. In
"Message" befindet sich die Nachricht, besser gesagt ihre
Kennzahl. "wParam" und "lParam"
werden nicht immer gefüllt. Hier werden die weiteren Parameter, wie z.B.
Mauskoordinaten usw. gespeichert. "Time" beinhaltet die
genaue Zeit, in der die Nachricht gesendet wurde. "Pt"
bezeichnet die Cursorposition zur Zeit des Sendens der Nachricht.
-
PM_REMOVE:
Bei der "PeekMessage"-Funktion das letzte Argument. Es
bedeutet, dass die gefundene Nachricht gelöscht wird. Das Gegenstück dazu wäre
"PM_NOREMOVE" (&H0).
-
WM_QUIT:
Dies ist die Nachricht, die mittels "PostQuitMessage" in
der Warteschleife gespeichert wird, wenn das Programm beendet werden soll.
-
POINTAPI:
Dieser benutzerdefinierter Datentyp beinhaltet die Koordinaten der Maus während
die Nachricht gesendet wurde. Sie kennen diesen oft gebrauchten Datentyp sicher
von Tipps wie "Mauszeiger bewegen" oder
"Cursorposition
ermitteln".

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 |