Windows ist ein Nachrichten - gesteuertes System. Die Behandlung von Nachrichten ist ein zentraler Bestandteil des Betriebssystems. Es gibt eine Maus (mit zugehörigem einer System-Message-Queue). Es gibt eine tastatur (mit zugehörigem einer System-Message-Queue). Zu jeder Applikation wird eine Applikation-Message-Queue eingerichtet, in die jene Nachrichten (standardisiert) gestellt werden, die zu dieser Applikation gehören. Beispiel für den Nachrichten-Fluß bei einer Tasten-Nachricht:
KEY- BOARD (Ereignis) | Keyboard-Device-Driver holt Scan-Code vom Keyboard und stellt diesen in | SYSTEM- MESSAGE- QUEUE (geräte-spezifisch) |
Windows bringt die geräte- spezifische Nachricht auf standardisierte MSG-Form (WM_...), stellt diese in |
APPLICATION- MESSAGE- QUEUE (Thread-Message-Queue) (MSG: WM_...) |
|
Dispatch Message (&msg) ruft die CALLBACK- Funktion auf, die zu msg.hWin gehört |
Die Maus- und Tastatur - Ereignisse werden der System - Message - Queue( Hardware - Buffer ) entnommen und in ein einheitliches MSG - Format gebracht. Dann werden die Nachrichten in die Application - Message - Queue( Nachrichten an unser Fenster ) gestellt. Durch GetMessage() werden die Nachrichten dem Application - Buffer entnommen. Sollen z.B. sämtliche Nachrichten an alle Anwendungen abgehorcht werden, so ist direkt hinter der System - Message - Queue ( Hardware - Buffer ) ein Hook ( z.B. CallNextHookEx ) einzubauen.
Jede Anwendung hat eine eigene Application - Message - Queue. Ist diese leer, so können in der Zwischenzeit andere Programme ausgeführt werden ( kooperatives Multitasking ).
Für die Nachrichten verwendet Windows den MSG-Typ:
typedef struct tagMSG { HWND hwnd ; UINT uMsg ; WPARAM wParam ; LPARAM lParam ; DWORD time ; POINT pt ; } MSG ; MSG msg ; |
|
Keyboard-Prinzip: |
|
Beispiel lParam bei uMsg = WM_KEYDOWN: | |
WM_KEYDOWN: lParam : |
|
|
|
|
Die msg-Nachricht enthält auch msg.message. Durch message wird die Art der Nachricht eindeutig spezifiziert.
Jede Nachricht kann in msg.wParam, msg.lParam zusätzliche Informationen hinterlegen. Die genaue Bedeutung der msg.wParam, msg.lParam - Bits hängt von msg.message ab. Für viele einfache Nachrichten reichen die Bits von wParam, lParam aus. In msg.lParam kann auch ein Zeiger auf benötigte Informationen enthalten sein.
msg.time enthält die Ereignis - Zeit.
Die Cursor - Koordinaten ( zur Ereignis-Zeit ) werden in pt übergeben.
Soll z.B. die nächste Nachricht aus der Application-Message-Queue geholt werden, so wird mit GetMessage( & msg ) diese Nachricht in die ( vorher angelegte ) Variable
MSG msg ;
gespeichert. Haupt - Nachrichten - Schleife ( nach WinMain ) ist eine ( beinahe ) Unendlich-Schleife, die nur durch die WM_QUIT - Nachricht verlassen werden kann.
MSG msg; while ( GetMessage( & msg, NULL, 0, 0 ) ) { ... DispatchMessage ( & msg ) ; }
Durch RegisterClass() wurde unsere ( Klassen - ) CALLBACK - Funktion WNDCLASS. lpfnWndProc = ( WNDPROC ) WndProc ; eingetragen. Durch DispatchMessage ( & msg ) wird die aktuelle Nachricht an diese Funktion weiter gereicht, d.h. die WndProc() wird mit den msg - Paramtern aufgerufen. Jedes Fenster hat ein eindeutiges Handle. Deshalb kann DispatchMessage ( & msg ) mit Hilfe von msg.hWnd die Nachricht über die ( globalen ) Klassen - Daten - Struktur an die CALLBACK - Funktion weiter geben. Die Haupt - Nachrichten - Schleife wird bei einer WM_QUIT - Botschaft abgebrochen. Nach dem Eintreffen von WM_DESTROY fügen wir in der Application - Message - Queue durch PostQuitMessage() die Nachricht WM_QUIT ein. Wenn GetMessage() die WM_QUIT - Nachricht entnimmt, so wird die Haupt - Nachrichten - Schleife beendet.
In windowsX.h sind die Message - Cracker - Macros enthalten. Durch diese Macros wird das Nachrichten - Carsting vermieden und die Win16/Win32 - Portabilität erhöht.
Beispiele für soche Macros sind:
#define HANDLE_MSG(hWnd, uMsg, fn) \ case (uMsg): return HANDLE_##uMsg((hWnd), (wParam), (lParam), (fn))
Ein HANDLE_MSG(hWnd, WM_CHAR, fn) - Macro - Aufruf enpandiert in ein weiteres ( in WindowsX.h enthaltenes ) HANDLE_WM_CHAR() - Macro:
/* void Cls_OnChar( HWND hWnd, TCHAR ch, int cRepeat) */ #define HANDLE_WM_CHAR( hWnd, wParam, lParam, fn) \ ((fn)(( hWnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L) #define FORWARD_WM_CHAR( hWnd, ch, cRepeat, fn) \ (void)(fn)(( hWnd), WM_CHAR, (WPARAM)(TCHAR)(ch), MAKELPARAM((cRepeat),0))
Viele HANDLE_ - Macros ( z.B. HANDLE_WM_CHAR ) zerlegen die Nachrichten typentreu in die enthaltenen Nachrichten - Parameter und rufen damit die Funktion ( hier fn ) auf. Die FORWARD_ - Macros machen diesen Vorgang rückgängig und erzeugen wieder die ursprüngliche ( hWnd, uMsg, wParam, lParam ) - Nachricht.
Mit dem HANDLE_MSG - Macro hat eine CALLBACK - Funktion etwa den folgenden Aufbau:
LRESULT CALLBACK myCallbackProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { HANDLE_MSG( hWnd, WM_CHAR, myOnChar); HANDLE_MSG( ... ); ... default: return myOrgProc( hWnd, uMsg, wParam, lParam); } }
Vielfach wird myOrgProc() der DefWindowProc() von Windows entsprechen. Die Funktion myOnChar() wird etwa wie folgt aufgebaut:
void myOnChar( HWND hWnd, UINT ch, int cRepeat) { if ( ch == testvalue ) { // handle it here } else { FORWARD_WM_CHAR( hWnd, ch, cRepeat, myOrgProc); } }
Das FORWARD_ - Macro setzt die zerlegte Nachricht wieder zur ursprünglichen ( hWnd, uMsg, wParam, lParam ) - Nachricht zusammen.
In WindowsX.h sind ( als Kommentar ) die Funktions - Parameter für myOnChar() angegeben.
/* void Cls_OnChar( HWND hWnd, TCHAR ch, int cRepeat) */
Soll für myOrgProc() nicht
DefWindowProc() sondern die orginal Klassen - CALLBACK -
Funktion lpOrgProc
aufgerufen werden, so kann myOrgProc
definiert werden durch:
LRESULT myOrgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { return CallWindowProc( lpOrgProc, hWnd, uMsg, wParam, lParam); }
CallWindowProc() ruft die Funktion lpOrgProc auf. In WindowsX.h ist
#define Sumy_classWindow( hWnd, lpfn) \ ((WNDPROC)SetWindowLong(( hWnd), GWL_WNDPROC, \ (LPARAM)(WNDPROC)MakeProcInstance((FARPROC)(lpfn),GetModuleHandle(NULL))))
enthalten. Damit kann ein Sumy_classing gemäß erfolgen durch
WNDPROC lpOrgProc = NULL; lpOrgProc = Sumy_classWindow( hWnd, myCallbackProc)); ...
Beim Übergang von WIN16 auf WIN32 hat sich das Nachrichten - Format geändert. Bei WIN16 war wParam ein WORD - Typ, bei WIN32 ist wParam ein LONG - Typ. Bei WIN32 benötigt ein Handle 32 Bits.
32 Bit 32 Bit |---------------------------------|---------------------------------| | wParam | lParam | |----------------|----------------|---------------------------------| | | | | | wmCMD | wmID | wmHWND |
16 Bit 32 Bit |----------------|---------------------------------| | wParam | lParam | |----------------|---------------------------------| | | | | | wmID | wmCMD | wmHWND |
Der Button sendet Nachrichten an das Parent - Window, wenn sich sein Zustand ändert. Der Button - Identifizierer wird mit wmID, die Notification Messages ( z.B. BN_CLICKED ) wird mit wmCMD und das Control - Handle mit wmHWND bezeichnet. Wegen der WIN16/WIN32 - Portabilität sind die windoesX.h - Macros sinnvoll:
Nachrichten - Casting | WindosX.h-Macros |
#ifdef WIN16 int wmCMD = HIWORD( lParam ) ; #else int wmCMD = HIWORD( wParam ) ; #endif int wmID = LOWORD( wParam ); HWND wmHWND= (HWND)(UINT)lParam; | int wmCMD = GET_WM_COMMAND_CMD (wParam,lParam); int wmID = GET_WM_COMMAND_ID (wParam,lParam); HWND wmHWND= GET_WM_COMMAND_HWND(wParam,lParam); |
Wenn Prozessen mit unterschiedlicher Ausführungs - Geschwindigkeit synchronisiert werden müssen, so werden Warteschlangen ( Buffer ) benötigt. Der schreibende Prozeß hinterlegt die unregelmäßig eintreffenden Ereignisse in einem Buffer. Der lesende Prozeß holt sich die Nachrichten und verarbeitet diese mit der eigenen Geschwindigkeit. Bei dem Windows - System - Tastatur - Buffer handelt es sich um einen Ring - Buffer. Bei DOS enthält der Tastatur - Buffer 32 Worte ( 64 Byte ).
#include <stdio.h> extern key_read( int*, int* ); void main( ) { int *ascii_ptr, *scan_ptr, num, num1; num = 0; num1 = 0; ascii_ptr = # scan_ptr = &num1; // initialize pointers to zero key_read( ascii_ptr, scan_ptr ); // call assembly routine // print the high byte - ASCII code, and the low byte - extended code // of the character placed in the keyboard buffer printf( "ASCII Code hex %x or decimal %d\n", *ascii_ptr," " *ascii_ptr); printf( "EXTENDED Code hex %x " "or decimal %d\n", *scan_ptr, *scan_ptr); } ****************************************************** .model small,c .data .code PUBLIC key_read key_read PROC PUSH bp ;save the base pointer MOV bp, sp ; Invoke Int 21h Function Ch to clear the keyboard buffer before ; ; accepting a keystroke. MOV ah, 0CH MOV al, 0 INT 21h ; Invoke Int 16h Function 0h to place the character code in the AX ; register. MOV ah, 0H INT 16H MOV bx, [bp+4] ;ASCII returned MOV [bx], al MOV bx, [bp+6] ;Extended code returned MOV [bx], ah POP bp RET key_read ENDP END
Der folgende Tasten - Scan - Code ist festgelegt worden:
Bei Windows kann der System - Tastatur - Buffer 60 Zeichen aufnehmen.
Im System - Nachrichten - Buffer kommt der Tasten - Scan - Code. Die Tasten - Nachricht wird aufbereitet ( einheitliches MSG - Format ) und in den Applikations - Nachrichten - Buffer gestellt.
Bei Windows hat ein Fenster den Focus. Dieses Fenster ist i.a. an der blauen Titel - Zeile erkennbar. Die Tasten - Nachrichten werden in der Haupt - Nachrichten - Schleife aus dem Applikations - Buffer geholt ( GetMessage ) und die CALLBACK - Funktion des Fensters wird mit der Tasten - Nachricht ( uMsg, wParam, lParam ) aufgerufen, d.h.
Vor dem Aufruf der Fensters - CALLBACK - Funktion werden durch das Windows - System die Parameter der Nachricht auf den Stack gelegt, d.h. die Nachricht wird über den Aufrufer - Stack an die CALLBACK - Funktion übergeben. An hWnd ist das Fenster ( genauer: der Speicher für die Fensterdaten ) erreichbar. In uMsg ist die Tasten - Nachricht eindeutig identifizierbar. Mit wParam, lParam können die Tasten unterschieden werden.
LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch ( uMsg ) { ... case WM_CHAR : { switch ( LOWORD(wParam) ) { case ‘\b’ : Rücktaste; break; case ‘\t’ : Tabulatortaste; break; case ‘\n’ : LF-Taste; break; default : //normales Zeichen bearbeiten } } ... } return DefWindowProc( hWnd, uMsg, wParam, lParam ) ; }
In dem obigen Beispiel werden nur einige WM_CHAR - Nachrichten behandelt.
Es gibt die folgenden Keyboard - Nachrichten:
|
|
Je Taste werden mehr als eine Nachricht generiert. Wird z.B. der Klein - Buchstabe a auf der Tastatur gedrückt, so wird die CALLBACK - Funktion mehrfach aufgerufen, d.h. es werden die folgenden 3 Nachrichten generiert:
Wird z.B. der Groß - Buchstabe A auf der Tastatur gedrückt, so wird die CALLBACK - Funktion mehrfach aufgerufen, d.h. es werden die folgenden 5 Nachrichten generiert:
Die (V)irtuellen (K)ey - Nachrichten ( VK_... ) können in der CALLBACK WndProc - Funktion etwa wie folgt benutzt werden.
LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch ( uMsg ) { ... case WM_KEYDOWN : { switch ( wParam ) { ... case VK_LEFT: //die Caret-nach-links-Taste ( Pfeilchen-Taste ) //wurde gedrückt, jetzt soll ... break ; case VK_F1: ... } ... } ... } ... }
Die RETURN - Tasten können unterschieden werden durch das 24. Bit von lParam.
switch ( uMsg ) { case WM_KEYDOWN : { switch ( LOWORD(wParam) ) { ... case VK_RETURN: if ( lParam & 0x01000000L ) { // Enter-Taste ( numeric keypad ) } else { // Enter-Taste ( standard keypad ) } break ; } ... } ... } ... }
Bei einer WM_KEYDOWN - Nachricht wird in LOWORD(wParam) der ( standardisierte ) Virtual - Key - Code übergeben. Die folgende Tabelle enthält die #define`s.
VK_LBUTTON | = 0x01 | VK_RBUTTON | = 0x02 | VK_CANCEL | = 0x03 | VK_MBUTTON | = 0x04 | VK_BACK | = 0x08 | VK_TAB | = 0x09 |
VK_CLEAR | = 0x0C | VK_RETURN | = 0x0D | VK_SHIFT | = 0x10 | VK_CONTROL | = 0x11 | VK_MENU | = 0x12 | VK_PAUSE | = 0x13 |
VK_CAPITAL | = 0x14 | VK_ESCAPE | = 0x1B | VK_SPACE | = 0x20 | VK_PRIOR | = 0x21 | VK_NEXT | = 0x22 | VK_END | = 0x23 |
VK_HOME | = 0x24 | VK_LEFT | = 0x25 | VK_UP | = 0x26 | VK_RIGHT | = 0x27 | VK_DOWN | = 0x28 | VK_SELECT | = 0x29 |
VK_PRINT | = 0x2A | VK_EXECUTE | = 0x2B | VK_SNAPSHOT | = 0x2C | VK_INSERT | = 0x2D | VK_DELETE | = 0x2E | VK_HELP | = 0x2F |
VK_0 ..VK_9 |
= 0x30 ...0x39 |
VK_A ..VK_Z |
= 0x41 ..0x5A |
VK_LWIN | = 0x5B | VK_RWIN | = 0x5C | VK_APPS | = 0x5D | VK_NUMPAD0 | = 0x60 |
VK_NUMPAD1 | = 0x61 | VK_NUMPAD2 | = 0x62 | VK_NUMPAD3 | = 0x63 | VK_NUMPAD4 | = 0x64 | VK_NUMPAD5 | = 0x65 | VK_NUMPAD6 | = 0x66 |
VK_NUMPAD7 | = 0x67 | VK_NUMPAD8 | = 0x68 | VK_NUMPAD9 | = 0x69 | VK_MULTIPLY | = 0x6A | VK_ADD | = 0x6B | VK_SEPARATOR | = 0x6C |
VK_SUBTRACT | = 0x6D | VK_DECIMAL | = 0x6E | VK_DIVIDE | = 0x6F | VK_F1 | = 0x70 | VK_F2 | = 0x71 | VK_F3 | = 0x72 |
VK_F4 | = 0x73 | VK_F5 | = 0x74 | VK_F6 | = 0x75 | VK_F7 | = 0x76 | VK_F8 | = 0x77 | VK_F9 | = 0x78 |
VK_F10 | = 0x79 | VK_F11 | = 0x7A | VK_F12 | = 0x7B | VK_F13 | = 0x7C | VK_F14 | = 0x7D | VK_F15 | = 0x7E |
VK_F16 | = 0x7F | VK_F17 | = 0x80 | VK_F18 | = 0x81 | VK_F19 | = 0x82 | VK_F20 | = 0x83 | VK_F21 | = 0x84 |
VK_F22 | = 0x85 | VK_F23 | = 0x86 | VK_F24 | = 0x87 | VK_NUMLOCK | = 0x90 | VK_SCROLL | = 0x91 | VK_LSHIFT | = 0xA0 |
VK_RSHIFT | = 0xA1 | VK_LCONTROL | = 0xA2 | VK_RCONTROL | = 0xA3 | VK_LMENU | = 0xA4 | VK_RMENU | = 0xA5 | VK_PROCESSKEY WINVER<=0x0400 |
= 0xE5 |
VK_ATTN | = 0xF6 | VK_CRSEL | = 0xF7 | VK_EXSEL | = 0xF8 | VK_EREOF | = 0xF9 | VK_PLAY | = 0xFA | VK_ZOOM | = 0xFB |
VK_NONAME | = 0xFC | VK_PA1 | = 0xFD | VK_OEM_CLEAR | = 0xFE |
Z.B. wird durch die Alt - Taste die wParam = VK_MENU - Nachricht generiert.
VK_L... bzw. VK_R... gehören zu der linken bzw. rechten Alt - , Ctrl - und Shift - Tasten und werden nur als Parameter bei den GetAsyncKeyState(), GetKeyState() - Funktionen benutzt.
Der aktuelle Zustand aller Tasten wird in einem Buffer protokolliert. Auch die Applikation kann diese Einträge lesen/schreiben, wobei zwischen synchron/asynchron unterschieden wird. Wird eine neue Tasten - Nachricht in den Applikations - Nachrichten - Warteschlange ( Applikations - Buffer ) eingetragen, so ändert sich der asynchron Keyboard - Zustand. Der synchron Keyboard - Zustand entspricht dem momentanen Zustand der Tastatur.
if ( GetKeyState ( VK_SHIFT ) & 0x80000000L ) { // SHIFT - Taste gedrückt }
GetKeyState() ( imGegensatz zu GetAsyncKeyState ) liefert den Zustand ohne Verzögerung zurück. Durch GetKeyState ( VK_LBUTTON ) wird z.B. der aktuelle Zustand der linken Maustaste abgefragt.
Dauert z.B. eine Berechnung zu lange und soll diese Berechnung durch
abgebrochen werden, so kann dies mit der ( asynchronen ) GetAsyncKeyState() - Funktion
if ( ( GetAsyncKeyState ( VK_LBUTTON ) < 0 ) // linke Maus - Taste down || ( GetAsyncKeyState ( VK_ESCAPE ) < 0 ) // Escape Taste ) { // ... z.B. exit ( -1 ); oder // ... SendMessage ( hWnd, WM_CLOSE, 0, 0 ) }
erfolgen. Um den Zustand von mehreren Tasten zu untersuchen, wie z.B. die
können alle 256 Virtual Keys in einen Buffer buf kopiert werden. Die Funktionen GetKeyboardState(), SetKeyboardState(), GetAsyncKeyState(), GetKeyState(), MapVirtualKey() werden benutzt. Es kann dann z.B. zwischen linken und rechten SHIFT - Tasten unterschieden werden. Die GetKeyboardState( buf ) - Funktion kopiert alle 256 Virtual Keys in einen Buffer buf. Eine Taste ist gerade gedrückt, wenn das 7. Bit gesetzt ist ( sonst 0 ). Der Gedrückt/Losgelassen - Zustand hat gewechselt, wenn das 0. Bit gleich 1 ist ( tggled ). Normalerweise ist eine Taste nicht gedrückt, dann ist das 0. Bit gleich 1.
BYTE buf[256]; GetKeyboardState( buf ); // hole VK_ - Keys buf[VK_CONTROL] |= 0x80; // setze "gedrückt" bei VK_CONTROL - Taste SetKeyboardState( buf ); // schreibe VK_ - Keys zurück
BYTE buf[256]; GetKeyboardState( buf ); if ( buf[VK_CAPITAL] & 1 ) buf[VK_CAPITAL] &= 0xFE; else buf[VK_CAPITAL] |= 0x01; SetKeyboardState( buf );
VK_L... bzw. VK_R... gehören zu der linken bzw. rechten Alt - , Ctrl - und Shift - Tasten und werden nur als Parameter bei den GetAsyncKeyState(), GetKeyState() - Funktionen benutzt.
case WM_RBUTTONDOWN: {
BYTE buf[256];
GetKeyboardState( buf ); // hole VK_ - Keys
buf[VK_RBUTTON] = 0x00; // setze "losgelassen" bei VK_RBUTTON - Maus - Taste
SetKeyboardState( buf ); // schreibe VK_ - Keys zurück
... create - pop - up - Menu ...
... call TrackPopUp ...
break; }
TranslateMessage() benutzt die Funktion ToAsciiEx() um den virtuellen Key - Code ( z.B. für die WM_KEYDOWN - Nachricht ) zu erzeugen. Eine Nachricht enthält in LOWORD( lParam ) die Anzahl von automatischen Tasten - Wiederholungen. Durch diesen Anschlag - Wiederholungs - Zähler werden Überflutungen von Nachrichten vermieden.
In HIWORD( lParam ) sind interessante Tasten - Flags, die im folgenden erklärt werden. Eine Nachricht enthält in HIWORD( lParam ) interessante Tasten - Flags, die im folgenden erklärt werden.
Bit | HIWORD( lParam ) - Bit | Bit | HIWORD( lParam ) - Bit | Bit | HIWORD( lParam ) - Bit | Bit | HIWORD( lParam ) - Bit |
15 | 1 if the key is up; 0 if the key is down. |
14 | 1 if the key was previously up; 0 if the key was previously down. |
13 | 1 if the ALT key is down. | 12 | 1 if Windows displays a menu. |
11 | 1 if Windows displays a dialog box. | 10 | Not used. | 9 | Not used. | 8 | 1 if the key is extended; 0 if it is not. |
7 | generally 0. | 6..0 | hardware-scan code ( used mainly in the translation of ALT+number-pad character code input ) |
Die Maus - Nachrichten werden in der Haupt - Nachrichten - Schleife aus dem Applikations - Buffer geholt ( GetMessage ) und die CALLBACK - Funktion des Fensters wird mit der Maus - Nachricht ( uMsg, wParam, lParam ) aufgerufen, d.h.
Vor dem Aufruf der Fensters - CALLBACK - Funktion werden durch das Windows - System die Parameter der Nachricht auf den Stack gelegt, d.h. die Nachricht wird über den Aufrufer - Stack an die CALLBACK - Funktion übergeben. An hWnd ist das Fenster ( genauer: der Speicher für die Fensterdaten ) erreichbar. In uMsg ist die Maus - Nachricht eindeutig identifizierbar. Typische uMsg sind: WM_LBUTTONDOWN, WM_RBOTTOMDOWN, WM_MOUSEMOVE, WM_NCLBUTTONDBLCLICK.
Die Behandlung von Maus - Ereignisses geschieht vielfach in der CALLBACK - Funktion. In lParam wird die aktuelle Maus - Position an die CALLBACK - Funktion übergeben.
LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { static int xPos,yPos; switch ( uMsg ) { ... case WM_LBUTTONDOWN : xPos = (int) LOWORD(lparam); // 16 BIT yPos = (int) HIWORD(lparam); // pt = MAKEPOINT(lparam); // 32 BIT, pt vom Typ Point break; ... } ... return DefWindowProc( hWnd, uMsg, wParam, lParam ) ; }
Für einen Doppel - Klick muß nach WM_LBUTTONDOWN ein Zähler gestartet werden. Deshalb ist für einen Doppelklick ein Eintrag
WNDCLASSEX wc={ 0 }; wc.cbSize=sizeof(WNDCLASSEX); ... wc.style = ... | CS_DBLCLKS; // Zeitgeber ½ sec. RegisterClass( & wc );erforderlich.
Ein Fenster besteht aus dem Fenster - Inneren ( Client - Bereich ) und dem Nicht Client - Bereich ( NC ). Auch der Fenster - Rand gehört zu NC. Maus-Nachricht
Nachricht | wParam, lParam enthalten ... |
WM_CAPTURECHANGED | hwndNewCapture = (HWND) lParam; // handle of window to gain mouse capture |
WM_MOUSEMOVE WM_LBUTTONDOWN WM_LBUTTONUP WM_RBUTTONDOWN WM_RBUTTONUP WM_MBUTTONDOWN WM_MBUTTONUP WM_LBUTTONDBLCLK WM_MBUTTONDBLCLK WM_RBUTTONDBLCLK |
fwKeys = wParam; // key flags xPos = LOWORD(lParam); // horizontal position of cursor yPos = HIWORD(lParam); // vertical position of cursor fwKeys: MK_CONTROL Set if the CTRL key is down. MK_LBUTTON Set if the left mouse button is down. MK_MBUTTON Set if the middle mouse button is down. MK_RBUTTON Set if the right mouse button is down. MK_SHIFT Set if the SHIFT key is down. |
WM_MOUSEACTIVATE | hwndTopLevel = (HWND) wParam; // handle of
top-level parent nHittest = (INT) LOWORD(lParam); // hit-test value uMsg = (UINT) HIWORD(lParam); // mouse message nHittest is the return value of DefWindowProc: MA_ACTIVATE Activates the window, and does not discard the mouse message. MA_ACTIVATEANDEAT Activates the window, and discards the mouse message. MA_NOACTIVATE Does not activate the window, and does not discard the mouse message. MA_NOACTIVATEANDEAT Does not activate the window, but discards the mouse message |
WM_MOUSEWHEEL | fwKeys = LOWORD(wParam); // key flags zDelta = (short) HIWORD(wParam); // wheel rotation xPos = (short) LOWORD(lParam); // horizontal position of pointer yPos = (short) HIWORD(lParam); // vertical position of pointer fwKeys: MK_CONTROL Set if the CTRL key is down. MK_LBUTTON Set if the left mouse button is down. MK_MBUTTON Set if the middle mouse button is down. MK_RBUTTON Set if the right mouse button is down. MK_SHIFT Set if the SHIFT key is down. |
WM_NCHITTEST | xPos = LOWORD(lParam); // horizontal screen
position of cursor yPos = HIWORD(lParam); // vertical screen position of cursor Value Location of hot spot is the return value of DefWindowProc: HTBORDER In the border of a window that does not have a sizing border HTBOTTOM In the lower horizontal border of a window HTBOTTOMLEFT In the lower-left corner of a window border HTBOTTOMRIGHT In the lower-right corner of a window border HTCAPTION In a title bar HTCLIENT In a client area HTCLOSE In a close button HTERROR On the screen background or on a dividing line between windows (same as HTNOWHERE, except that the DefWindowProc function produces a system beep to indicate an error) HTGROWBOX In a size box (same as HTSIZE) HTHELP In a Help button HTHSCROLL In a horizontal scroll bar HTLEFT In the left border of a window HTMENU In a menu HTMAXBUTTON In Maximize button HTMINBUTTON In Minimize button HTNOWHERE On the screen background or on a dividing line between windows HTREDUCE In a Minimize button HTRIGHT In the right border of a window HTSIZE In a size box (same as HTGROWBOX) HTSYSMENU In a System menu or in a Close button in a child window HTTOP In the upper horizontal border of a window HTTOPLEFT In the upper-left corner of a window border HTTOPRIGHT In the upper right corner of a window border HTTRANSPARENT In a window currently covered by another window HTVSCROLL In the vertical scroll bar HTZOOM In a Maximize button |
WM_NCLBUTTONDBLCLK WM_NCLBUTTONDBLCLK WM_NCLBUTTONDOWN WM_NCLBUTTONUP WM_NCMBUTTONDBLCLK WM_NCMBUTTONDOWN WM_NCMBUTTONUP WM_NCMOUSEMOVE WM_NCRBUTTONDBLCLK WM_NCRBUTTONDOWN WM_NCRBUTTONUP | nHittest = (INT) wParam; // hit-test value pts = MAKEPOINTS(lParam); // position of cursor nHittest see WM_NCHITTEST |
Das Maus - Rad ( WM_MOUSEWHEEL ) kann z.B. zur Steuerung von Scroll - Bars eingesetzt werden.
Um die Folge von Nachrichten zu untersuchen, soll die folgende Funktion schreibe_nachrichten(UINT uMsg,WPARAM wParam,LPARAM lParam) die Folge der Nachrichten anzeigen. Der Header-File enthält die #define's für die Nachrichten, die in einen Array der Art { "WM_DESTROY", WM_DESTROY}// 0x0002 hinterlegt werden. Steht der Aufruf schreibe_nachrichten(uMsg,wParam,lParam) in einer CALLBACK-Funktion, so durchläuft for(int i = 0;i < n; i++) {...} alle Array-Einträgt und gibt den gefundenen aus.
Das stdout_to()-Macro ermöglicht (mit Hilfe der freopen()-Funktion), die Standard-Ausgabe der printf's (einer Console-Applikation) in den aktuellen Quelltext-File (__FILE__) umzuleiten. Die Benutzung von stdout_to erfolgt etwa gemäss:
stdout_to(__FILE__); printf("\n // ..."); printf("\n // ..."); stdout_to("CON");
Die folgende Funktion schreibe_nachrichten(UINT uMsg,WPARAM wParam,LPARAM lParam) wird in der CALLBACK-Funktion aufgerufen. In schreibe_nachrichten() wird beijeder ankommenden Nachricht die Nachrichten-Tabelle msgdesc[] durchlaufen und bei Übereinstimmung wird der Name der aktuellen uMsg-Nachricht (und auch wParam,lParam) ausgegeben.
void schreibe_nachrichten(UINT uMsg,WPARAM wParam,LPARAM lParam) { #undef stdout_to #define stdout_to(f) if((freopen(f,"at", stdout))==NULL)\ {fprintf(stderr,"\nredir-err\n");exit(-1);} typedef struct { LPTSTR psz; UINT uMsg;} MSGDESC; static MSGDESC msgdesc[] = { { "WM_NULL", WM_NULL}, // 0x0000 { "WM_CREATE", WM_CREATE}, // 0x0001 { "WM_DESTROY", WM_DESTROY}, // 0x0002 { "WM_MOVE", WM_MOVE}, // 0x0003 { "WM_SIZE", WM_SIZE}, // 0x0005 { "WM_ACTIVATE", WM_ACTIVATE}, // 0x0006 { "WM_SETFOCUS", WM_SETFOCUS}, // 0x0007 ... }; static UINT j; if(j == 0) stdout_to(__FILE__); UINT len = sizeof(msgdesc)/sizeof(msgdesc[0]); for(int i = 0; i < len; i++) { if(uMsg == msgdesc[i].uMsg) { printf("\n// %03u %04x %s", j++, i, msgdesc[i].psz); if(uMsg == WM_COMMAND) printf(" wPar=0x%08x lPar=0x%08x",wParam,lParam); } } }
Es gibt Werkzeuge, die eine fortgeschrittene Verfolgung der Nachrichten erlauben (z.B. spy++).