Parent windows created with a style that includes WS_SYSMENU have a system menu box at the left of the caption bar. If you like, you can modify this menu. For instance, you can add your own menu commands to the system menu. While this is not recommended, modifying the system menu is often a quick-and-dirty way to add a menu to a short program without defining it in the resource script. The only restriction is this: The ID numbers you use to add commands to the system menu must be lower than F000H. Otherwise, they will conflict with the IDs that Windows uses for the normal system menu commands. And remember: When you process WM_SYSCOMMAND messages in your window procedure for these new menu items, you must pass the other WM_SYSCOMMAND messages to DefWindowProc. If you don't, you'll effectively disable all normal options on the system menu.
The program POORMENU (”poor person's menu“), shown in Figure 9-6 beginning on the following page, adds a separator bar and three commands to the system menu. The last of these commands removes the additions.
POORMENU.MAK
#------------------------
# POORMENU.MAK make file
#------------------------
poormenu.exe : poormenu.obj poormenu.def
link poormenu, /align:16, NUL, /nod slibcew libw, poormenu
rc poormenu.exe
poormenu.obj : poormenu.c
cl -c -Gsw -Ow -W2 -Zp poormenu.c
POORMENU.C
/*-----------------------------------------
POORMENU.C -- The Poor Person's Menu
(c) Charles Petzold, 1990
-----------------------------------------*/
#include <windows.h>
#define IDM_ABOUT 1
#define IDM_HELP 2
#define IDM_REMOVE 3
long FAR PASCAL WndProc (HWND, WORD, WORD, LONG) ;
static char szAppName [] = "PoorMenu" ;
int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
HMENU hMenu ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
if (!hPrevInstance)
{
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
RegisterClass (&wndclass) ;
}
hwnd = CreateWindow (szAppName, "The Poor Person's Menu",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
hMenu = GetSystemMenu (hwnd, FALSE) ;
AppendMenu (hMenu, MF_SEPARATOR, 0, NULL) ;
AppendMenu (hMenu, MF_STRING, IDM_ABOUT, "About...") ;
AppendMenu (hMenu, MF_STRING, IDM_HELP, "Help...") ;
AppendMenu (hMenu, MF_STRING, IDM_REMOVE, "Remove Additions") ;
ShowWindow (hwnd, nCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
long FAR PASCAL WndProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
switch (message)
{
case WM_SYSCOMMAND :
switch (wParam)
{
case IDM_ABOUT :
MessageBox (hwnd, "The Poor Person's Menu Program.",
szAppName, MB_OK | MB_ICONEXCLAMATION) ;
return 0 ;
case IDM_HELP :
MessageBox (hwnd, "Help not yet implemented.",
szAppName, MB_OK | MB_ICONEXCLAMATION) ;
return 0 ;
case IDM_REMOVE :
GetSystemMenu (hwnd, TRUE) ;
return 0 ;
}
break ;
case WM_DESTROY :
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
POORMENU.DEF
;-------------------------------------
; POORMENU.DEF module definition file
;-------------------------------------
NAME POORMENU
DESCRIPTION 'The Poor Person's Menu (c) Charles Petzold, 1990'
EXETYPE WINDOWS
STUB 'WINSTUB.EXE'
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE MULTIPLE
HEAPSIZE 1024
STACKSIZE 8192
EXPORTS WndProc
The three menu IDs are defined near the top of POORMENU.C:
#define IDM_ABOUT 1
#define IDM_HELP 2
#define IDM_REMOVE 3
After the program's window has been created, POORMENU obtains a handle to the system menu:
hMenu = GetSystemMenu (hwnd, FALSE) ;
When you first call GetSystemMenu, you should set the second parameter to FALSE in preparation for modifying the menu.
The menu is altered with four AppendMenu calls:
AppendMenu (hMenu, MF_SEPARATOR, 0, NULL) ;
AppendMenu (hMenu, MF_STRING, IDM_ABOUT, "About...") ;
AppendMenu (hMenu, MF_STRING, IDM_HELP, "Help...") ;
AppendMenu (hMenu, MF_STRING, IDM_REMOVE, "Remove Additions") ;
The first AppendMenu call adds the separator bar. Choosing the Remove Additions menu item causes POORMENU to remove these additions, which it accomplishes simply by calling GetSystemMenu again with the second parameter set to TRUE:
GetSystemMenu (hwnd, TRUE) ;
The standard system menu has the options Restore, Move, Size, Minimize, Maximize, Close, and Switch To. These generate WM_SYSCOMMAND messages with wParam equal to SC_RESTORE, SC_MOVE, SC_SIZE, SC_MINIMUM, SC_MAXIMUM, SC_CLOSE, and SC_TASKLIST. Although Windows programs do not normally do so, you can process these messages yourself rather than pass them on to DefWindowProc. You can also disable or remove some of these standard options from the system menu using methods described below. The Windows documentation also includes some standard additions to the system menu. These use the identifiers SC_NEXTWINDOW, SC_PREVWINDOW, SC_VSCROLL, SC_HSCROLL, and SC_ARRANGE. You might find it appropriate to add these commands to the system menu in some applications.