Tricks of the Windows Game Programming Gurus:Advanced Windows Programming

All ITKnowledge Source Code Search Tips Advanced Search |

| Tricks of the Windows Game Programming Gurus by Andre LaMothe Sams, Macmillan Computer Publishing ISBN: 0672313618 Pub Date: 09/27/99

Search this book:

Previous | Table of Contents | Next

#### Loading a Menu

There are a number of ways to attach a menu to a window. You can associate a single menu with all windows in a Windows class, or you can attach different menus to each window that you create. First, let’s see how to associate a single menu with the Windows class itself.

In the definition of the Windows class, there is a line of code that defines what the menu is

    winclass.lpszMenuName = NULL;

All you need to do is assign it the name of the menu resource. Presto, that’s it! Here’s how

    winclass.lpszMenuName = "MainMenu";

And if `“MainMenu”` was a constant, you would do it this way:

    winclass.lpszMenuName = MAKEINTRESOURCE(MainMenu);

No problemo… almost. The only problem with this is that every window you create will have the same menu. To get around this, you can assign a menu to a window during creation by passing a menu handle. However, to get a menu handle, you must load the menu resource with `LoadMenu()`. Here’s its prototype(s):

    HMENU LoadMenu(HINSTANCE hInstance,// handle of application instance

     LPCTSTR lpMenuName);// menu name string or menu-resource identifier

If successful, `LoadMenu()` returns an `HMENU` handle to the menu resource, which you can then use.

Here’s the normal `CreateWindow()` call you have been making, changed to load the menu `“MainMenu”` into the menu handle parameter:

    // create the window

    if (!(hwnd = CreateWindowEx(NULL,              // extended style

                                WINDOW_CLASS_NAME, // class

                    "Sound Resource Demo", // title

                    WS_OVERLAPPEDWINDOW | WS_VISIBLE,

                     0,0,      // initial x,y

                    400,400,   // initial width, height

                    NULL,      // handle to parent

                    LoadMenu(hinstance, "MainMenu"), // handle to menu

                    hinstance, // instance of this application

                    NULL)))    // extra creation parms

    return(0);

Or if `MainMenu` was a symbolic constant, the call would look like this:

    LoadMenu(instance, MAKEINTRESOURCE(MainMenu)), // handle to menu

> Note: You may think I’m belaboring the difference between resources defined by string and by symbolic constant. However, taking into consideration that it’s the number one cause of self-mutilation among Windows programmers, I think it’s worth the extra work—don’t you?

And of course, you can have many different menus defined in your `.RC` file, and thus you can attach a different one to each window.

The final method of attaching a menu to a window is by using the `SetMenu()` function, shown here:

    BOOL SetMenu(HWND hWnd,    // handle of window to attach to

                 HMENU hMenu); // handle of menu

`SetMenu()` takes the window handle, along with the handle to the menu (retrieved from `LoadMenu()`), and simply attaches the menu to the window. The new menu will override any menu previously attached. Here’s an example listing, assuming that the Windows class defines the menu as `NULL`, as does the menu handle in the call to `CreateWindow()`:

    // first fill in the window class structure

    winclass.cbSize  = sizeof(WNDCLASSEX);

    winclass.style      = CS_DBLCLKS | CS_OWNDC |

                       CS_HREDRAW | CS_VREDRAW;

    winclass.lpfnWndProc    = WindowProc;

    winclass.cbClsExtra    = 0;

    winclass.cbWndExtra    = 0;

    winclass.hInstance    = hinstance;

    winclass.hIcon = LoadIcon(hinstance,

                           MAKEINTRESOURCE(ICON_T3DX));

    winclass.hCursor = LoadCursor(hinstance,

                          MAKEINTRESOURCE(CURSOR_CROSSHAIR));

    winclass.hbrBackground  = GetStockObject(BLACK_BRUSH);

    winclass.lpszMenuName  = NULL; // note this is null

    winclass.lpszClassName  = WINDOW_CLASS_NAME;

    winclass.hIconSm = LoadIcon(hinstance, MAKEINTRESOURCE(ICON_T3DX));

    // register the window class

    if (!RegisterClassEx(&winclass))

        return(0);

    // create the window

    if (!(hwnd = CreateWindowEx(NULL,           // extended style

                   WINDOW_CLASS_NAME, // class

                    "Menu Resource Demo", // title

                   WS_OVERLAPPEDWINDOW | WS_VISIBLE,

                   0,0,     // initial x,y

                   400,400,  // initial width, height

                   NULL,     // handle to parent

                   NULL,  // handle to menu, note it’s null

                   hinstance, // instance of this application

                   NULL)))    // extra creation parms

    return(0);

    // since the window has been created you can

    // attach a new menu at any time

    // load the menu resource

    HMENU hmenuhandle = LoadMenu(hinstance, "MainMenu");

    // attach the menu to the window

    SetMenu(hwnd, hmenuhandle);

For an example of creating the menu and attaching it to the window using the second method (that is, during the window creation call), take a look at `DEMO3_3.CPP` on the CD-ROM and the associated executable, `DEMO3_3.EXE`, which is shown running in Figure 3.10.

Figure 3.10 Running `DEMO3_3.EXE`.

The only two files of interest are the resource and header files, `DEMO3_3RES.H` and `DEMO3_3.RC.`

Contents of `DEMO3_3RES.H`:

    // defines for the top level menu FILE

    #define MENU_FILE_ID_OPEN                1000

    #define MENU_FILE_ID_CLOSE               1001

    #define MENU_FILE_ID_SAVE                1002

    #define MENU_FILE_ID_EXIT                1003

    // defines for the top level menu HELP

    #define MENU_HELP_ABOUT                  2000

Contents of `DEMO3_3.RC`:

    #include "DEMO3_3RES.H"

    MainMenu MENU DISCARDABLE

    {

    POPUP "File"

        {

        MENUITEM "Open", MENU_FILE_ID_OPEN

        MENUITEM "Close", MENU_FILE_ID_CLOSE

        MENUITEM "Save", MENU_FILE_ID_SAVE

        MENUITEM "Exit", MENU_FILE_ID_EXIT

        } // end popup

    POPUP "Help"

        {

        MENUITEM "About", MENU_HELP_ABOUT

        } // end popup

    } // end top level menu

To compile your own `DEMO3_3.CPP` executable, make sure to include

  `DEMO3_3.CPP`—The main source.
  `DEMO3_3RES.H`—The resource symbol header.
  `DEMO3_3.RC`—The resource script file.

Try playing with `DEMO3_3.EXE` and the associated source. Change the menu items, add some more menus by adding more `POPUP` blocks to the `.RC` file, and get a good feel for it. Also, try making a cascading menu tree. (Hint: Just replace `MENUITEM` with a `POPUP` for one of the `MENUITEMS` making up a menu.)

Previous | Table of Contents | Next

Copyright © Macmillan Computer Publishing, Inc.

Products | Contact Us | About Us | Privacy | Ad Info | Home
Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.