Windows allows the storage of more than just the program code in an application. Using resources, Windows allows the combinination of pieces of data with program code, which can then be loaded during runtime by the program itself.
This tutorial will cover two examples of this: Custom icons and custom cursors.
To work with resources, two files need to be created, an .rc file and a .h file. Thankfully the Visual Studio IDE does all of the dirty work, thus I won't go into any details, which could be looked up in LaMothe's book, if necessary.
To create or load an icon, right-click on "Resource files" in the "Solution Explorer" and then select "Add Resource". Everything else should then be self-explanatory.
I found a lovely image of a barking dog and added it to my project, by the name IDI_BARKING_DOG.
The resource.h looks like this:
// ICONS #define IDI_BARKING_DOG 101
Now to load an icon into an application, the newly created resouce.h file must be included into the project and then the following two lines in the window creation process must be changed:
... wc.hIcon = (HICON)LoadImage(dxApp->appInstance, MAKEINTRESOURCE(IDI_BARKING_DOG), IMAGE_ICON, LR_DEFAULTSIZE, LR_DEFAULTSIZE, LR_DEFAULTCOLOR | LR_SHARED); wc.hIconSm = (HICON)LoadImage(dxApp->appInstance, MAKEINTRESOURCE(IDI_BARKING_DOG), IMAGE_ICON, LR_DEFAULTSIZE, LR_DEFAULTSIZE, LR_DEFAULTCOLOR | LR_SHARED); ...
The LoadImage function loads an icon, cursor, or a bitmap and returns a handle to that resource:
HANDLE WINAPI LoadImage( _In_opt_ HINSTANCE hinst, _In_ LPCTSTR lpszName, _In_ UINT uType, _In_ int cxDesired, _In_ int cyDesired, _In_ UINT fuLoad );
As always, this is a handle to an instance, in this case, the handle to the module of the executable file that wants to contains the image to be loaded. We simply pass the handle to the instance of our application.
This long pointer to a constant string takes the location of the image to be loaded. The MAKEINTRESOURCE macro converts an integer value to a resource type compatible with the resource-management functions, and can be used in place of a string containing the name of the resource.
This unsigned int defines the type of the image to be loaded; it can be set to one of the following values: IMAGE_BITMAP, IMAGE_CURSOR or IMAGE_ICON.
int cxDesired and int cyDesired
Those parameters define the width and height, in pixels, of the resource to load. We simply set this to use the default size.
This unsigned int defines further behaviour of the icon to be loaded. Check the MSDN for all possible flags, in this tutorial we used LR_DEFAULTCOLOR, which simply means that the icon is not monochromatic, and LR_SHARED, which shares the image handle if the image is loaded multiple times.
Loading a custom cursor is equally simple. To create or load a cursor, right-click on "Resource files" in the "Solution Explorer" and then select "Add Resource". Everything else should then be self-explanatory.
For example, I downloaded and loaded two StarCraft related cursor resources. The resource.h file now looks like this:
// ICONS #define ID_ICON_BARKING_DOG 101 // CURSORS #define ID_CURSOR_PROTOSS 102 #define ID_CURSOR_TERRAN 103
Now to load the cursor, one line must be changed in the window definition process:
... wc.hCursor = (HCURSOR)LoadImage(dxApp->appInstance, MAKEINTRESOURCE(ID_CURSOR_TERRAN), IMAGE_CURSOR, LR_DEFAULTSIZE, LR_DEFAULTSIZE, LR_DEFAULTCOLOR | LR_SHARED); ...
Putting It All Together
For this tutorial, only the custom icon has been added to the application. You can download the source code from here.
And that's it already. Easy.
For more information on this topic, have a look at the third chapter of LaMothe's book.
The next tutorial will give a brief summary of the framework we created and an instruction on how to use it.
- Tricks of the Windows Game Programming Gurus, by André LaMothe
- Microsoft Developer Network (MSDN)