CHAPTER 14

CREATING WINDOW MENUS.

There are three ways of creating window menus (that is, menus that appear in a menu bar underneath the window title bar).

Menus in the menu bar are forms of data that can be created as a resource, independently of your source code, and linked in at the time of the creation of the

final exe file, or they can be created, by two different methods, by using API functions, within the source code itself. In all cases, the operating system itself automatically creates and draws the menu bar when a menu is assigned to a window, and the programmer does not have to directly create it in the same way as would be the case with a toolbar.

MENU RESOURCES:

As indicated in Chapter 10, on creating exe files, a resource compiler converts suitable source files into a data resource in binary form. Window menus are one example of the kind of resources that can be created in this way.

The menu source files, suitable to be operated on by Microsoft's resource compiler rc.exe, are C language source files called Menu.h and Menu.rc, which are simply re-named text files. Menu.rc defines the menus and menu items, and also has a command to include Menu.h, which is a list of C language definitions of equate names. The menu items, and sub items, defined in Menu.rc, will appear on the menu bar of the final executable file.

You create the files Menu.h and Menu.rc with an ordinary text editor, and save them as *.h and *.rc files, or save them as *.txt files and simply rename them. The following is an example of the contents of a Menu.rc file:

#include "Menu.h"

MENU1 MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&Open", IDM_FILE_OPEN
MENUITEM SEPARATOR
MENUITEM "&Save", IDM_FILE_SAVE
MENUITEM SEPARATOR
MENUITEM "&Print", IDM_FILE_PRINT
END
POPUP "&Edit"
BEGIN
MENUITEM "&Cut", IDM_EDIT_CUT
MENUITEM "&Copy", IDM_EDIT_COPY
MENUITEM "&Paste", IDM_EDIT_PASTE
MENUITEM SEPARATOR
MENUITEM "&Delete", IDM_EDIT_DELETE
END
POPUP "&Help"
BEGIN
MENUITEM "&Help", IDM_HELP_HELP
MENUITEM "&About", IDM_HELP_ABOUT
END
END

MENU1, at the start, is the name of the menu, which can also be assigned to the .lpszMenuName element of the WNDCLASSEX data structure, when registering the window class. File, Edit, and Help, in inverted commas, specify the names of the menus as they will appear in the menu bar of the window, each of which creates a popup menu when selected. Open, Save, and Print, for example, are the names of the menu items of the popup menu associated with the File menu, when it is selected, and similarly with the other menus, and their popup items.

All parameters like IDM_FILE_OPEN are equate names for identification numbers for a particular menu item. When the item is selected, the relevant identification number is associated with the WM_COMMAND message sent by the menu to the program message loop. This enables the program code to identify which menu item was selected, and thus respond accordingly. The following are the contents of a Menu.h file that correspond to those of the above Menu.rc file, and are included in Menu.rc by the instruction, #include “Menu.h“:

#define IDM_FILE_OPEN 101
#define IDM_FILE_SAVE 102
#define IDM_FILE_PRINT 103
#define IDM_EDIT_CUT 104
#define IDM_EDIT_COPY 105
#define IDM_EDIT_PASTE 106
#define IDM_EDIT_DELETE 107
#define IDM_HELP_HELP 108
#define IDM_HELP_ABOUT 109

These equates must be also independently defined as such in your program's source code, because they are used not only by the resource compiler, but also in the context of the WM_COMMAND message sent by the menu items. You must thus convert all these C language definitions to assembly language equates, which is a simple operation as, for example

#define IDM_FILE_NEW 101
becomes
IDM_FILE_NEW equ 101
etc.

A menu assigned to a window class is apparently supposed to be loaded automatically by Windows. In practice, I have found that this does not appear to work, unless the [hInstance] value inserted into the .hInstance element of the WNDCLASSEX data structure is the program's module handle, rather than the value passed as the [ebp+8] parameter, that was pushed onto the stack when Windows called WinMain. The module handle is the handle of the opened exe file, and is obtained from the API function GetModuleHandle. The solution that I suggest is to use API functions to assign the menu to the window, independently of the WNDCLASSEX data structure, just after calling CreateWindowEx, and before calling ShowWindow, as follows:

api GetModuleHandle,0
mov [ModuleHandle],eax
api LoadMenu,[ModuleHandle],WINDOW.MenuName
mov [MENU.Handle],eax
api SetMenu,[WINDOW.Handle],[MENU.Handle]

It is necessary to call both the LoadMenu and SetMenu API functions, as shown, in order to successfully assign the menu to the window.

CREATING MENUS DIRECTLY:

It is not essential to create menus as a resource, as they can be created directly by the use of suitable API functions. It is thus not necessary to have a resource compiler in order to create windows with menus.

To create menus directly, the same information appearing in the resource source file, menu.rc, has to be provided as data in the data section of your program source code.

There are two ways in which this can be done. The first way uses data structures that constitute a menu template, the address of which is then passed to an API function that creates the menu. The second way is to use an API function to create a menu, and then use another API function to add items to the menu, one after the other. The final result, of course, is the same in either case.

USING THE MENU TEMPLATE METHOD:

The template data has to be provided in the form of two kinds of data structures, that are used together to create the menu template as a whole.

The first of the two kinds of data structures is a MENUITEMTEMPLATEHEADER structure, and the second is a MENUITEMTEMPLATE structure. The MENUITEMTEMPLATEHEADER is used only

once, at the start of the menu template, and is immediately followed by a series of MENUITEMTEMPLATE structures, one for each item in the menu, with a slight difference between the structures for the menus themselves and for their popup menu items. These two data structures are shown below:

Strct MENUITEMTEMPLATEHEADER,?
el MENUITEMTEMPLATEHEADER.VersionNo, 0, 2
el MENUITEMTEMPLATEHEADER.ItemTemplatesOffset, 2, 2
el MENUITEMTEMPLATEHEADER.ItemTemplates, 4, ?
end.strct

Strct MENUITEMTEMPLATE,?
el MENUITEM.Flags, 0, 2
el MENUITEM.ID, 2, 2
el MENUITEM.String, 4, ?
end.strct

For the menus themselves, like File, or Edit, etc., the MENUITEMTEMPLATE structure's second element (MENUITEM.ID) is left out. It is not merely set to zero; it is left out altogether, so that the structure for the menu itself is:

Strct MENUITEMTEMPLATE,?
el MENUITEM.Flags, 0, 2
el MENUITEM.String, 2, ?
end.strct

The ItemTemplates element of the header structure really does not belong to the header, but I have created it as representing a list of MENUITEMTEMPLATE structures that follow one another immediately after the second, and last, element of the header.

The total size of these, in bytes, depends on the

number of items in the menu, which thus also determines the total size of the memory block associated with the header - hence the question marks.

To actually create the menu involves simply starting at the header address, setting the two header elements to zero (which is required when the items immediately follow the header), and then entering menus, and their popup menu items, one after the other.

To do this you first need to declare all the strings in the data section of your code. In the case of menus, the string characters must be word sized Unicode characters, as follows, and not the normal ASCII byte sized characters (for a discussion of Unicode strings, see Chapter 24):

MENU.String.1 dw 0x0046,0x0069,0x006c,0x0065,0x0000 ;File
MENU.String.2 dw 0x004f,0x0070,0x0065,0x006e,0x0000 ;Open
MENU.String.3 dw 0x0053,0x0061,0x0076,0x0065,0x0000 ;Save
etc.

and so on for all the strings already displayed in the menu.rc example above. The next step is to create a procedure that inserts the strings and equate values into a memory block in the order, and at offsets, indicated by the MENUITEMTEMPLATE data structures, in order to form the overall menu template. This is shown below.

MENUITEMTEMPLATEHEADER is a symbol

defining the start address of the memory block, and the two word sized elements that form the header are set to zero. Then all the menus and popup items, with their strings, immediately follow the two header elements.

The memory block starting address is initially put in register esi, and the value of esi is incremented as required.

MENU.CreateMenuBarMenus:
mov esi,MENUITEMTEMPLATEHEADER
set.w '=&',[esi],[esi+2],0
ii.. add esi,4, mov [esi], word MF_POPUP, add esi,2, mov edi,MENU.String.File
call .add.string
ii.. mov [esi], word MF_ENABLED, mov [esi+2],word IDM_FILE_OPEN
ii.. add esi,4, mov edi,MENU.String.Open
call .add.string
ii.. mov [esi],word MF_GRAYED, mov [esi+2],word IDM_FILE_SAVE
ii.. add esi,4, mov edi,MENU.String.Save
call .add.string
ii.. mov [esi],word MF_GRAYED+MF_END, mov [esi+2],word IDM_FILE_PRINT
ii.. add esi,4, mov edi,MENU.String.Print
call .add.string
and so on, until we get to
ii.. mov [esi],word MF_POPUP+MF_END, add esi,2, mov edi,MENU.String.Help
call .add.string
ii.. mov [esi],word MF_ENABLED, mov [esi+2],word IDM_HELP_HELP
ii.. add esi,4, mov edi,MENU.String.Help
call .add.string
ii.. mov [esi],word MF_ENABLED+MF_END, mov [esi+2],word IDM_HELP_ABOUT
ii.. add esi,4, mov edi,MENU.String.d
call .add.string
ret
;----------------
.add.string:
until.w '=',[edi],0
set.w '=',[esi],[edi]
add.d esi,2, edi,2
end.until
ii.. mov word [esi],0, add esi,2
ret

The .add.string procedure transfers each string, in turn, from the data section string declaration to the menu template, as required.

The item data structures are not overtly used, as such, but are really used as a guide to what must be the sequence of values at successive offsets within the one, overall, menu template memory block.

You can see that the overall menu template contains the same data as that which appears in the menu.rc file. The flags MF_ENABLED or MF_GRAYED, which specify the initial states of the menu items, can be entered into the flags elements of the MENUITEMTEMPLATE structures.

I need to emphasise an important consideration here regarding the correct use of the other flag values.

MF_POPUP declares a main menu item, like File or Edit, which produces a popup menu when selected. The popup menu items themselves have only the enabled or grayed flags. Note, however, that the last item of a popup item list also has the flag MF_END, which declares the end of a popup menu, after which the next menu begins, again with the MF_POPUP flag. Note, in addition, however, that the last menu in the template has MF_POPUP|MF_END flags, and its last popup menu item also includes the MF_END flag, which declares the end of the menu template.

If these FM_END flags are not thus properly placed or, in other words, if one of them is misplaced, or omitted, the menu template won't work properly, if at all.

ASSIGNING THE MENU TO THE WINDOW:

Once you have created the menu template, and added the menus and items lists, the following API functions must be called to assign the menu to the window:

api LoadMenuIndirect,MENUITEMTEMPLATEHEADER
mov [MENU.Handle],eax
api SetMenu,[WINDOW.Handle],[MENU.Handle]

Since these require the handle of the window, they have to be called after the window has been created by the CreateWindowEx function, and before the window is displayed on the screen. The LoadMenuIndirect function has the template header

address, or address of the template memory block, as its parameter, and this must be filled with menu items before the function is called. The API function, SetMenu, then assigns the menus to the window, and the system inserts them into the window menu bar when the window is displayed on the screen.

This is one of the occasions when it is necessary to intercept the Windows messages, which are sent to the window code, as described in Chapter 7, so that the menu can be assigned to the window after the window has been created, but before it is displayed on the screen.

CREATING A MENU DIRECTLY, WITHOUT A TEMPLATE:

Creating a menu directly, without using a template, is done in the same way as that in which mouse right button popup menus are created, as we shall see later on. The main difference is that the normal menu is assigned to the window, as the window's menu, whereas a right button popup menu is not. The code sample shown below creates a menu, and then assigns it to the window.

First, the menu is created, using the API function CreateMenu, and the returned menu handle is saved in memory. This only creates the menu, which is empty, and it contains no menu items, or popup menus. That is, it represents only the basic empty menubar, as it were. Different popup menus, such as File, Edit, etc. have to be created individually, using the CreatePopupMenu API function, separately, for each one of them, with the popup menu handles again being saved in memory.

These popup menus are created independently, and are not yet linked to the main menu. They are also initially empty, and contain no popup menu Items. These have to be added, one by one, as desired, using the API function AppendMenu. The second

parameter of AppendMenu is the handle of a popup menu, and thus links the item to the particular popup menu. If it contains both the handle of the popup menu, and the handle of the main menu, it links the popup menu, with all its items, to the main menu.

The completion of this process then creates the final window menubar menu. The menu is then assigned to the window, using the API function SetMenu, and the system will add the menu bar and menus to the window.

The menu should be created immediately after the window has been created, although this doesn't really matter, as far as the system is concerned. If the window is already displayed on the screen, without a menubar, and the following code is called, the system will still assign the menubar, and menus, to the window. You can easily prove that, by experiment, if you want to.

In my view, this is the easiest way to create and assign menus to a window, and has the highest assurance of success compared to the other methods, or the lowest risk of encountering problems.

api CreateMenu
mov [MENU.Handle],eax
api CreatePopupMenu
mov [POPUPMENU.Handle1],eax
api CreatePopupMenu
mov [POPUPMENU.Handle2],eax
;
api AppendMenu,[POPUPMENU.Handle1],MF_STRING,IDM_FILE_OPEN,MENU.String.2
api AppendMenu,[POPUPMENU.Handle1],MF_STRING,IDM_FILE_SAVE,MENU.String.3
api AppendMenu,[POPUPMENU.Handle1],MF_STRING,IDM_FILE_PRINT,MENU.String.5
;
api AppendMenu,[MENU.Handle],MF_POPUP,[POPUPMENU.Handle1],MENU.String.1
;
api AppendMenu,[POPUPMENU.Handle2],MF_STRING,IDM_HELP_HELP,MENU.String.6
;
api AppendMenu,[MENU.Handle],MF_POPUP,[POPUPMENU.Handle2],MENU.String.6
;
api EnableMenuItem,[POPUPMENU.Handle1],IDM_FILE_SAVE,MF_BYCOMMAND|MF_GRAYED
api EnableMenuItem,[POPUPMENU.Handle1],IDM_FILE_PRINT,MF_BYCOMMAND|MF_GRAYED
api SetMenu,[WINDOW.Handle],[MENU.Handle]
ret

                  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.