Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
98 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

Contents
 Resource Scripts
 Icons and Cursors
 Bitmaps
 Menus
 Custom Resources

 Printable version
 Discuss this article
 in the forums



The Series
 Beginning Windows
 Programming

 Using Resources
 in Win32 Programs

 Tracking Your
 Window/Using GDI

 Introduction
 to DirectX

 Palettes and Pixels
 in DirectDraw

 Bitmapped Graphics
 in DirectDraw

 Developing the
 Game Structure

 Basic Tile Engines
 Adding Characters
 Tips and Tricks

Menus

This is the last type of Windows resource I'll go over, and it's also one of the most useful. Menu resources are used to define the menu bar that would appear underneath the title bar of your application, and are loaded during the definition of the window class. Looking back, in the window class we developed during the last article, there was a line that looked like this:

sampleClass.lpszMenuName = NULL;

If you're creating a windowed application, chances are that you'll want to have a menu bar of some sort. This is done using the menu resource. The script file entry for this one can get a little complicated, but here is its most basic form:

[identifier] MENU { POPUP [menu name] { MENUITEM [item name], [identifier] } }

The identifier is what you're used to: either a string or a numeric constant that is used to refer to the menu. Within the MENU brackets, there can be one or more POPUP menus, each of which represent a pull-down menu, whose name is given by [menu name]. Within the POPUP brackets, there can be one or more MENUITEMs, each of which represents a final menu selection, with a name given by [item name] and an identifier that must be a numeric constant. Within the menu and item names, if you want that option to be accessible by a keyboard shortcut, you precede the letter of the shortcut with the ampersand (&). For instance, if you want to create a File menu accessible by pressing Alt+F, the menu name should be &File. Menu and item names should be enclosed in double quotation marks. With that, here is an example of a simple menu resource:

MAIN_MENU MENU { POPUP "&File" { MENUITEM "&New", MENUID_NEW MENUITEM "&Open...", MENUID_OPEN MENUITEM "&Save", MENUID_SAVE MENUITEM "Save &As...", MENUID_SAVEAS MENUITEM "E&xit", MENUID_EXIT } POPUP "&Help" { MENUITEM "&Contents", MENUID_CONTENTS MENUITEM "&Index...", MENUID_INDEX MENUITEM "&About", MENUID_ABOUT } }

You can also create submenus by including one POPUP inside of another, specify menu items as being initially grayed or checked, or do several other more advanced things, but I'm not going to go into that here. To obtain a handle to a menu resource, use the LoadMenu() function whose prototype is shown here:

HMENU LoadMenu( HINSTANCE hInstance, // handle to application instance LPCTSTR lpMenuName // menu name string or menu-resource identifier );

You should be used to these parameters by now. The first one is the instance of your application, and the second is the identifier you assigned to the menu. Remember to use MAKEINTRESOURCE() if you used a numerical constant. Now, to attach a menu to a window, you have two options. The first is to set the menu as the default for your window class, like this:

sampleClass.lpszMenuName = LoadMenu(hinstance, MAKEINTRESOURCE(MAIN_MENU));

The second option is to leave lpszMenuName equal to NULL, and attach a menu yourself later. This can be useful if you want to create two windows with different menus, but don't want to define two separate window classes. To attach a menu, use the SetMenu() function:

BOOL SetMenu( HWND hWnd, // handle to window HMENU hMenu, // handle to menu );

The return value is TRUE if the function succeeds, or FALSE if it fails. The parameters are pretty easy to figure out:

HWND hWnd: This is the handle to the window to which you want to attach the menu. Pass the handle that was returned when you called CreateWindowEx().

HMENU hMenu: To identify the menu, pass the handle returned by LoadMenu(). If you pass NULL, the specified window's menu is removed.

This resource is particularly nice because all the functionality of the menu is defined by that simple scripting. But what happens when the user selects a menu option? The answer is that Windows sends a WM_COMMAND message informing the program that it must take action. Let's pay a visit to our message-handling function and see if we can't figure out how to handle this.

Handling Menu Events

As you probably remember, Windows messages are handled by a special callback function usually called WindowProc() or something similar. The simple one we wrote last time was called MsgHandler(), and its prototype looked like this:

LRESULT CALLBACK MsgHandler( HWND hwnd, // window handle UINT msg, // the message identifier WPARAM wparam, // message parameters LPARAM lparam, // more message parameters };

When a menu message is sent, msg will be WM_COMMAND, and the menu item that was selected will be contained in wparam. This is why menu item identifiers can't be strings; they need to fit into the wparam parameter. More specifically, the menu item identifier is the low word of wparam. To extract the low or high word of a 32-bit variable type like WPARAM, LPARAM, int, etc. Windows provides macros called LOWORD() and HIWORD() that do the job. They are shown here:

#define LOWORD(l) ((WORD) (l)) #define HIWORD(l) ((WORD) (((DWORD) (l) >> 16) & 0xFFFF))

In the case of LOWORD(), the typecast to WORD simply truncates the value to the lower 16 bits. HIWORD() shifts the upper 16 bits to the right, then performs a logical AND with 0xFFFF just to be sure any bits above the lower 16 are all set to zero. If you're not familiar with the >> and << operators, they are bit shifts. The << operator shifts all the bits of a variable a number of positions to the left, and the >> operator shifts to the right. For example, suppose you had a 16-bit variable x whose value was 244. In binary this is 0000 0000 1111 0100. The following example shows a bit shift, and the effect on x:

short int x = 244, y; y = x << 4;

Contents of x: 0000 0000 1111 0100
Contents of y: 0000 1111 0100 0000

Anyway, use LOWORD() to extract the low word of wparam, and you have the ID of the menu item that was selected. So, somewhere in your MsgHandler() function, you should have something like this:

// handle menu selections if (msg == WM_COMMAND) { switch (LOWORD(wparam)) { case MENUID_NEW: // code to handle File->New goes here break; case MENUID_OPEN: // code to handle File->Open goes here break; // the rest of the option handlers go here } // tell Windows you took care of it return(0); }

Make sense? Good. That about wraps it up for the specific resource types I'm going to cover. There are others, such as accelerator tables (tables full of keyboard shortcuts), HTML pages, WAV files etc. but I think these are the most useful. Before I wrap this up, though, there's one more very powerful feature of Windows programs I'm going to show you, and that's defining a custom resource type.




Next : Custom Resources