The format of icon resources

Raymond Chen


It’s been a long time since my last entry in the continuing
sporadic series on resources formats.
Today we’ll look at icons.

Recall that an icon file

consists of two parts
an icon directory
(consisting of an icon directory header followed by a number of
icon directory entries),
and then the icon images themselves.

When an icon is stored in resources, each of those parts gets its own
resource entry.

The icon directory (the header plus the directory entries)
is stored as a resource of type
The format of the icon directory in resources is slightly different
from the format on disk:

typedef struct GRPICONDIR
    WORD idReserved;
    WORD idType;
    WORD idCount;
    GRPICONDIRENTRY idEntries[];
typedef struct GRPICONDIRENTRY
    BYTE  bWidth;
    BYTE  bHeight;
    BYTE  bColorCount;
    BYTE  bReserved;
    WORD  wPlanes;
    WORD  wBitCount;
    DWORD dwBytesInRes;
    WORD  nId;

All the members mean the same thing as in the corresponding
ICONDIR and IconDirectoryEntry
structures, except for that mysterious nId
(which replaces the dwImageOffset from the
To unravel that mystery, we need to look at where
the rest of the icon file went.

In the icon file format,
the dwImageOffset represented the location
of the icon bitmap within the file.
When the icon file is converted to a resource,
each icon bitmap is split off into its own resource
of type RT_ICON.
The resource compiler auto-assigns the resource IDs,
and it is those resource IDs that are stored in the
nId member.

For example, suppose you have an icon file with four
In your resource file you say

42 ICON myicon.ico

The resource compiler breaks the file into five resources:

Resource typeResource IdContents
RT_ICON124Pixels for image 0
RT_ICON125Pixels for image 1
RT_ICON126Pixels for image 2
RT_ICON127Pixels for image 3

Why does Windows break the resources into five pieces instead of just
dumping them all inside one giant resource?


how 16-bit Windows managed resources
Back in 16-bit Windows, a resource was a handle into a table,
and obtaining the bits of the resource involved allocating memory and
loading it from the disk.
Recall also that 16-bit Windows operated under tight memory constraints,
so you didn’t want to load anything into memory unless you really
needed it.

Therefore, looking up an icon in 16-bit Windows went like this:

  • Find the icon group resource, load it, and lock it.
  • Study it to decide which icon image is best.
  • Unlock and free the icon group resource since we don’t need
    it any more.

  • Find and load the icon image resource for the one you chose.
  • Return that handle as the icon handle.

Observe that once we decide which icon image we want,
the only memory consumed is the memory for that specific image.
We never load the images we don’t need.

Drawing an icon went like this:

  • Lock the icon handle to get access to the pixels.
  • Draw the icon.
  • Unlock the icon handle.

Since icons were usually marked discardable,
they could get evicted from memory if necessary,
and they would get reloaded the next time you tried to draw them.

Although Win32 does not follow the same memory management model
for resources as 16-bit Windows,
it preserved the programming model
(find, load, lock)
to make it easier to port programs from 16-bit Windows to 32-bit Windows.
And in order not to break code which loaded icons from resources directly
(say, because they wanted to replace the icon selection algorithm),
the breakdown of an icon file into a directory + images was also preserved.

You now know enough to solve this customer’s problem:

I have an icon in a resource DLL, and I need to pass its raw data
to another component.
However, the number of bytes reported by
Size­Of­Resource is only 48 instead of 5KB
which is the amount actually stored in the resource DLL.
I triple-checked the resource DLL and I’m sure I’m looking at the
right icon resource.

Here is my code:

HRSRC hrsrcIcon = FindResource(hResources,
DWORD cbIcon = SizeofResource(hResources, hrsrcIcon);
HGLOBAL hIcon = LoadResource(hResources, hrsrcIcon);
void *lpIcon = LockResource(hIcon);
Raymond Chen
Raymond Chen

Follow Raymond