Topic : Using Resources in Win32 Programs
Author : Joseph Farrell
Page : << Previous 2  Next >>
Go to page :

files include a macro that changes an integer to a form compatible with this parameter called MAKEINTRESOURCE().
As an example, let's look at the line that sets the icon to represent the program. Suppose your resource script file looks like this:
#include "resource.h"

ICON_MAIN     ICON    myicon.ico
If the identifiers ICON_MAIN and CURSOR_ARROW do not have matching #define statements somewhere in resource.h, then you would pass the corresponding string to the appropriate resource-loading function, like this:
sampleClass.hIcon = LoadIcon(hinstance, "ICON_MAIN");
Now let's say that resource.h contains a few #define directives:
#define ICON_MAIN        1000
#define CURSOR_ARROW     2000

Now you have to use the MAKEINTRESOURCE() macro to turn the numerical identifier into something of type LPCTSTR. This gives you a little more ease of flexibility in loading resources. Any of the following calls would be correct:
sampleClass.hIcon = LoadIcon(hinstance, MAKEINTRESOURCE(ICON_MAIN));
sampleClass.hIcon = LoadIcon(hinstance, MAKEINTRESOURCE(1000));
int ident = 1000;
sampleClass.hIcon = LoadIcon(hinstance, MAKEINTRESOURCE(ident));

That's about all you need to know about including icons and cursors in your programs, but I'll mention one more thing while we're on the topic. If you want to set a cursor sometime other than at the beginning of the program, there's a simple Windows function you can use to accomplish this:
HCURSOR SetCursor(HCURSOR hCursor);
The one parameter is the handle you get by calling LoadCursor(), and the handle that is returned is a handle to the previous cursor. If no previous cursor was set, the return value is NULL. Relatively painless, wouldn't you say? Let's move on to something a bit more interesting.

Including bitmap resources is probably the easiest way to add images to your program. Bitmaps are native to Windows and so there are functions included to deal with loading and manipulating them, but remember, if you include too many, you'll end up with an enormous .EXE file. In any case, you include bitmaps in your resource script file in basically the same way you handle icons and cursors:
[identifier]  BITMAP  [filename]
There is a function called LoadBitmap() that is analagous to LoadCursor() and LoadIcon(); it is used to retrieve a handle to a bitmap, but since I haven't talked about graphics yet, I won't describe this function here. You can probably guess exactly how it works, but once you have a handle to a bitmap, what would you do with it? More to come on that in the future, don't worry! For now, I just wanted to show you how to include a bitmap resource. Now let's look at something you can use right away.

String Tables
The string table is one of my favorite resource types. It's exactly what you're thinking: a giant table full of strings. There are any number of purposes for using a string table. You can use it to store data filenames, character dialogue for a game, message-box text, text for menus that are generated by the program, anything you want. Creating a string table in your script file is easy. Here's what it looks like:
// entries go here

An entry in a string table consists of a number to identify the string, followed by a comma, then the string itself, enclosed in double quotation marks. The strings in a string table can include escape sequences like \n or \t. Note that the string table itself does not have an identifier, so each program you write can include only one string table. A simple string table might look something like this:
// program information
1, "3D Space Game v1.0"
2, "Written by The Masked Coder"
3, "(C) 2000 WienerDog Software"

To load a string from your program's string table, you use the -- you guessed it -- LoadString() function. Here is its prototype:

int LoadString(
    HINSTANCE hInstance,  // handle to module containing string resource
    UINT uID,             // resource identifier
    LPTSTR lpBuffer,      // pointer to buffer for resource
    int nBufferMax        // size of buffer

The integer returned by the function is the number of characters, excluding the terminating null character, that were successfully copied into the buffer. This corresponds to the length of the string. If you load a blank string, or if the function fails, the return value is 0. Take a look at the parameters:
HINSTANCE hInstance: Once again, this is the instance of your application.
UINT uID: This is the number that identifies the particular string you want to load.
LPTSTR lpBuffer: This is a pointer to the location you want the string copied to.
int nBufferMax: This is the size of the buffer in bytes. If the string to be loaded is longer than the buffer can hold, the string is truncated and null-terminated.
For example, to load WienerDog Software's copyright message, the following code would be used:
char buffer[80];
LoadString(hinstance, 3, buffer, sizeof(buffer));

Even though the declaration of a string table in your script file has to use numbers and not identifiers, I usually #define a number of string table constants in one of my header files when using a string table. For instance, to accompany the string table above, I might have a line like:
Your code will be much easier to read if you have LoadString() calls that use readable constants for the uID parameter, rather than just having the index numbers. This doesn't mean you should have a constant for every string table entry; that would take ages if you have a large string table. Usually I like to use one #define per "section" of the string table. For instance, ST_FILENAMES for the first index where filenames are stored, ST_DIALOGUE for the first index of the character dialog strings, etc.

This 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:

[identifier] MENU
    POPUP [menu name]
        MENUITEM [item name], [identifier]

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:

    POPUP "&File"
        MENUITEM "&New",        MENUID_NEW
        MENUITEM "&Open...",    MENUID_OPEN
        MENUITEM "&Save",       MENUID_SAVE
        MENUITEM "Save &As...", MENUID_SAVEAS
        MENUITEM "E&xit",       MENUID_EXIT
    POPUP "&Help"
        MENUITEM "&Contents",   MENUID_CONTENTS
        MENUITEM "&Index...",   MENUID_INDEX
        MENUITEM "&About",      MENUID_ABOUT

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:

HMENU LoadMenu(
    HINSTANCE hInstance,

Page : << Previous 2  Next >>