MenusThis 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:
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:
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:
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:
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:
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 EventsAs 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:
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:
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:
Contents of x: 0000 0000 1111 0100 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:
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. |
|