Home Step1 Step2 Step3 Step4 Step5
So you want to be a programmer... Part 2
Making a Great Circle Map program for Windows.


Adding a menu

A menu is a nice way to communicate with the user.

You have to add 2 files to you project. One file is called Step2.rc . The rc means "resource". Here you add your menuitems, dialogs, accelerator keys and stringtables etc. The other is a header file. It is handy when you need to share necessary information among source files. Here we use the file resource.h to define constants used in Step2.rc.

Things changed from Step1 on Yellow background.

Source for step2 here.

#include <windows.h>
#include "resource.h"


/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
void HandleMenu (HWND hwnd, UINT Command);

/*  Make the class name into a global variable  */
char szClassName[ ] = "WindowsApp";
HWND hWndMain; /* This is the handle for our window - Moved from WinMain*/


int WINAPI 
WinMain (HINSTANCE hThisInstance, 
        HINSTANCE hPrevInstance, 
        LPSTR lpszArgument, 
        int cmdShow)
{
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */
    HMENU hMenu;             /* Handle for the menu */
    HACCEL hAccKeys;

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);
    wincl.hIcon = LoadIcon (hThisInstance, MAKEINTRESOURCE (IDI_GCM)); // Get the icon from the resource
    wincl.hIconSm = LoadIcon (hThisInstance, MAKEINTRESOURCE (IDI_GCM));
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default color as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hWndMain = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           "GcmWin",            /* Title Text */
           WS_OVERLAPPEDWINDOW, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           544,                 /* The programs width */
           375,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

    /* Load the menu */
      hMenu = LoadMenu (hThisInstance, "MAINMENU");
      SetMenu (hWndMain, hMenu);

    /* Load accelerator keys (ex. Ctrl-N) */
    hAccKeys = LoadAccelerators (hThisInstance, "IDR_ACCKEYS");

    /* Make the window visible on the screen */
    ShowWindow (hWndMain, cmdShow);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
	if (!TranslateAccelerator(hWndMain, hAccKeys, &messages))
	{
            TranslateMessage(&messages);
            /* Send message to WindowProcedure */
            DispatchMessage(&messages);
         }
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK
WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_COMMAND:
            HandleMenu (hwnd, LOWORD (wParam)); // Handle messages in a separate function
          break;

        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

void HandleMenu (HWND hwnd, UINT Command)
{

    switch (Command)
    {
        case IDM_NEW:
      	  MessageBox (NULL, "New Map", "Menu", MB_OK | MB_ICONINFORMATION);
        break;

        case IDM_SAVEBMP:
      	  MessageBox (NULL, "Save Bitmap", "Menu", MB_OK | MB_ICONINFORMATION);
        break;

        case IDM_SAVEBMPAS:
      	  MessageBox (NULL, "Save Bitmap AS", "Menu", MB_OK | MB_ICONINFORMATION);
        break;

        case IDM_OPTIONS:
      	  MessageBox (NULL, "Options", "Menu", MB_OK | MB_ICONINFORMATION);
        break;

        case IDM_DXPOS:
      	  MessageBox (NULL, "DxPos", "Menu", MB_OK | MB_ICONINFORMATION);
        break;

        case IDM_ABOUT:
      	  MessageBox (NULL, "About", "Menu", MB_OK | MB_ICONINFORMATION);
        break;

        case IDM_HELP:
      	  MessageBox (NULL, "Help", "Menu", MB_OK | MB_ICONINFORMATION);
        break;

        case IDM_EXIT:
          PostQuitMessage (0);
        break;
    }
  return;
}



 Well, a little bit nicer. Menu works ok and launches a messagebox indicating wich menu you clicked. The icon and Window name is changed.

Below is the code for the new files.

resource.h

#define	IDB_TOOL 60
#define	IDI_GCM	120

#define	IDR_TOOLB	800
#define	IDR_STATUS	900

#define	IDM_NEW	        10001
#define	IDM_SAVEBMP     10002
#define	IDM_SAVEBMPAS   10003
#define	IDM_EXIT        10005
#define	IDM_OPTIONS     10006
#define	IDM_DXPOS       10007
#define	IDM_ABOUT       10008
#define	IDM_HELP        10009

step2.rc

#include <windows.h>
#include "resource.h"

IDI_GCM  ICON "gcmw.ico"

IDR_ACCKEYS ACCELERATORS DISCARDABLE
BEGIN
    "N",            IDM_NEW,  VIRTKEY, CONTROL, NOINVERT
    "X",            IDM_EXIT, VIRTKEY, CONTROL, NOINVERT
    "H",            IDM_HELP,  VIRTKEY, CONTROL, NOINVERT
END

MAINMENU MENU
BEGIN
    POPUP "&File"
        BEGIN
        MENUITEM "&New Map  (Ctrl+N)",IDM_NEW
        MENUITEM SEPARATOR
        MENUITEM "&Save Bitmap",IDM_SAVEBMP
        MENUITEM "Save Bitmap &As",IDM_SAVEBMPAS
        MENUITEM SEPARATOR
        MENUITEM "&Exit         (Ctrl+X)",IDM_EXIT
        END
    MENUITEM "&Options",            IDM_OPTIONS
    MENUITEM "&DxPos" ,             IDM_DXPOS
    POPUP "&Help"
        BEGIN
        MENUITEM "&Help         (Ctrl+H)",           IDM_HELP
        MENUITEM SEPARATOR
        MENUITEM "About &GcmWin	",  IDM_ABOUT
        END
END



 Step 1 Step 3