WM_SYSCOMMAND Message

Platforms

Description & Usage

A window receives the WM_SYSCOMMAND message when either the user selects an item from its system menu or the user presses the restore, maximize, minimize, or close button on its title bar. Typically, a program should let the default window procedure process this command, unless the program needs to respond to an item added by the program to the window's system menu (see the example below).

Return Value

The WM_SYSCOMMAND message should always return 0.

Visual Basic-Specific Issues

None.

Parameters

wParam
The unique menu item identifier of the selected item. This could be one of the following flags, if the user selected an item that is by default on the system menu. When checking for these flags, first perform a bitwise And &HFFF0 on wParam before checking its value. This is necessary because the lowest four bits are used internally by the system and do not affect the flag itself. Of course, if your program added its own items to the system menu, then wParam will be that item's identifier and not one of the following values.
SC_CLOSE
Close the window.
SC_CONTEXTHELP
Display a context-sensitive help window.
SC_MAXIMIZE
Maximize the window.
SC_MINIMIZE
Minimize the window.
SC_MOVE
Move the window.
SC_RESTORE
Restore the window.
SC_SIZE
Size the window.
lParam
If the system menu item was selected using the mouse, this contains the coordinates of the mouse cursor. The x-coordinate is stored in the low-order word, and the y-coordinate is stored in the high-order word. The LOWORD and HIWORD macros can be used to extract the coordinates.

Constant Definitions

Const WM_SYSCOMMAND = &H112
Const SC_CLOSE = &HF060
Const SC_CONTEXTHELP = &HF180
Const SC_MAXIMIZE = &HF030
Const SC_MINIMIZE = &HF020
Const SC_MOVE = &HF010
Const SC_RESTORE = &HF120
Const SC_SIZE = &HF000

Example

' This code is licensed according to the terms and conditions listed here.

' Declarations and such needed for the example:
' (Copy them to the (declarations) section of a module.)
' There's quite a few declarations for this example, but it's worth it!
Public Declare Function GetSystemMenu Lib "user32.dll" (ByVal hWnd As Long, ByVal bRevert _
	As Long) As Long
Public Declare Function GetMenuItemCount Lib "user32.dll" (ByVal hMenu As Long) As Long
Public Type MENUITEMINFO
	cbSize As Long
	fMask As Long
	fType As Long
	fState As Long
	wID As Long
	hSubMenu As Long
	hbmpChecked As Long
	hbmpUnchecked As Long
	dwItemData As Long
	dwTypeData As String
	cch As Long
End Type
Public Const MIIM_STATE = &H1
Public Const MIIM_ID = &H2
Public Const MIIM_TYPE = &H10
Public Const MFT_SEPARATOR = &H800
Public Const MFT_STRING = &H0
Public Const MFS_ENABLED = &H0
Public Const MFS_CHECKED = &H8
Public Declare Function InsertMenuItem Lib "user32.dll" Alias "InsertMenuItemA" (ByVal _
	hMenu As Long, ByVal uItem As Long, ByVal fByPosition As Long, lpmii _
	As MENUITEMINFO) As Long
Public Declare Function SetMenuItemInfo Lib "user32.dll" Alias "SetMenuItemInfoA" (ByVal _
	hMenu As Long, ByVal uItem As Long, ByVal fByPosition As Long, lpmii _
	As MENUITEMINFO) As Long

Public Declare Function SetWindowPos Lib "user32.dll" (ByVal hWnd As Long, ByVal _
	hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal _
	cy As Long, ByVal wFlags As Long) As Long
Public Const HWND_TOPMOST = -1
Public Const HWND_NOTOPMOST = -2
Public Const SWP_NOMOVE = &H2
Public Const SWP_NOSIZE = &H1
Public Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hWnd _
	As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Public Const GWL_WNDPROC = -4
Public Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" (ByVal _
	lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam _
	As Long, ByVal lParam As Long) As Long
Public Const WM_SYSCOMMAND = &H112
Public Const WM_INITMENU = &H116

' Add an option to make window Form1 "Always On Top" to the bottom of its system
' menu.  A check mark appears next to this option when active.  The menu item acts as a toggle.
' Note how subclassing the window is necessary to process the two messages needed
' to give the added system menu item its full functionality.

' *** Place the following code in a module. ***

Public pOldProc As Long  ' pointer to Form1's previous window procedure
Public ontop As Boolean  ' identifies if Form1 is always on top or not

' The following function acts as Form1's window procedure to process messages.
Public Function WindowProc (ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam _
		As Long, ByVal lParam As Long) As Long
	Dim hSysMenu As Long     ' handle to Form1's system menu
	Dim mii As MENUITEMINFO  ' menu item information for Always On Top
	Dim retval As Long       ' return value
	
	Select Case uMsg
	Case WM_INITMENU
		' Before displaying the system menu, make sure that the Always On Top
		' option is properly checked.
		hSysMenu = GetSystemMenu(hwnd, 0)
		With mii
			' Size of the structure.
			.cbSize = Len(mii)
			' Only use what needs to be changed.
			.fMask = MIIM_STATE
			' If Form1 is now always on top, check the item.
			.fState = MFS_ENABLED Or IIf(ontop, MFS_CHECKED, 0)
		End With
		retval = SetMenuItemInfo(hSysMenu, 1, 0, mii)
		WindowProc = 0
	Case WM_SYSCOMMAND
		' If Always On Top (ID = 1) was selected, change the on top/not on top
		' setting of Form1 to match.
		If wParam = 1 Then
			' Reverse the setting and make it the current one.
			ontop = Not ontop
			retval = SetWindowPos(hwnd, IIf(ontop, HWND_TOPMOST, HWND_NOTOPMOST), _
				0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE)
			WindowProc = 0
		Else
			' Some other item was selected.  Let the previous window procedure
			' process it.
			WindowProc = CallWindowProc(pOldProc, hwnd, uMsg, wParam, lParam)
		End If
	Case Else
		' If this is some other message, let the previous procedure handle it.
		WindowProc = CallWindowProc(pOldProc, hwnd, uMsg, wParam, lParam)
	End Select
End Function

' *** Place the following code inside Form1. ***

' When Form1 loads, add Always On Top to the system menu and set up the
' new window procedure.
Private Sub Form_Load()
	Dim hSysMenu As Long     ' handle to the system menu
	Dim count As Long        ' the number of items initially on the menu
	Dim mii As MENUITEMINFO  ' describes a menu item to add
	Dim retval As Long       ' return value
	
	' Get a handle to the system menu.
	hSysMenu = GetSystemMenu(Form1.hWnd, 0)
	' See how many items are currently in it.
	count = GetMenuItemCount(hSysMenu)
	
	' Add a separator bar and then Always On Top to the system menu.
	With mii
		' The size of the structure.
		.cbSize = Len(mii)
		' What parts of the structure to use.
		.fMask = MIIM_ID Or MIIM_TYPE
		' This is a separator.
		.fType = MFT_SEPARATOR
		' It has an ID of 0.
		.wID = 0
	End With
	' Add the separator to the end of the system menu.
	retval = InsertMenuItem(hSysMenu, count, 1, mii)
	
	' Likewise, add the Always On Top command.
	With mii
		.fMask = MIIM_STATE Or MIIM_ID Or MIIM_TYPE
		' This is a regular text item.
		.fType = MFT_STRING
		' The option is enabled.
		.fState = MFS_ENABLED
		' It has an ID of 1 (this identifies it in the window procedure).
		.wID = 1
		' The text to place in the menu item.
		.dwTypeData = "&Always On Top"
		.cch = Len(.dwTypeData)
	End With
	' Add this to the bottom of the system menu.
	retval = InsertMenuItem(hSysMenu, count + 1, 1, mii)
	
	' Set the custom window procedure to process Form1's messages.
	ontop = False
	pOldProc = SetWindowLong(Form1.hWnd, GWL_WNDPROC, AddressOf WindowProc)
End Sub

' Before unloading, restore the default system menu and remove the
' custom window procedure.
Private Sub Form_Unload(Cancel As Integer)
	Dim retval As Long  ' return value
	
	' Replace the previous window procedure to prevent crashing.
	retval = SetWindowLong(Form1.hWnd, GWL_WNDPROC, pOldProc)
	' Remove the modifications made to the system menu.
	retval = GetSystemMenu(Form1.hWnd, 1)
End Sub

See Also

WM_COMMAND

Category

Menus

Back to the Message list.
Back to the Reference section.


Last Modified: June 4, 2000
This page is copyright © 2000 Paul Kuliniewicz. Copyright Information Revised October 29, 2000
Go back to the Windows API Guide home page.
E-mail: vbapi@vbapi.com Send Encrypted E-Mail
This page is at http://www.vbapi.com/ref/w/wm_syscommand.html