|VC++ 6.0 ebook chapter index|
The 10 mouse messages discussed so far occur when the mouse is moved or clicked within the client area of a window. If the mouse is outside a window's client area but within the window, Windows sends the window procedure a "nonclient-area" mouse message. The nonclient area of a window includes the title bar, the menu, and the window scroll bars.
You do not usually need to process nonclient-area mouse messages. Instead, you simply pass them on to DefWindowProc so that Windows can perform system functions. In this respect, the nonclient-area mouse messages are similar to the system keyboard messages WM_SYSKEYDOWN, WM_SYSKEYUP, and WM_SYSCHAR.
The nonclient-area mouse messages parallel almost exactly the client-area mouse messages. The message identifiers include the letters "NC" to indicate "nonclient." If the mouse is moved within a nonclient area of a window, the window procedure receives the message WM_NCMOUSEMOVE. The mouse buttons generate these messages:
|Button||Pressed||Released||Pressed (Second Click)|
The wParam and lParam parameters for nonclient-area mouse messages are somewhat different from those for client-area mouse messages. The wParam parameter indicates the nonclient area where the mouse was moved or clicked. It is set to one of the identifiers beginning with HT (standing for "hit-test") that are defined in the WINUSER.H.
The lParam parameter contains an x-coordinate in the low word and a y-coordinate in the high word. However, these are screen coordinates, not client-area coordinates as they are for client-area mouse messages. For screen coordinates, the upper-left corner of the display area has x and y values of 0. Values of x increase as you move to the right, and values of y increase as you move down the screen. (See Figure 7-3.)
You can convert screen coordinates to client-area coordinates and vice versa with these two Windows functions:
ScreenToClient (hwnd, &pt) ; ClientToScreen (hwnd, &pt) ;
where pt is a POINT structure. These two functions convert the values stored in the structure without preserving the old values. Note that if a screen-coordinate point is above or to the left of the window's client area, the x or y value of the client-area coordinate could be negative.
Figure 7-3. Screen coordinates and client-area coordinates.
The Hit-Test Message
If you've been keeping count, you know that so far we've covered 20 of the 21 mouse messages. The last message is WM_NCHITTEST, which stands for "nonclient hit test." This message precedes all other client-area and nonclient-area mouse messages. The lParam parameter contains the x and y screen coordinates of the mouse position. The wParam parameter is not used.
Windows applications generally pass this message to DefWindowProc. Windows then uses the WM_NCHITTEST message to generate all other mouse messages based on the position of the mouse. For nonclient-area mouse messages, the value returned from DefWindowProc when processing WM_NCHITTEST becomes the wParam parameter in the mouse message. This value can be any of the wParam values that accompany the nonclient-area mouse messages plus the following:
HTCLIENT Client area HTNOWHERE Not on any window HTTRANSPARENT A window covered by another window HTERROR Causes DefWindowProc to produce a beep
If DefWindowProc returns HTCLIENT after it processes a WM_NCHITTEST message, Windows converts the screen coordinates to client-area coordinates and generates a client-area mouse message.
If you remember how we disabled all system keyboard functions by trapping the WM_SYSKEYDOWN message, you may wonder if you can do something similar by trapping mouse messages. Sure! If you include the lines
case WM_NCHITTEST: return (LRESULT) HTNOWHERE ;
in your window procedure, you will effectively disable all client-area and nonclient-area mouse messages to your window. The mouse buttons will simply not work while the mouse is anywhere within your window, including the system menu icon, the sizing buttons, and the close button.
Messages Beget Messages
Windows uses the WM_NCHITTEST message to generate all other mouse messages. The idea of messages giving birth to other messages is common in Windows. Let's take an example. As you may know, if you double-click the system menu icon of a Windows program, the window will be terminated. The double-click generates a series of WM_NCHITTEST messages. Because the mouse is positioned over the system menu icon, DefWindowProc returns a value of HTSYSMENU and Windows puts a WM_NCLBUTTONDBLCLK message in the message queue with wParam equal to HTSYSMENU.
The window procedure usually passes that mouse message to DefWindowProc. When DefWindowProc receives the WM_NCLBUTTONDBLCLK message with wParam equal to HTSYSMENU, it puts a WM_SYSCOMMAND message with wParam equal to SC_CLOSE in the message queue. (This WM_SYSCOMMAND message is also generated when a user selects Close from the system menu.) Again the window procedure usually passes that message to DefWindowProc. DefWindowProc processes the message by sending a WM_CLOSE message to the window procedure.
If the program wants to require confirmation from a user before terminating, the window procedure can trap WM_CLOSE. Otherwise, DefWindowProc processes WM_CLOSE by calling the DestroyWindow function. Among other chores, DestroyWindow sends a WM_DESTROY message to the window procedure. Normally, a window procedure processes WM_DESTROY with the code
case WM_DESTROY: PostQuitMessage (0) ; return 0 ;
The PostQuitMessage causes Windows to place a WM_QUIT message in the message queue. This message never reaches the window procedure because it causes GetMessage to return 0, which terminates the message loop and the program.