Win32 Resource File Format

by Marco Cocco, of d3k - The Artisan Of Ware, Italy

INTRODUCTION

Preface
Welcome to the Win32 Resource File Format reference guide !
This document is a guide to reading/writing Windows 95 and Windows NT resource files (RES extension).
This guide has been written by M.Cocco (of d3k - The Artisan Of Ware, Italy) while developing the MakeRes Resource Editor, a tool of the "Photoshop Plug-in Toolkit" for Delphi 2.0.
Copyright (c) 1997, Marco Cocco. All rights reserved.
Copyright (c) 1997, d3k - The Artisan Of Ware. All rights reserved.

Audience
This guide is for any programmers who have written applications for Windows systems and wish to understand how to work with standalone binary resource file (RES files, not in-EXE resources). This guide assumes you are proficient in the Windows programming and have worked in any development environments such as Borland Delphi 2.0, Borland Delphi 3.0, Borland C++ Builder, Microsoft Visual C++ (on Windows 95 or Windows NT).
You should have a working knowledge of the different resource types, and understand how handle binary files. This guide assumes you understand terminology such as records (structures), WORD and DWORD types, strings (ANSI and UNICODE), record (structure) alignment, etc.

Remarks
This documentation is made to provide specific information on implementation and structuring issues for Win32 resource files only. Win16 resource files are not explained in this guide.
The best way to use this guide is to read it all without skipping any chapter.
Should you have any question, feel free to contact the author.

GETTING STARTED

This document details the structure of the resource binary file (.RES) format for Win32 platforms (W95 and WNT). The structure is very similar to the existing Win16 (W3/W3.1/3.11) structure, but it supports some new data types and data structures.
One important enhancement is the DWORD/WORD alignment of structures/fields which increases performance of new 32 bit microprocessors but makes resource reading/writing a bit more complex (structures are of dynamic size). The order of the fields of resource data structures is not changed due to alignment, but some padding is required between fields.
The Win32 resource file contains one or more binary resources merged in a single file and aligned on DWORD boundaries. Each resource has its own header structure followed by resource data. Immediately after the resource data comes the header for the next resource followed by resource data, and so on.
To read/write resource files you must have knowledge of binary files handling. Resource files cannot be read using text mode file routines.

THE RESOURCE HEADER

The structure of the header is as follows:

Offset | Field | Data type | Description
0 | DataSize | DWORD 4 bytes, 32 bit unsigned integer | The size of the data that follows the header (not including any padding).
4 | HeaderSize | DWORD 4 bytes, 32 bit unsigned integer | The size of the header structure.
8 | ResType | Ordinal or UNICODE string Array of 16 bit unsigned integers (2 bytes each) | Resource Type ID (standard or custom).
OfsOf(ResType)+SizeOf(ResType)+Padding | ResName | Ordinal or UNICODE string Array of 16 bit unsigned integers (2 bytes each) | Resource name.
OfsOf(ResName)+SizeOf(ResName)+Padding | DataVersion | DWORD 4 bytes, 32 bit unsigned integer | Determines the format of the information within the resource header that follows. Not currently used. Should be zeroed.
OfsOf(DataVersion)+4 | MemoryFlags | WORD 2 bytes, 16 bit unsigned integer | The state of the resource.
OfsOf(MemoryFlags)+2 | LanguageID | WORD 2 bytes, 16 bit unsigned integer | The language that the strings are written with.
OfsOf(LanguageID)+2 | Version | DWORD 4 bytes, 32 bit unsigned integer | It has no significance to the system. Used by resource editors. Usually zeroed.
OfsOf(Version)+4 | Characteristics | DWORD 4 bytes, 32 bit unsigned integer | It has no significance to the system. Used by resource editors. Usually zeroed.

- Resource header structure is not of fixed length. You have to read/write header fields one at a time.
- Resource headers ever start on a DWORD boundary.
- When reading a RES file you must move the file pointer to next nearest DWORD boundary (only if current file pointer is not already on a DWORD boundary).
- When writing a RES file you must write as much padding bytes as it is required to let the header be DWORD aligned (only if current file pointer is not already on a DWORD boundary).
More about the resource header fields:

Field | Additional information
DataSize | The size of the data that follows the header. This value does not include any file padding bytes added after the actual data. The format of the data is different for any of the possible resource types. Data size is expressed in BYTEs (8 bit unsigned integer).
HeaderSize | The size of the resource header structure. This value includes the size of the DataSize and HeaderSize fields. The value of HeaderSize is expressed in BYTEs and can be used to seek directly to resource data following the resource header (seek to FilePos(DataSize) + HeaderSize). The Win32 SDK wrongly says: "The HeaderSize field gives the size of the resource header structure that follows". This should be read: "The HeaderSize field gives the size of the resource header structure, including the DataSize field and the HeaderSize field itself".
ResType | Specifies the resource type (its integer code or its alphabetic name). Further explanation of this field can be found in "The ResType field" chapter.
ResName | Specifies the name of resource (its integer name-code or its alphabetic name). Further explanation of this field can be found in "The ResName field" chapter.
DataVersion | Determines the format of the information within the resource header that follows. Reserved for future expansion. This field is always zeroed but is supposed to change on next version of Win32. Resource editors should check this field and maintan unchaged the resource data if the format is not supported.
MemoryFlags | Contains flags about the state of the resource. Further explanation of this field can be found in "The MemoryFlags field" chapter.
LanguageID | Specifies the language that the strings are written. By providing different values for this field it is possible to store different language versions of the same resource. The application can then choose the set of resources to load based on the currently system language. Further explanation of this field can be found in "Language IDs" chapter.
Version | This field can be used to store custom version information. This lets resource editors to keep backward compatibility whith other version of the same resource editor. This value is stripped out when the resource is linked to the application executable file.
Characteristics | Like the Version field, this field can be used to store custom information flags. This value is stripped out when the resource is linked to the application executable file.

The ResType field
The ResType field can either be:

- 1) a number
- 2) a NULL-terminated UNICODE string

# | Description
1) | The first WORD of the ResType field is 0xFFFF and the second WORD contains the resource type ID. The ResType field is always 4 bytes long (0xFFFF WORD + ID WORD), thus it doesn't require any padding for DWORD boundary alignment. This kind of ResType field is used for system defined resources (menu, dialogs, icons,...) but is can also be used for custom resource types. If you are going to use this kind of ResType for your custom resources, be sure to use ID values not already reserved for standard resources (I suggest you using IDs greater than 0x8000 or like). Or better: never use non numeric IDs for your custom resources. All standard Windows resource types have been assigned numeric IDs as follows:
    	0x0001 = Cursor
    	0x0002 = Bitmap
    	0x0003 = Icon
    	0x0004 = Menu
    	0x0005 = Dialog
    	0x0006 = String Table
    	0x0007 = Font Directory
    	0x0008 = Font
    	0x0009 = Accelerators Table
    	0x000A = RC Data (custom binary data)
    	0x000B = Message table
    	0x000C = Group Cursor
    	0x000E = Group Icon
    	0x0010 = Version Information
    	0x0011 = Dialog Include
    	0x0013 = Plug'n'Play
    	0x0014 = VXD
    	0x0015 = Animated Cursor
    	0x2002 = Bitmap (new version)
    	0x2004 = Menu (new version)
    	0x2005 = Dialog (new version)
2) | The first WORD of the ResType field is not 0xFFFF. The ResType field is an array of UNICODE characters (a string) terminated by a NULL (0x0000 WORD). An additional WORD may be inserted after the terminating NULL to make next field (ResName) start on a DWORD boundary. CORRECTION: From Microsoft's documentation: You do not need to add padding for DWORD alignment between the TYPE and NAME members because they contain WORD data. However, you may need to add a WORD of padding after the NAME member to align the rest of the header on DWORD boundaries. If your application is not using the set of UNICODE API calls you have to convert the resource name to ANSI encoding. Standard resources never use this kind of ResType field.

The ResName field
The ResName field can either be:

- 1) a number
- 2) a NULL-terminated UNICODE string

# | Description
1) | The first WORD of the ResName field is 0xFFFF and the second WORD contains the resource name ID. The ResName field is always 4 bytes long (0xFFFF WORD + ID WORD), thus it doesn't require any padding for DWORD boundary alignment. Notice: String Table resources are not allowed to be named using a UNICODE string: they must be have a numeric name ID (case 1).
2) | The first WORD of the ResName field is not 0xFFFF. The ResName field is an array of UNICODE characters (a string) terminated by a NULL (0x0000 WORD). An additional WORD may be inserted after the terminating NULL to make next field (DataVersion) start on a DWORD boundary. If your application is not using the set of UNICODE API calls you have to convert the resource name to ANSI encoding. Notice: String Table resources are not allowed to be named using a UNICODE string: they must be have a numeric name ID (case 1).

The MemoryFlags field
The MemoryFlags field contains flags about the state of a the resource.
This field is a "bit set", that is, each single bit of its value have a different meaning as follows:

Bit # | Bit mask | Description
4 | 0x0010 | If set: the resource is MOVEABLE, that is, the system can move the resource in memory. If not set: the resource is FIXED, that is, the system cannot move the resource in memory.
5 | 0x0020 | If set: the resource is PURE, that is, the resource contains DWORD aligned data (padding is not needed). If not set: the resource is IMPURE, that is, the resource contains non DWORD aligned data (padding is needed).
6 | 0x0040 | If set: the resource must to be PRELOADed, that is, the resource must be loaded in memory just after the application has been loaded from disk. If not set: the resource must not be PRELOADed, that is, the resource must be loaded in memory only when the application requires it.
10 | 0x1000 | If set: the resource is DISCARDABLE, that is, on low memory conditions, the resource can be removed from memory and then reloaded when the application needs it. If not set: the resource isn't DISCARDABLE, that is, on low memory conditions, the resource cannot be removed from memory.

Notice:
WinNT ignores the setting of the MOVEABLE, IMPURE, and PRELOAD flags.

Language IDs
The LanguageID field, included in each resource header, specifies the language that the strings (of String Tables and Message Tables) are written with.
The system must be informed of the language because it needs to know how to convert characters from UNICODE to ANSI (from double-byte to single-byte characters).
The LanguageID field (found in any resource header) if a 16 bin unsigned integer (WORD) containing not only the language ID but also a sub-language ID. The lower 10 bits (bits 0-9) of this value contain the LanguageID, remaining bits contain the SubLanguageID (bits 11-15).
The LanguageID specifies the code of the primary language. The SubLanguageID specifies a variation of the primary language (a dialect).

Win32 Resource Format Guide v1.0 - Released on October 27th, 1997