Edit

Resource Types

The following are the predefined resource types.

Constant/value Description
RT_ACCELERATOR
MAKEINTRESOURCE(9)
Accelerator table.
RT_ANICURSOR
MAKEINTRESOURCE(21)
Animated cursor.
RT_ANIICON
MAKEINTRESOURCE(22)
Animated icon.
RT_BITMAP
MAKEINTRESOURCE(2)
Bitmap resource.
RT_CURSOR
MAKEINTRESOURCE(1)
Hardware-dependent cursor resource.
RT_DIALOG
MAKEINTRESOURCE(5)
Dialog box.
RT_DLGINCLUDE
MAKEINTRESOURCE(17)
Allows a resource editing tool to associate a string with an .rc file. Typically, the string is the name of the header file that provides symbolic names. The resource compiler parses the string but otherwise ignores the value. For example,
1 DLGINCLUDE "MyFile.h"
RT_FONT
MAKEINTRESOURCE(8)
Font resource.
RT_FONTDIR
MAKEINTRESOURCE(7)
Font directory resource.
RT_GROUP_CURSOR
MAKEINTRESOURCE((ULONG_PTR)(RT_CURSOR) + 11)
Hardware-independent cursor resource.
RT_GROUP_ICON
MAKEINTRESOURCE((ULONG_PTR)(RT_ICON) + 11)
Hardware-independent icon resource.
RT_HTML
MAKEINTRESOURCE(23)
HTML resource.
RT_ICON
MAKEINTRESOURCE(3)
Hardware-dependent icon resource.
RT_MANIFEST
MAKEINTRESOURCE(24)
Side-by-Side Assembly Manifest.
RT_MENU
MAKEINTRESOURCE(4)
Menu resource.
RT_MESSAGETABLE
MAKEINTRESOURCE(11)
Message-table entry.
RT_PLUGPLAY
MAKEINTRESOURCE(19)
Plug and Play resource.
RT_RCDATA
MAKEINTRESOURCE(10)
Application-defined resource (raw data).
RT_STRING
MAKEINTRESOURCE(6)
String-table entry. See Remarks below for more info.
RT_VERSION
MAKEINTRESOURCE(16)
Version resource.
RT_VXD
MAKEINTRESOURCE(20)
VXD.

Remarks

String Table Resources

When enumerating String Table resources (type RT_STRING) with functions such as EnumResourceNamesW, the system doesn't enumerate each individual string resource ID; instead it enumerates blocks of resources. You must inspect these blocks to determine which string resource ID(s) they actually contain.

String resources are packaged into blocks, each of which contains 16 length-prefixed strings representing 16 consecutive IDs (some of which may not be used; see below). Given a string resource ID X, it will be placed in the resource block number (X \ 16) + 1 (where \ denotes integer division). Within that block, the resource can be found as the Nth entry, where N = X % 16.

The following table shows some example string resource IDs and the block number (and offset) of where they will be located:

Resource ID Block # Offset
1 (1 \ 16) + 1 = 1 1 % 16 = 1
2 (2 \ 16) + 1 = 1 2 % 16 = 2
5 (5 \ 16) + 1 = 1 5 % 16 = 5
15 (15 \ 16) + 1 = 1 15 % 16 = 15
20 (20 \ 16) + 1 = 2 20 % 16 = 4
32 (32 \ 16) + 1 = 3 32 % 16 = 0
50 (50 \ 16) + 1 = 4 50 % 16 = 2
100 (100 \ 16) + 1 = 7 100 % 16 = 4

Any unused (missing) resource IDs are denoted by zero-length strings. So in the example above, block #1 will have zero-length strings representing IDs 0, 3, 4, and 6 - 14. None of the strings in the block have terminating NULL characters, since it is permitted for string resources to contain embedded NULLs. Thus, the memory layout of block #1 looks like this, assuming each string's value is "Hello world" (11 characters long) and where the numbers in angle brackets represent integers (not literal characters):

<0><11>Hello world<11>Hello world<0><0>
<11>Hello world<0><0><0><0><0><0><0><0>
<0><11>Hello world

The following code snippet shows an enumeration callback function that will enumerate individual RT_STRING resources just like other types (like RT_ICON) rather than the blocks:

// Number of entries in the string table.
constexpr UINT STRING_TABLE_SIZE{ 16 };

// Returns the original resource ID from a given block / offset.
inline UINT GetStringResourceIdFromStringTable(LPCWSTR lpName, const unsigned int index)
{
    _ASSERT(index < STRING_TABLE_SIZE);
    return ((reinterpret_cast<UINT>(lpName) - 1) * STRING_TABLE_SIZE) + index;
}

// Helper function that will enumerate string table blocks, looking for resources.
BOOL EnumerateResourceNamesWrapperForStrings(HMODULE hModule, LPWSTR lpName, LONG_PTR lParam, ENUMRESNAMEPROCW lpEnumFunc)
{
    // No need to free or unlock resources in Win32, so OK to throw away intermediates
    auto ptr = (wchar_t*)LockResource(LoadResource(hModule, FindResource(hModule, lpName, RT_STRING)));
    if (ptr)
    {
        for (unsigned int i = 0; i < STRING_TABLE_SIZE; ++i)
        {
            wchar_t size = *ptr;
            if (size > 0)
            {
                auto id = GetStringResourceIdFromStringTable(lpName, i);

                // Invoke the callback for this string resource ID.
                auto callbackResult = lpEnumFunc(hModule, RT_STRING, MAKEINTRESOURCE(id), lParam);
                if (!callbackResult)
                {
                    return callbackResult;
                }
            }
            // Skip to next potential string in the block
            ptr += size + 1;
        }
        return TRUE;
    }

    // Couldn't load the string table entry; something is wrong.
    return FALSE;
}

// Wrapper function for EnumResourceNamesW that will enumerate individual string resources.
BOOL EnumResourceNamesIncludingStringsW(HMODULE hModule, LPCWSTR lpType, ENUMRESNAMEPROCW lpEnumFunc, LONG_PTR lParam)
{
    struct param_wrapper { ENUMRESNAMEPROCW lpEnumFunc; LONG_PTR lParam; } params{ lpEnumFunc, lParam };

    // Use a simple lambda to either call our String helper, or directly call the user's callback
    return EnumResourceNamesW(hModule, lpType, [](auto hModule, auto lpType, auto lpName, auto lParam)
        {
            auto params = reinterpret_cast<param_wrapper*>(lParam);
            if (lpType == RT_STRING)
            {
                return EnumerateResourceNamesWrapperForStrings(hModule, lpName, params->lParam, params->lpEnumFunc);
            }

            return params->lpEnumFunc(hModule, lpType, lpName, params->lParam);
        }, reinterpret_cast<LONG_PTR>(&params));
};

//////////

// Sample callback that just increments a counter.
BOOL CountResources(HMODULE, LPCWSTR, LPWSTR, LONG_PTR lParam)
{
    // Add one to the count...
    (*(reinterpret_cast<UINT*>(lParam)))++;
    return TRUE;
}

// Sample usage:
void CountStringsInExplorer()
{
    auto lib = LoadLibraryExW(LR"(c:\windows\explorer.exe)", nullptr, LOAD_LIBRARY_AS_DATAFILE);
    if (!lib)
    {
        return;
    }

    UINT nStringBlocks{ 0 };
    UINT nStrings{ 0 };

    // Count the number of string blocks using raw Win32 API.
    EnumResourceNamesW(lib, RT_STRING, CountResources, (LONG_PTR)&nStringBlocks);

    // Count the number of actual strings, using the wrapper.
    EnumResourceNamesIncludingStringsW(lib, RT_STRING, CountResources, (LONG_PTR)&nStrings);

    // Outputs something like:
    //
    // Explorer.exe contains 44 strings (in 17 blocks).
    //

    std::wcout << L"Explorer.exe contains " << nStrings << L" strings (in " << nStringBlocks
        << L" blocks)." << std::endl;
}

Requirements

Requirement Value
Header
Winuser.h