rss
logo

I provide consulting and custom development for Natural Language Processing, Information Extraction and Search solutions.Self Picture


 learn more   get in touch 

Logo - I Build Search
Jul 26
2008

Lesson 3 – Resources: Icons, Dialogs and Menus digg

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.

I forgot to set the Project output path earlier, so we’ll do it now. Go to Project » Properties and add /bin/ as indicated in the figure below:

Changing project output path

This will create all binaries inside the bin folder.

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
1
2
3
4
5
6
7
8
9
10
/* DrawLite - Windows Programming Tutorial
 * by Pravin Paratey (March 31, 2007)
 * http://www.dustyant.com/wintut
 *
 * 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
1
2
3
4
5
6
7
8
9
10
11
12
/* 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 <windows.h>
#include "resource.h"
 
IDI_APP_ICON   ICON    DISCARDABLE "res\\draw.ico"

Download 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
   +-- ./src/ +- 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:

MainWindow.cpp
27
28
29
30
31
32
33
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

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:

resource.rc
13
14
15
16
17
18
19
20
21
22
23
24
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

Numeric Identifiers

The symbols IDI_APP_ICON and IDD_ABOUT are called numeric indentifiers. They’re used in place of numbers simply because its easier to remember IDD_ABOUT rather than 100.

Terms like STYLE, CAPTION and BEGIN are keywords. To learn more about them, look up your Win32 docs or MSDN under Resources.

Okaay. But what’s with the IDD?

Right. Long back, people used the Hungarian notation at Microsoft (perhaps they still do), and so most of the example code was written in Hungarian. I guess I caught the habit. I personally find it rather convenient.

In our code, IDD_ABOUT would mean ID for a Dialog named ABOUT. The idea is that you can learn about the variable (or constant) by merely looking at it.

We’ll have to define IDD_ABOUT and IDC_STATIC. We’ll arbitrarily assign them numbers:

resource.h
10
11
12
13
#define IDI_APP_ICON    1
 
#define IDD_ABOUT   100
#define IDC_STATIC  101

Next, lets add code to handle the About Dialog. Create two files AboutDialog.cpp and AboutDialog.h with the code:

AboutDialog.cpp
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/* 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 <windows.h>
#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;
}
AboutDialog.h
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/* 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 <windows.h>
#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:

MainWindow.cpp
50
51
52
53
54
55
56
57
58
59
    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.

Exercise

Add an icon to the About Dialog:

3:3

Hint: ICON IDI_APP_ICON, IDC_STATIC, 80, 28, 32, 32

Menus

Adding static menus is deceptively simple. All you have to do is define a Menu structure like so:

resource.rc
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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
resource.h
12
13
14
15
16
17
18
#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:

MainWindow.cpp
31
32
33
    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

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))

windowsx.h

This header files contains many macros designed to make coding easier. Take a look at it. Some of the stuff in there is really interesting. You’ll find it in the include folder of your development environment.

Enough of that. Lets code:

MainWindow.cpp
9
10
11
#include <windows.h>
#include <windowsx.h>
#include "MainWindow.h"
53
54
55
56
57
58
59
    case WM_DESTROY:
        PostQuitMessage (0);
        break;
    case WM_COMMAND:
        HANDLE_WM_COMMAND(hwnd, wParam, lParam, OnCommand);
        break;
    default:
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// 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;
    }
}
MainWindow.h
18
19
20
    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);

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. In short, it lets us get to:

3:5
3:6

Adding version info involves editing the resource.rc file and adding:

resource.rc
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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.

5 Responses (rss) (trackback)

#1

bungy_serbia

December 13th, 2008 at 4:08 pm

invalid use of member `MainWindow::m_hInstance’ in static member function

#2

w359

January 5th, 2009 at 3:18 am

I am also getting:
MainWindow.h|13|error: invalid use of member `MainWindow::m_hInstance’ in static member function
MainWindow.cpp|48|error: from this location

when adding the AboutDialog. What’s wrong???

#3

bascarane

February 3rd, 2009 at 4:04 pm

I also get the same error. Seems that the member variables cannot be used in static function. Is there another way to acheive this? may be create another function and call it!

#4

bascarane

February 3rd, 2009 at 5:10 pm

I found a workaround for the error, “MainWindow.h|13|error: invalid use of member `MainWindow::m_hInstance’”.

try to add a global variable in mainWindow.hpp as follows:

static HINSTANCE g_instance;

then in mainWindow.cpp, initialise the global variable with the instance value as follows:

MainWindow::MainWindow(HINSTANCE hInstance)
{
g_instance = hInstance;
m_hInstance = hInstance; // Save Instance handle

m_wndClass.cbSize = sizeof(WNDCLASSEX); // Must always be sizeof(WNDCLASSEX)

and then finally, use this value instead of m_hInstance as follows:

case WM_LBUTTONDOWN:
AboutDialog* dlg = new AboutDialog();
dlg->Run(m_hInstance, hwnd);
delete dlg; dlg = NULL;
break;

this should solve the problem!

#5

Pravin Paratey

March 28th, 2009 at 12:14 am

Updated the code. You’ll have to change

HINSTANCE m_hInstance;

to

static HINSTANCE m_hInstance;

in MainWindow.h

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">

Latest Articles

Feb
19

Join a list of integers in Python

How do you run a string join on a list of integers in Python? After googling for about 10 mins, I gave up and did this. I am sure there is a better way of doing it! [Read More]
Jan
21

Writing a spider in 10 mins using Scrapy

I came across Scrapy a few days back and have grown to really love it. This tutorial will illustrate how you can write a simple spider using Scrapy to scrape data off Paul Smith. All this in 10 minutes. [Read More]

Featured Projects

Indic to English Transliterator

Indic to English Transliterator

Transliteration is the process of converting a word from one language to another while retaining its phonetic characteristics. This application lets you convert a word from any major Indian language (currently supports Hindi, Marathi, Sanskrit and Bengali) to English.

[Read More]

Document Tagger

Document Tagger

DocTagger lets you automatically classify text documents. Use this as a starting point to write apps that can sort through volumes of unorganized data.

[Read More]

This page and its contents are copyright © 2010, Pravin Paratey.