Win messages

From Team Developer SqlWindows Wiki
Jump to: navigation, search

Windows API messages


Pointer2.png How to detect mouse leaving a window Pointer.png

When the mouse cursor is leaving a window a message is send to the window indicating this.
But to enable this feature, you will have to call the Windows API function TrackMouseEvent first to register the window.

This is the declaration for TrackMouseEvent

Library name: USER32.DLL
   Function: TrackMouseEvent
      Export Ordinal: 0
         Boolean: BOOL
            Number: DWORD
            Number: DWORD
            Window Handle: HWND
            Number: DWORD

The following list of possible constant declarations for the function TrackMouseEvent

(The NC constants are for the non-client area's like caption or borders)

! Below the flags for TrackMouseEvent

Number: TME_HOVER         = 0x0001
Number: TME_LEAVE         = 0x0002
Number: TME_NONCLIENT     = 0x0010

! Below the message constants being send on notification

Number: WM_NCMOUSEHOVER   = 0x02A0
Number: WM_MOUSEHOVER     = 0x02A1
Number: WM_NCMOUSELEAVE   = 0x02A2
Number: WM_MOUSELEAVE     = 0x02A3

! Below the mousemove message as used in the sample

Number: WM_MOUSEMOVE     = 0x0200

To register a window to receive messages when leaving or hovering the window

! Below register window to receive LEAVE notification
Call TrackMouseEvent( 16, TME_LEAVE, hWndForm, 1 )

! Below register window to receive HOVER notification
Call TrackMouseEvent( 16, TME_HOVER, hWndForm, 400 )

The next sample shows an implementation of this feature.
When the user moves the mouse within the window, the message WM_MOUSEMOVE is received.

There the window will be registered to be notified when the mouse is leaving.
A boolean (wbTracking) is used to hold if the window is already registered.

The window will be registered until it receives a notification.

Form Window: frmSample
   Window Variables
      Boolean: wbTracking
   Message Actions
         ! The mouse is leaving the window, do custom actions here
         Set wbTracking = FALSE
         If NOT wbTracking
            If TrackMouseEvent( 16, TME_LEAVE, hWndForm, 1 )
               Set wbTracking = TRUE

Here you can download a sample:

Pointer2.png How to detect (double) clicks on a window Pointer.png

Several windows messages are send to the window when clicking.

Received when the user presses the left mousebutton
Received when the user releases the left mousebutton
Received when the user doubleclicks the left mousebutton
Received when the user presses the right mousebutton
Received when the user releases the right mousebutton
Received when the user doubleclicks the right mousebutton

Below the constant declarations for the messages:

! Left button
Number: WM_LBUTTONDOWN    = 0x0201
Number: WM_LBUTTONUP      = 0x0202
Number: WM_LBUTTONDBLCLK  = 0x0203
! Right button
Number: WM_RBUTTONDOWN    = 0x0204
Number: WM_RBUTTONUP      = 0x0205
Number: WM_RBUTTONDBLCLK  = 0x0206

Pointer2.png How to drag a window without a caption Pointer.png

When a window does not have a caption or you want to be able to drag a window while clicking anywhere on the window, this is the easiest way.

First you will have to declare the next constants.

Number: WM_LBUTTONDOWN		= 0x0201
Number: HTCAPTION		= 2

When clicking on a window (anywhere in the client area) send a message to the window indicating the mouse is within the caption area.

Form Window: frmSample
   Message Actions
         ! The user clicks somewhere in the client area of the window.
         ! Send a message to trick windows the user has clicked on the caption.
         ! While moving the mouse, the window will be dragged
         Call SalSendMsg( hWndForm, WM_NCLBUTTONDOWN, HTCAPTION, NUMBER_Null )

Here you can download a sample:

Pointer2.png How to detect/suppress system commands from a window (minimise, maximize, close etc) Pointer.png

A window receives the WM_SYSCOMMAND message when the user presses any of the syscommand options of a window.

First you will have to declare the constant for this message

   Number: WM_SYSCOMMAND   = 0x0112

The wParam of this message contains the action taken.
Next is a list of all possible action values.

Number: SC_SIZE           = 0xF000
Number: SC_MOVE           = 0xF010
Number: SC_MINIMIZE       = 0xF020
Number: SC_MAXIMIZE       = 0xF030
Number: SC_NEXTWINDOW     = 0xF040
Number: SC_PREVWINDOW     = 0xF050
Number: SC_CLOSE          = 0xF060
Number: SC_VSCROLL        = 0xF070
Number: SC_HSCROLL        = 0xF080
Number: SC_MOUSEMENU      = 0xF090
Number: SC_KEYMENU        = 0xF100
Number: SC_ARRANGE        = 0xF110
Number: SC_RESTORE        = 0xF120
Number: SC_TASKLIST       = 0xF130
Number: SC_SCREENSAVE     = 0xF140
Number: SC_HOTKEY         = 0xF150
Number: SC_DEFAULT        = 0xF160
Number: SC_MONITORPOWER   = 0xF170
Number: SC_CONTEXTHELP    = 0xF180
Number: SC_SEPARATOR      = 0xF00F

Here is a short description of the values:

  • SC_CLOSE - Closes the window.
  • SC_CONTEXTHELP - Changes the cursor to a question mark with a pointer. If the user then clicks a control in the dialog box, the control receives a WM_HELP message.
  • SC_DEFAULT - Selects the default item; the user double-clicked the window menu.
  • SC_HOTKEY - Activates the window associated with the application-specified hot key. The lParam parameter identifies the window to activate.
  • SC_HSCROLL - Scrolls horizontally.
  • SC_KEYMENU - Retrieves the window menu as a result of a keystroke. For more information, see the Remarks section.
  • SC_MAXIMIZE - Maximizes the window.
  • SC_MINIMIZE - Minimizes the window.
  • SC_MONITORPOWER - Sets the state of the display. This command supports devices that have power-saving features, such as a battery-powered personal computer. The lParam parameter can have the following values: 1 - the display is going to low power 2 - the display is being shut off
  • SC_MOUSEMENU - Retrieves the window menu as a result of a mouse click.
  • SC_MOVE - Moves the window.
  • SC_NEXTWINDOW - Moves to the next window.
  • SC_PREVWINDOW - Moves to the previous window.
  • SC_RESTORE - Restores the window to its normal position and size.
  • SC_SCREENSAVE - Executes the screen saver application specified in the [boot] section of the System.ini file.
  • SC_SIZE - Sizes the window.
  • SC_TASKLIST - Activates the Start menu.
  • SC_VSCROLL - Scrolls vertically.

Catch the message and determine which action was taken

Form Window: frmMain
   Message actions
         Select Case (wParam)
            Case SC_MINIMIZE
               // do something here
            Case SC_MAXIMIZE
               // do something else here

These constants can be found in the Windows API archive:
Down.png Windows API Archive

Pointer2.png How to detect that CTRL + SPACE was pressed within an graphical Object Pointer.png

The WM_CHAR message is posted to the window with the keyboard focus when a WM_KEYDOWN message is translated by the TranslateMessage function.
The WM_CHAR message contains the character code of the key that was pressed.
For Unicode there is also a WM_UNICHAR Message.

First you will have to declare the constant for this message:

   Number: WM_CHAR   = 0x0102

The wParam specifies the character code of the key.
The lParam specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag, as shown in the following table.

    Specifies the repeat count for the current message. 
    The value is the number of times the keystroke is auto repeated as a result of the user holding down the key. 
    If the keystroke is held long enough, multiple messages are sent. However, the repeat count is not cumulative.
    Specifies the scan code. The value depends on the OEM.
    Specifies whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an 
    enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
    Reserved; do not use.
    Specifies the context code. The value is 1 if the ALT key is held down while the key is pressed; otherwise, the value is 0.
    Specifies the previous key state. The value is 1 if the key is down before the message is sent, or it is 0 if the key is up.
    Specifies the transition state. The value is 1 if the key is being released, or it is 0 if the key is being pressed.

Catch the message and determine with GetKeyState which Keys has been pressed:

   If GetKeyState( VK_CONTROL ) < 0 AND GetKeyState( VK_SPACE ) < 0
      Return FALSE

To have the GetKeyState Function available you need to declare it in USER32.DLL like the following:

Global Declarations
   External Functions
      Library Name: USER32.DLL
         Function: GetKeyState
            Export Ordinal: 0
            Return: Number: SHORT
            Parameters: Number: INT

The Constants VK_CONTROLL and VK_SPACE are the following:

   Number: VK_CONTROLL   = 0x0011
   Number: VK_SPACE      = 0x0020

The Reason to have a Return FALSE in the On WM_CHAR message is, that otherwise a SPACE-Character would be printed. But in this way nothing will happen.

TODO Translate in correct English and proof if the Links are copied in the right way...

Pointer2.png How to detect SysColors have changed Pointer.png

When the user changes the Windows theme or changes any colors for the several GUI elements, Windows will send
message WM_SYSCOLORCHANGE to all top level windows currently present in the system.

When your application is depending or anticipating on special colors, you might want to be informed the System colors have changed. For instance when you do custom painting or display icons/bitmaps in predefined colors and you want to repaint them in the correct wanted color.

First declare this constant:

   Number: WM_SYSCOLORCHANGE  = 0x0015

Now, trap this message on top level windows. Also send the message to all children to inform them.

Form Window: frmMain
   Message actions
         Call SalSendMsgToChildren( hWndForm, WM_SYSCOLORCHANGE, wParam, lParam )

Depending on your needs, update used icons/bitmaps or repaint the custom drawings.

To get the colors set by the user, you can use the WinAPI function GetSysColor.

This is the declaration

Library name: USER32.dll
   Function: GetSysColor
         Number: DWORD
         Number: INT

Use the default WinAPI SysColor index values for the input parameter.
You can find the complete list of color index values on GetSysColor.
Or you can find them in SalExtension library and in the sample supplied here.

The next sample shows :

  • Detect changes in SysColors
  • Show all current SysColors (as picture background colors, RGB values or color values)
  • Set SysColors from the sample (using SetSysColors WinAPI). (Beware, it is a system wide setting, not only within the application)

Here you can download the sample:

Pointer2.png How to prevent window resize at top/bottom/left/right/corner locations Pointer.png

When the user moves the mouse over the border of a top level window, the cursor is set to a resize icon and the window can be resized.
The locations are left, right, top, bottom and the four corners of the window.

In some situations it could be needed to prevent the user to resize. This can be achieved by the following trick.

When the mouse moves over non-client areas like the border, the message WM_NCHITTEST is send to the window.
By calling the WinAPI function DefWindowProc you can determine which non-client area is hit tested.
When returning HTNOWHERE value in the WM_NCHITTEST message on the several non-client area ID's, the resize is prevented.
There will be no resize icon shown and the window can not be resized on the particular border location.

Here the implementation:
First declare these constants

Number: WM_NCHITTEST   = 0x84
Number: HTNOWHERE      = 0
Number: HTLEFT         = 10
Number: HTRIGHT        = 11
Number: HTTOP          = 12
Number: HTTOPLEFT      = 13
Number: HTTOPRIGHT     = 14
Number: HTBOTTOM       = 15
Number: HTBOTTOMLEFT   = 16

Also declare DefWindowProc

Library name: USER32.dll
   Function: DefWindowProcA
      Export Ordinal: 0
         Number: DWORD
         Window Handle: HWND
         Number: UINT
         Number: WPARAM
         Number: LPARAM

For TD5.1 and higher, declare DefWindowProcW.

Now, trap WM_NCHITTEST on top level windows.

Form Window: frmMain
   Message actions
         Set nRet = DefWindowProcA( hWndForm, WM_NCHITTEST, wParam, lParam )
         ! Use the next line in TD5.x
         Set nRet = DefWindowProcW( hWndFrame, WM_NCHITTEST, wParam, lParam )
         Select Case nRet
            Case HTLEFT
            Case HTRIGHT
            Case HTBOTTOM
            Case HTTOP
            Case HTBOTTOMLEFT
            Case HTBOTTOMRIGHT
            Case HTTOPLEFT
            Case HTTOPRIGHT
                Return HTNOWHERE

In the code above, all 8 locations are prevented from resize.
To prevent only certain locations, change the code so only for that particular HT area the HTNOWHERE value is returned.

Here you can download a sample:
Here the sample for TD version 5.1 and higher (UNICODE):

These samples contain more HT constants (eg HTCAPTION) to handle other NC areas if needed.