Beginning with Windows 3, you can make use of menus without having a top-level menu bar. You can instead cause a popup menu to appear on top of any part of the screen. One approach is to invoke this popup menu in response to a click of the right mouse button. However, menu items must still be selected with the left mouse button. The POPMENU program in Figure 9-5 (beginning on the following page) shows how this is done.
POPMENU.MAK
#-----------------------
# POPMENU.MAK make file
#-----------------------
popmenu.exe : popmenu.obj popmenu.def popmenu.res
link popmenu, /align:16, NUL, /nod slibcew libw, popmenu
rc popmenu.res
popmenu.obj : popmenu.c popmenu.h
cl -c -Gsw -Ow -W2 -Zp popmenu.c
popmenu.res : popmenu.rc popmenu.h
rc -r popmenu.rc
POPMENU.C
/*----------------------------------------
POPMENU.C -- Popup Menu Demonstration
(c) Charles Petzold, 1990
----------------------------------------*/
#include <windows.h>
#include "popmenu.h"
long FAR PASCAL WndProc (HWND, WORD, WORD, LONG) ;
char szAppName [] = "PopMenu" ;
HANDLE hInst ;
int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
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) ;
}
hInst = hInstance ;
hwnd = CreateWindow (szAppName, "Popup Menu Demonstration",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
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)
{
static HMENU hMenu ;
static int wColorID [5] = { WHITE_BRUSH, LTGRAY_BRUSH, GRAY_BRUSH,
DKGRAY_BRUSH, BLACK_BRUSH } ;
static WORD wSelection = IDM_WHITE ;
POINT point ;
switch (message)
{
case WM_CREATE :
hMenu = LoadMenu (hInst, szAppName) ;
hMenu = GetSubMenu (hMenu, 0) ;
return 0 ;
case WM_RBUTTONDOWN :
point = MAKEPOINT (lParam) ;
ClientToScreen (hwnd, &point) ;
TrackPopupMenu (hMenu, 0, point.x, point.y, 0, hwnd, NULL) ;
return 0 ;
case WM_COMMAND :
switch (wParam)
{ case IDM_NEW :
case IDM_OPEN :
case IDM_SAVE :
case IDM_SAVEAS :
case IDM_UNDO :
case IDM_CUT :
case IDM_COPY :
case IDM_PASTE :
case IDM_CLEAR :
MessageBeep (0) ;
return 0 ;
case IDM_WHITE : // Note: Logic below
case IDM_LTGRAY : // assumes that IDM_WHITE
case IDM_GRAY : // through IDM_BLACK are
case IDM_DKGRAY : // consecutive numbers in
case IDM_BLACK : // the order shown here.
CheckMenuItem (hMenu, wSelection, MF_UNCHECKED) ;
wSelection = wParam ;
CheckMenuItem (hMenu, wSelection, MF_CHECKED) ;
SetClassWord (hwnd, GCW_HBRBACKGROUND,
GetStockObject (wColorID [wParam - IDM_WHITE])) ;
InvalidateRect (hwnd, NULL, TRUE) ;
return 0 ;
case IDM_ABOUT :
MessageBox (hwnd, "Popup Menu Demonstration Program.",
szAppName, MB_ICONINFORMATION | MB_OK) ;
return 0 ;
case IDM_EXIT :
SendMessage (hwnd, WM_CLOSE, 0, 0L) ;
return 0 ;
case IDM_HELP :
MessageBox (hwnd, "Help not yet implemented.",
szAppName, MB_ICONINFORMATION | MB_OK) ;
return 0 ;
}
break ;
case WM_DESTROY :
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
POPMENU.RC
/*----------------------------
POPMENU.RC resource script
----------------------------*/
#include "popmenu.h"
PopMenu MENU
{
POPUP ""
{
POPUP "&File"
{
MENUITEM "&New", IDM_NEW
MENUITEM "&Open...", IDM_OPEN
MENUITEM "&Save", IDM_SAVE
MENUITEM "Save &As...", IDM_SAVEAS
MENUITEM SEPARATOR
MENUITEM "E&xit", IDM_EXIT
}
POPUP "&Edit"
{
MENUITEM "&Undo", IDM_UNDO
MENUITEM SEPARATOR
MENUITEM "Cu&t", IDM_CUT
MENUITEM "&Copy", IDM_COPY
MENUITEM "&Paste", IDM_PASTE
MENUITEM "C&lear", IDM_CLEAR
}
POPUP "&Background"
{
MENUITEM "&White", IDM_WHITE, CHECKED
MENUITEM "&Lt Gray", IDM_LTGRAY
MENUITEM "&Gray", IDM_GRAY
MENUITEM "&Dk Gray", IDM_DKGRAY
MENUITEM "&Black", IDM_BLACK
}
POPUP "&Help"
{
MENUITEM "&Help", IDM_HELP
MENUITEM "&About PopMenu...", IDM_ABOUT
}
}
}
POPMENU.H
/*-----------------------
POPMENU.H header file
-----------------------*/
#define IDM_NEW 1
#define IDM_OPEN 2
#define IDM_SAVE 3
#define IDM_SAVEAS 4
#define IDM_EXIT 5
#define IDM_UNDO 10
#define IDM_CUT 11
#define IDM_COPY 12
#define IDM_PASTE 13
#define IDM_CLEAR 14
#define IDM_WHITE 20
#define IDM_LTGRAY 21
#define IDM_GRAY 22
#define IDM_DKGRAY 23
#define IDM_BLACK 24
#define IDM_HELP 30
#define IDM_ABOUT 31
POPMENU.DEF
;------------------------------------
; POPMENU.DEF module definition file
;------------------------------------
NAME POPMENU
DESCRIPTION 'Popup Menu Demonstration Program (c) Charles Petzold, 1990'
EXETYPE WINDOWS
STUB 'WINSTUB.EXE'
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE MULTIPLE
HEAPSIZE 1024
STACKSIZE 8192
EXPORTS WndProc
The POPMENU.RC resource script defines a menu very similar to the one in MENUDEMO.RC. The difference is that the top-level menu contains only one item—a popup that invokes the File, Edit, Background, and Help options.
During the WM_CREATE message in WndProc, POPMENU obtains a handle to this popup menu:
hMenu = LoadMenu (hInst, szAppName) ;
hMenu = GetSubMenu (hMenu, 0) ;
During the WM_RBUTTONDOWN message, POPMENU obtains the position of the mouse point, coverts the position to screen coordinates, and passes the coordinates to TrackPopupMenu:
point = MAKEPOINT (lParam) ;
ClientToScreen (hwnd, &point) ;
TrackPopupMenu (hMenu, 0, point.x, point.y, 0, hwnd, NULL) ;
Windows then displays the popup menu with the items File, Edit, Background, and Help. Selecting any of these options causes the nested popup menus to appear to the right. The menu functions the same as a normal menu.