Hello, I am an Engineering Manager at Facebook with 13+ years in Ad Technology, Natural Language Processing and Data mining. (Learn More)
by Pravin Paratey

Lesson 3 - Resources - Icons, Dialogs and Menus

In this lesson we’ll take a look at Windows Resources. You’ll learn to add an icon to your application, add a menu, and version information. You’ll also learn to include a very important kind of resource - the Dialog resource.

Resources

Resources are data that you can add to the applications executable file (Read more on msdn). Resources can be:

  • standard - icon, cursor, menu, dialog box, bitmap, enhanced metafile, font, accelerator table, message-table entry, string-table entry, or version.
  • custom - any kind of data that doesn’t fall into the previous category (for example a mp3 file or a dictionary database).

Add two new files to your project. Name them resource.h and resource.rc. resource.rc will contain the resource definitions and resource.h will define constants.

Adding an application icon

When Windows Explorer has to draw an icon for an .exe file, it looks for the first icon in the executable resource. What this means is, you must number the application icon with the lowest number so that it is found first.

Lets call our application icon IDI_APP_ICON. We give it the lowest possible number 1. Add the following code to the respective files:

/* resource.h
 * 
 * DrawLite - Windows Programming Tutorial
 * by Pravin Paratey (March 31, 2007)
 * http://pravin.insanityebegins.com/win32
 *
 * Source released under
 * Creative Commons Attribution-Noncommercial-No Derivative Works 3.0
 * http://creativecommons.org/licenses/by-nc-nd/3.0/
 */

#define IDI_APP_ICON    1
/* resource.rc 
 *
 * DrawLite - Windows Programming Tutorial
 * by Pravin Paratey (March 31, 2007)
 *
 * Source released under
 * Creative Commons Attribution-Noncommercial-No Derivative Works 3.0
 * http://creativecommons.org/licenses/by-nc-nd/3.0/
 */

#include 
#include "resource.h"

IDI_APP_ICON   ICON    DISCARDABLE "res\\draw.ico"


Download [draw.ico](https://bitbucket.org/pravin/win32-programming/raw/2543e47549df/res/draw.ico) and place it in the a folder called `res`. This folder will contain all our resource files (*.bmp, *.ico, etc). Our folder structure will now resemble:

./ +-- DrawLite.cbp
   +-- DrawLite.layout
   +-- ./bin/ +- DrawLite.exe
              +- DrawLite.exe.Manifest
              +- (Other binaries)
   +-- ./res/ +- draw.ico
   +- main.cpp
   +- MainWindow.cpp
   +- MainWindow.h
   +- resource.h
   +- resource.rc
Press Ctrl+F9 to build your project. If you go the bin folder now, you will see that the icon has changed. However, running the application does not show the icon in the top left corner. This is fixed by changing lines **28** and **33** of `MainWindow.cpp` as follows: ~~~ m_wndClass.hInstance = hInstance; // Instance of the application m_wndClass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); // Class Icon m_wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); // Class cursor m_wndClass.hbrBackground = (HBRUSH) (COLOR_WINDOW); // Background brush m_wndClass.lpszMenuName = NULL; // Menu Resource m_wndClass.lpszClassName = m_szClassName; // Name of this class m_wndClass.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); // Small icon for this class ~~~ {: class="prettyprint linenums:27"} You'll also have to add `#include "resource.h"` to `MainWindow.cpp` before hitting build. What happens if the top level windows' class icon isn't the lowest numbered icon? Try it. You'll see something odd. Explorer displays one icon and the top left corner of your application displays another icon. ## Adding an About dialog Let's add an About box to our app. The first thing we need to do, is to define a dialog resource. Edit `resource.rc` and add: ~~~ cpp IDI_APP_ICON ICON DISCARDABLE "res\\draw.ico" // About window IDD_ABOUT DIALOG DISCARDABLE 32, 32, 180, 100 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "About DrawLite" FONT 8, "MS Sans Serif" BEGIN CTEXT "DrawLite v0.1", IDC_STATIC, 40, 12, 100, 8 DEFPUSHBUTTON "&Ok", IDOK, 66, 80, 50, 14 CTEXT "A drawing application for windows", IDC_STATIC, 7, 52, 166, 8 END ~~~ {: class="prettyprint linenums:13"} We'll have to define `IDD_ABOUT` and `IDC_STATIC`. We'll arbitrarily assign them numbers: ~~~ cpp #define IDI_APP_ICON 1 #define IDD_ABOUT 100 #define IDC_STATIC 101 ~~~ {: class="prettyprint linenums:10"} Next, lets add code to handle the About Dialog. Create two files `AboutDialog.cpp` and `AboutDialog.h` with the code: ~~~ cpp /* AboutDialog.cpp * * DrawLite - Windows Programming Tutorial * by Pravin Paratey (April 22, 2007) * * Source released under * Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 * http://creativecommons.org/licenses/by-nc-nd/3.0/ */ #include #include "AboutDialog.h" #include "resource.h" AboutDialog::AboutDialog() { } AboutDialog::~AboutDialog() { } // Function: Run // Returns: Result of the DialogBox int AboutDialog::Run(HINSTANCE hInstance, HWND hParent) { int retval = DialogBox( hInstance, MAKEINTRESOURCE(IDD_ABOUT), // Dialog template hParent, // Pointer to parent hwnd DialogProc); } // Function: DialogProc // Handles the messages for the About dialog BOOL CALLBACK AboutDialog::DialogProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { int retVal = false; switch(msg) { case WM_INITDIALOG: retVal = true; break; case WM_COMMAND: if(LOWORD(wParam)== IDOK) EndDialog(hwnd, TRUE); break; case WM_CLOSE: EndDialog(hwnd, TRUE); break; } return retVal; } ~~~ {: class="prettyprint linenums:1"}
/* AboutDialog.h 
 *
 * DrawLite - Windows Programming Tutorial
 * by Pravin Paratey (April 22, 2007)
 *
 * Source released under
 * Creative Commons Attribution-Noncommercial-No Derivative Works 3.0
 * http://creativecommons.org/licenses/by-nc-nd/3.0/
 */

#include 
#include "resource.h"

// Class: AboutDialog
// Draws the About Dialog
class AboutDialog
{
public:
    AboutDialog();
    ~AboutDialog();
    static BOOL CALLBACK DialogProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
    int Run(HINSTANCE hInstance, HWND hParent);

private:
    HWND m_hwnd;
};


Hit Ctrl+F9 to build. You should get no errors. We haven't added code to display the About box yet, so that's what we'll do now:

    case WM_DESTROY:
        PostQuitMessage (0);
        break;
    case WM_LBUTTONDOWN:
        AboutDialog* dlg = new AboutDialog();
        dlg->Run(m_hInstance, hwnd);
        delete dlg; dlg = NULL;
        break;
    default:
        return DefWindowProc (hwnd, msg, wParam, lParam);
Hit F9 to build and run. Clicking anywhere on the window should cause the About Dialog to pop up.
3:2
Good job! You're almost done for today. Next, we'll learn to add menus and wrap up by adding version information to our project. ## Menus Adding static menus is deceptively simple. All you have to do is define a Menu structure in `resource.rc` like so:
IDM_MAINMENU MENU DISCARDABLE
BEGIN
    POPUP "&File"
    BEGIN
        MENUITEM "&New\tCtrl+N", IDM_FILE_NEW
		MENUITEM "&Open\tCtrl+O", IDM_FILE_OPEN
		MENUITEM "&Save\tCtrl+S", IDM_FILE_SAVE
		MENUITEM SEPARATOR
        MENUITEM "E&xit", IDM_FILE_EXIT
    END
    POPUP "&Help"
    BEGIN
        MENUITEM "&About", IDM_HELP_ABOUT
    END
END
#define IDC_STATIC  101
#define IDM_MAINMENU    200
#define IDM_FILE_NEW    201
#define IDM_FILE_OPEN   203
#define IDM_FILE_SAVE   204
#define IDM_FILE_EXIT   205
#define IDM_HELP_ABOUT  206
And then, change line 32 in `MainWindow.cpp` to:
    m_wndClass.hbrBackground = (HBRUSH) (COLOR_WINDOW); // Background brush
    m_wndClass.lpszMenuName = MAKEINTRESOURCE(IDM_MAINMENU); // Menu Resource
    m_wndClass.lpszClassName = m_szClassName; // Name of this class
And tada!
![3:4](/img/win32/3-4.png)
## Handling user input When a menu item is clicked, a `WM_COMMAND` message is sent to our application. The `WM_COMMAND` message looks like:
wNotifyCode = HIWORD(wParam); // notification code
wID = LOWORD(wParam); // item, control, or accelerator identifier
hwndCtl = (HWND) lParam; // handle of control
- **wNotifyCode:** Value of the high-order word of wParam. Specifies the notification code if the message is from a control. If the message is from an accelerator, this parameter is 1. If the message is from a menu, this parameter is 0. - **wID:** Value of the low-order word of wParam. Specifies the identifier of the menu item, control, or accelerator. - **hwndCtl:** Value of lParam. Identifies the control sending the message if the message is from a control. Otherwise, this parameter is NULL. While we could work with `wParam` and `lParam` ourselves, Windows provides a better mechanism for handling `WM_` messages - through the `HANDLE_WM_` macros. They are defined in `windowsx.h`. For `WM_COMMAND`, we use the `HANDLE_WM_COMMAND` macro defined as,
HANDLE_WM_COMMAND(HWND hwnd, WPARAM wParam, LPARAM lParam,
    (void *)OnCommand (HWND hwnd, int id, HWND hCtl, UINT codeNotify))
Enough of that. Lets code:
#include 
#include 
#include "MainWindow.h"


    static LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
    static void OnCommand(HWND hwnd, int id, HWND hCtl, UINT codeNotify);
    bool Run(int nCmdShow);
    case WM_DESTROY:
        PostQuitMessage (0);
        break;
    case WM_COMMAND:
        HANDLE_WM_COMMAND(hwnd, wParam, lParam, OnCommand);
        break;
    default:
// Function: OnCommand
// Handles WM_COMMAND messages (Menu, toolbar, etc)
void MainWindow::OnCommand(HWND hwnd, int id, HWND hCtl, UINT codeNotify)
{
    switch(id)
    {
    case IDM_FILE_EXIT:
        PostQuitMessage(0);
        break;
    case IDM_HELP_ABOUT:
        AboutDialog* dlg = new AboutDialog();
        dlg->Run(m_hInstance, hwnd);
        delete dlg; dlg = NULL;
        break;
    }
}
Hit F9. Selecting _Help » About_ should now pop up the About Dialog while _File » Exit_ should quit the app. ## Version Info This adds version info to your application. Read more about it [here](http://msdn2.microsoft.com/en-us/library/aa381058.aspx). In short, it lets us get to: ![3:5](/img/win32/3-5.png)
![3:6](/img/win32/3-6.png) Adding version info involves editing the `resource.rc` file and adding:
VS_VERSION_INFO VERSIONINFO
 FILEVERSION 1,0,0,1
 PRODUCTVERSION 1,0,0,1
 FILEFLAGSMASK VS_FF_PRERELEASE // Which bits are to be taken
 FILEFLAGS VS_FF_PRERELEASE // This is a pre-release version
 FILEOS VOS__WINDOWS32 // Built for Windows 32 bit OS
 FILETYPE VFT_APP // Type of this is Application
 FILESUBTYPE 0x0L // 0
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "040904B0"
        BEGIN
            VALUE "CompanyName", "Pravin Paratey\0"
            VALUE "FileDescription", "Windows Drawing Application\0"
            VALUE "FileVersion", "1, 0, 0, 1\0"
            VALUE "InternalName", "DrawLite\0"
            VALUE "LegalCopyright", "Copyright (C) 2007\0"
            VALUE "LegalTrademarks", "\0"
            VALUE "OriginalFilename", "DrawLite.exe\0"
            VALUE "ProductName", "DrawLite\0"
            VALUE "ProductVersion", "1, 0, 0, 1\0"
        END
    END
END
And that ends our lesson for today. To recap, we learnt about resources. We started off by adding an icon to our app. We followed that by adding an About dialog and a working Menu. In the next lesson, we'll take a break from win32 programming and learn about managing our code better through auto-documentation systems and code versioning. - [Previous Lesson](/posts/win32-lesson2) - [Next Lesson](/posts/win32-lesson4)