Introduction
In this tutorial, I will show you how to replace an application’s icon with a given .ICO file. To keep things simple, you will use an .ICO file containing a single 32×32 image (meaning, I will give the complete source code to accomplish this), but I will provide the general theory to enable you to extend the example to support all types of icons.
There are a lot of icon editors around, so use your favorite one to create a 32×32, 256-color icon.
First Things First: the Structure of an .ICO File on Disk
Icon files have the following structure:
ICON HEADER: WORD Reserved - reserved WORD Type - 1 means icon, 2 means cursor WORD ImageCount - number of images stored inside the file ICON DIRECTORY ENTRY - there are ImageCount directory entries BYTE Width - width of image BYTE Height - height of image BYTE Colors - 0 means 256 or more BYTE Reserved - reserved WORD Planes - number of planes WORD BitsPerPixel - bits per pixel DWORD ImageSize - size of image data DWORD ImageOffset - offset of image data inside file ICON DIRECTORY ENTRY ... ICON DIRECTORY ENTRY ICON IMAGE - the actual image data (which has the structure of ICON IMAGE a bitmap) found at the location specified by ImageOffset ... ICON IMAGE
As you can see, a .ICO file can contain more than one image.
The Secret
It isn’t enough to read a .ICO file into memory and insert it as a RC_ICON resource because the resulting resource will be corrupted. In resources, icons are split into several RC_ICON resources and a RC_GROUP_ICON. A RC_ICON entry is basically the above ICON IMAGE. RC_GROUP_ICON contains the ICON HEADER and DIRECTORY ENTRIES with a single modification: The DWORD ImageOffset becomes WORD ResourceID. That is because the actual image data is no longer following its header, so it can be identified by its resource ID.
An application can have several icons contained inside its resources. Usually, the displayed icon has the resource ID equal to 1, but this is not necessary. Windows chooses which icon to display based on the RC_GROUP_ICON resource named ‘MAINICON’. You can use a tool such as PE Explorer to take a look at the resources of compiled executable modules (.EXE and .DLL files).
What You Will Do
You will load the ICON IMAGE of an .ICO file into a buffer, create a structure containing RC_GROUP_ICON resource data, and inject both of these into a given executable file.
Here are some structure declarations:
// Make sure structures are packed the same way as Windows packs them #pragma pack(push, 2) typedef struct // This is the Directory Entry stored in resources { BYTE Width; BYTE Height; BYTE Colors; BYTE Reserved; WORD Planes; WORD BitsPerPixel; DWORD ImageSize; WORD ResourceID } IconDirResEntry, *PIconDirResEntry; typedef struct // This is the actual RT_GROUP_ICON structure { WORD Reserved; WORD ResourceType; WORD ImageCount; PIconDirResEntry Enries; // The number of entries is ImageCount } GroupIcon; // Restore default packing #pragma pack(pop)
For the example, you can declare a simpler structure because you will use an .ICO file containing only one image. You will combine the header and the directory entry into a single structure:
#pragma pack(push, 2) typedef struct { WORD Reserved1; // reserved, must be 0 WORD ResourceType; // type is 1 for icons WORD ImageCount; // number of icons in structure (1) BYTE Width; // icon width (32) BYTE Height; // icon height (32) BYTE Colors; // colors (0 means more than 8 bits per pixel) BYTE Reserved2; // reserved, must be 0 WORD Planes; // color planes WORD BitsPerPixel; // bit depth DWORD ImageSize; // size of structure WORD ResourceID; // resource ID } GROUPICON; #pragma pack(pop)
The last structure is the RC_GROUP_ICON resource you will inject into the executable.
Using WinAPI
You will update the resources using WinAPI’s BeginUpdateResource, UpdateResource, and EndUpdateResource. Declare a InjectMainIcon method that will receive the filename of an application and the filename of an icon.
A quick overview: BeginUpdateResource receives the name of an executable module and a boolean parameter which, if set to TRUE, will remove all resources found in that executable (you don’t want that).
UpdateResource receives the handle of the module in which to do the update (the handle returned by BeginUpdateResource). It receives the type name of the resource and the name of the resource for which you can use MAKEINTRESOURCE. (For example, type is RC_ICON and name is MAKEINTRESOURCE(1). This inserts an icon resource giving it the ID 1.) It also receives the language identifier. You will use MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)to set the resource’s language to default. Finally, UpdateResource receives a pointer to the buffer containing the resource and the length of that buffer.
The last method you will use is EndUpdateResource. It receives the handle provided by BeginUpdateResource and a boolean parameter that, if set to TRUE, discards all changes made to the resources.
Out of the Windows SDK Documentation:
HANDLE BeginUpdateResource( LPCTSTR pFileName, // pointer to file in which to update // resources BOOL bDeleteExistingResources // deletion option ); BOOL UpdateResource( HANDLE hUpdate, // update-file handle LPCTSTR lpType, // address of resource type to update LPCTSTR lpName, // address of resource name to update WORD wLanguage, // language identifier of resource LPVOID lpData, // address of resource data DWORD cbData // length of resource data, in bytes ); BOOL EndUpdateResource( HANDLE hUpdate, // update-file handle BOOL fDiscard // write flag );