Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
98 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

Contents
 Resource Scripts
 Icons and Cursors
 Bitmaps
 Menus
 Custom Resources

 Printable version
 Discuss this article
 in the forums



The Series
 Beginning Windows
 Programming

 Using Resources
 in Win32 Programs

 Tracking Your
 Window/Using GDI

 Introduction
 to DirectX

 Palettes and Pixels
 in DirectDraw

 Bitmapped Graphics
 in DirectDraw

 Developing the
 Game Structure

 Basic Tile Engines
 Adding Characters
 Tips and Tricks

Custom Resources

The standard Windows resources are those which have special functions for loading and handling them, but they are not the only types you can use. Resources can be any data you want them to be! Working with custom resources requires a little more work since you must locate and read the resource data manually, but it's not too bad. The script file entry for a custom type follows the basic format you're already used to:

[identifier] [resource type name] [filename]

The resource type name is a string that defines your custom resource, and can be whatever you want. For the purposes of this example, let's say you want to include a data file called p1config.dat that contains information necessary to initialize a character in a game program. We'll call the custom resource type CHARCONFIG. With that in mind, here's an example of what the script file entry might look like for your data file:

DATA_PLAYERINIT CHARCONFIG p1config.dat

Pretty simple, hey? Now that you've included your file, there are three steps you must take in order to retrieve a pointer to the resource data. Each involves calling a function we haven't talked about yet, so let's go through them one at a time. The first thing you must do is to find the resource with a call to FindResource(). Here's the prototype:

HRSRC FindResource( HMODULE hModule, // module handle LPCTSTR lpName, // pointer to resource name LPCTSTR lpType // pointer to resource type );

The return value is a handle to the resource's information block, or NULL if the function fails. The parameters are as follows:

HMODULE hModule: The HMODULE data type is simply an HINSTANCE. Don't ask me why they felt they needed another name for it, but you should simply pass the instance of your application. You don't even need a typecast because the data types are exactly the same.

LPCTSTR lpName: This is the resource identifier. Remember to use MAKEINTRESOURCE() on this one if you're using numeric constants to define your resources.

LPCTSTR lpType: This is the resource type, so pass the string you used to define your resource type. In our case, this is CHARCONFIG.

A sample function call looks like this:

HRSRC hRsrc = FindResource(hinstance, MAKEINTRESOURCE(DATA_PLAYERINIT), "CHARCONFIG");

This is a handle to the info block the resource resides in. The next step to getting a pointer to the data is to take this handle and pass it to LoadResource() to actually load the data. This yields a handle to the resource itself. Here is the function prototype:

HGLOBAL LoadResource( HMODULE hModule, // resource-module handle HRSRC hResInfo // resource handle );

The return type, HGLOBAL, is a pretty general handle type, as opposed to the other load functions we've covered, which returned specific handle types like HBITMAP or HICON. If the function fails, this value will be NULL. The parameters are straightforward:

HMODULE hModule: Again, simply the application instance.

HRSRC hResInfo: Pass the handle that was returned by FindResource().

Now that you have a handle to the resource, you can finally get a pointer to the data that was in the resource file you included. This is achieved with a call to LockResource(), shown here:

LPVOID LockResource(HGLOBAL hResData);

Simply pass the handle that was returned by LoadResource(). If the return value is NULL, the function call failed. If not, you've got your pointer! Now you're free to do whatever you like with the data. Note that the return type is LPVOID (Windows-speak for void*), so if you want to use array notation on the pointer, you need to cast it to something like a BYTE*. Now that we've gone through all the steps, I'll show you an example of a function you might write to return a pointer to a specified resource:

UCHAR* LoadCustomResource(int resID) { HRSRC hResInfo; HGLOBAL hResource; // first find the resource info block if ((hResInfo = FindResource(hinstance, MAKEINTRESOURCE(resID), "CUSTOMRESOURCETYPE")) == NULL) return(NULL); // now get a handle to the resource if ((hResource = LoadResource(hinstance, hResInfo)) == NULL) return(NULL); // finally get and return a pointer to the resource return ((UCHAR*)LockResource(hResource)); }

Closing

Well, that about does it for resources! See, programming for Windows is fun. :) Even with all this knowledge of resources, you're still pretty limited in what you can actually get your programs to do, so next time I'll be going over some basic Windows GDI (Graphics Device Interface) functions, so you can start using all this stuff to put some demo programs together. As always, send me your comments, your ideas, your death threats:

E-mail: ironblayde@aeon-software.com
ICQ: UIN #53210499

Farewell everyone, until we meet again...