CHAPTER 16

HOW TO CREATE POPUP MENUS.

OVERVIEW:

Right button popup menus are displayed in response to WM_RBUTTONDOWN messages received by the program from the client area of a window, and the code to display the popup menu will be provided as the response to this message.

The menu items in a popup menu normally have names in the form of text strings, although provision is made for them to alternatively be in the form of icons. When any such menu item is clicked inside a popup menu on the screen, a WM_COMMAND

message is sent to the window that owns it, and the program can use the parameters in the message to identify which menu item was selected and thus call the response code appropriate to that particular menu item.

In order to create a popup menu, we must therefore provide names in the form of text strings, and equate names that will uniquely identify each menu item for the WM_COMMAND message.

CREATING AND USING RIGHT BUTTON POPUP MENUS:

A right button popup menu is a default system object, and is assigned by calling a set of API functions. The first function that is called simply creates a menu handle and nothing else, as follows:

api CreatePopupMenu
mov [POPUP.MENU.Handle],eax

This function merely assigns an instance of the menu class, hidden within the operating system, and does not contain any menu items. These have to be added by calling either of the AppendMenu or InsertMenu

API functions, and are added individually, one by one.

Usually, one need use only AppendMenu, which simply adds a new item to the end of the current list of items each time it is called. InsertMenu can insert a new item within the already existing list, and moves the subsequent items further down the list.

The use of the AppendMenu API function has the following form:

api AppendMenu,[POPUPMENU.Handle],MF_STRING,IDM_EDIT_CUT,POPUPMENU.String.Cut

The parameters are, in order: the menu handle, obtained from CreatePopupMenu, as shown above, a flag, the menu item identifier, and the address of memory location containing the name of the menu item as a text string.

The flag, shown as MF_STRING, can be of the form MF_STRING+MF_ENABLED, or alternatively it can be of the form MF_STRING+MF_GRAYED, which means that the menu item will appear in the popup menu in an active and enabled, or inactive and grayed, state. MF_ENABLED is the default, if the flag is omitted, meaning that the menu item will appear as active and enabled. Clicking on an inactive menu item will not send any WM_COMMAND message to the owner window.

The 'cut' item in a menu, for example, should appear in a grayed and inactive form, if there is no highlighted text on the screen that can be cut, or removed. Likewise, the 'paste' item should appear in a grayed and inactive form if there is no data on the clipboard that could be pasted onto the screen, and so on. These various conditions can be assessed each time the user calls the right button menu, and an API function is provided to alter the states of the various items each time, if necessary, as we shall see.

The flag MF_STRING indicates that the menu item has its name only, as printed text. The alternative, an MF_BITMAP flag, would indicate that the last parameter was a handle to a bitmap instead of the

address of an item name text string. In that case, the menu item on the screen would display the bitmap rather than printed text.

IDM_EDIT_CUT is an equate that represents the numerical identifier of the menu item. This equate should be identical to that used for the same item, if there is one, associated with the menu bar menu. As an example, we can set up the equates for Cut, Copy, Paste, Delete as follows:

IDM_EDIT_CUT equ 106
IDM_EDIT_COPY equ 107
IDM_EDIT_PASTE equ 108
IDM_EDIT_DELETE equ 109

and the text strings would be:

[section .data]
POPUPMENU.String.Cut db "Cut",0
POPUPMENU.String.Copy db "Copy",0
POPUPMENU.String.Paste db "Paste",0
POPUPMENU.String.Delete db "Delete",0

The strings must be zero terminated, as shown, as is the usual practice with Windows, since the system will scan the text until it encounters a zero, and then terminate the scan.

The following procedure can be used to create a popup menu with the above four menu items in 'grayed' form, as a default:

api CreatePopupMenu
mov [POPUP.MENU.Handle],eax
mov ecx,MF_STRING+MF_GRAYED
api AppendMenu,[POPUPMENU.Handle],ecx,IDM_EDIT_CUT,POPUPMENU.String.Cut
api AppendMenu,[POPUPMENU.Handle],ecx,IDM_EDIT_COPY,POPUPMENU.String.Copy
api AppendMenu,[POPUPMENU.Handle],ecx,IDM_EDIT_PASTE,POPUPMENU.String.Paste
api AppendMenu,[POPUPMENU.Handle],ecx,IDM_EDIT_DELETE,POPUPMENU.String.Delete
ret

The above code only creates the popup menu, but does not display it on the screen, and it should be called only once, at the beginning of the program, and left as is until the program receives a WM_CLOSE message when the user terminates it at the end.

This is better than completely creating an destroying popup menus each time they are called, since, as mentioned in the chapter on bitmaps, creating and destroying too many resources, too often, can cause problems for the operating system memory management.

The popup menu can be displayed on the screen each time the user calls it, by using the TrackPopupMenu function, as indicated below.

Before displaying a popup menu on the screen, it is

necessary to determine whether or not each of its items should be displayed in a normal, enabled form, or in a grayed and disabled form. The program code should, for example, have a flag to declare whether or not there is any highlighted text on the screen, so that this can be used to determine whether or not the cut, copy, and delete menu items should appear as enabled or disabled. Likewise, the Windows Clipboard should be tested to see whether or not it has any data to be pasted, so that the paste menu item can be shown in an enabled or grayed form.

Once these conditions have been determined the EnableMenuItem function is called to set the conditions of the menu items, and then TrackPopupMenu is called to display the popup menu on the screen, as follows:

POPUPMENU:
.All.Enabled:
mov ecx,MF_BYCOMMAND+MF_ENABLED
api EnableMenuItem,[POPUPMENU.Handle],IDM_EDIT_CUT,ecx
api EnableMenuItem,[POPUPMENU.Handle],IDM_EDIT_COPY,ecx
api EnableMenuItem,[POPUPMENU.Handle],IDM_EDIT_PASTE,ecx
api EnableMenuItem,[POPUPMENU.Handle],IDM_EDIT_DELETE,ecx
jmp .DisplayPopupMenu
;
.PasteOnly.Enabled:
mov ecx,MF_BYCOMMAND+MF_ENABLED
mov edx,MF_BYCOMMAND+MF_GRAYED
api EnableMenuItem,[POPUPMENU.Handle],IDM_EDIT_CUT,edx
api EnableMenuItem,[POPUPMENU.Handle],IDM_EDIT_COPY,edx
api EnableMenuItem,[POPUPMENU.Handle],IDM_EDIT_PASTE,ecx
api EnableMenuItem,[POPUPMENU.Handle],IDM_EDIT_DELETE,edx
jmp .DisplayPopupMenu
;
etc. for other possible arrangements
;
.DisplayPopupMenu:
mov esi,POINT
set.d'==&',[esi],[Screen_.CURSOR.XPos], [esi+4],[Screen_.CURSOR.YPos]
api ClientToScreen,[WINDOW.Handle],POINT
set.d '==&',[Full.Screen_.MENU.XPos],[esi], [Full.Screen_.MENU.YPos],[esi+4]
;
mov ecx,TPM_RIGHTALIGN+TPM_LEFTBUTTON
eq [X], '=', [Full.Screen_.MENU.XPos]
eq [Y], '=', [Full.Screen_.MENU.YPos]
api TrackPopupMenu,[POPUPMENU.Handle],ecx,[X],[Y],0,[WINDOW.Handle],0
ret

The MF_BYCOMMAND flag indicates, to the EnableMenuItem API function, that the second parameter passed to the function is the item's equate name. There is an alternative, which I will omit.

The TrackPopupMenu function specifies the horizontal, [X], and vertical, [Y], coordinates on the screen, at which the popup menu is to be located when it is displayed. Since the popup menu is a system object, its x and y coordinates are specified relative to the top left corner of the full video screen, which is indicated by the environmental reference 'FullScreen' in [Full.Screen_.MENU.Xpos] and [Full.Screen_.MENU.Ypos].

The initial code within .DisplayPopupMenu is used to convert the mouse cursor window client x and y coordinates to full screen coordinates via the ClientToScreen API function, so that the menu will be displayed at the current position of the mouse cursor.

The TPM_RIGHTALIGN equate flag specifies that the menu should be displayed to the right of the mouse cursor position, which means that the top left corner of the menu will be positioned at the current mouse cursor coordinates. A TPM_LEFTALIGN flag would specify that the top right corner of the menu would be located at the mouse cursor position. Since, however, the menu is always displayed as fully visible on the screen, the menu will be displayed to

the left of the cursor position if the cursor is too close to the right hand edge of the screen, whatever the location flag might be, and vice versa.

The ClientToScreen API function requires the window handle and a 'POINT' data structure. The data structure is as follows:

strct POINT,8
el Screen_.POINT.XPos, 0, 4
el Screen_.POINT.YPos, 4, 4
end.strct

It thus contains merely x and y coordinate values. The window client coordinates of the mouse cursor are put into this structure, via esi in the code example above, before the API function is called, and the ClientToScreen function then returns the full screen x and y coordinates of the mouse cursor in the same POINT structure.

In response to the WM_CLOSE message, the program code must release all the resources the system has internally assigned to the menu by destroying the menu, which is done by calling the following API function.

api DestroyMenu,[POPUPMENU.Handle]

(The Windows documentation, by the way, refers to right button popup menus as 'context' menus).

                  Part I: Part I Introduction
                  Chapter 1: Binary numbers, code, and procedures
                  Chapter 3: Assembly Language
                  Chapter 4: Assembly Language Code example
                  Chapter 5: Macros and HLA
                  Chapter 6: HLA code example
                  Chapter 7: The Windows operating system
                  Chapter 8: Data Structures
                  Chapter 9: How to Create a Windows Program
                  Chapter 10: How to Create an Exe File
                  Chapter 11: Structured Programming and OOP
                  Part II: Part II Introduction
                  Chapter 12: Debugging a Windows Program Code
                  Chapter 13: Painting the Window Client Area
                  Chapter 14: Creating Window Menus
                  Chapter 15: How to Create Toolbars
                  Chapter 16: How to Create Popup Menus
                  Chapter 17: About the Windows Clipboard
                  Chapter 18: How to Create Bitmaps
                  Chapter 19: Icons and the Ico Format
                  Chapter 20: Common Dialog Boxes
                  Chapter 21: Working with Files
                  Chapter 22: Scrollbars and Scrolling
                  Chapter 23: How to Send Data to the Printer
                  Chapter 24: Miscellaneous Topics

© Alen, June 2014
alen@alenspage.net


Material on this page may be reproduced
for personal use only.