Commands related to Windows file resources
Windows resources are binary data that can be added to executable files. Examples include icons, strings and fonts. This module provides commands related to manipulation of these resources.
Resources are stored in Portable Executable format files (exe's and dll's). A resource has an associated name, type and a language. The name and type can be either integer values or strings. To retrieve a particular resource, you must know both the associated values, the type and the name, for that resource. When a resource type or name is a string, it must be explicitly enclosed in quotes. For example,
::twapi::read_resource $h 14 {"ICON3"} 0
and not
::twapi::read_resource $h 14 "ICON3" 0
or
::twapi::read_resource $h 14 ICON3 0
To support localization, there can be several resources with the same type and name, but associated with different languages. These languages are identified by a 16 bit language identifier (LANGID) as described in the TWAPI Internationalization documentation.
TWAPI provides commands to retrieve and update resources as binary data. It does not provide any functionality related to constructing the actual binary data itself. Each resource type has a specific structure and it is up to the application to construct it appropriately.
Windows defines certain standard resource types shown in the table below along with the corresponding #define values from the SDK.
1 | RT_CURSOR - Cursor |
2 | RT_BITMAP - Bitmap |
3 | RT_ICON - Icon |
4 | RT_MENU - Menu |
5 | RT_DIALOG - Dialog |
6 | RT_STRING - String (see String Resources) |
7 | RT_FONTDIR - Font directory |
8 | RT_FONT - Font |
9 | RT_ACCELERATOR - Accelerator |
10 | RT_RCDATA - Application defined raw data |
11 | RT_MESSAGETABLE - Message table |
12 | RT_GROUP_CURSOR - Hardware independent cursor |
14 | RT_GROUP_ICON - Hardware independent icon |
16 | RT_VERSION - Version |
17 | RT_DLGINCLUDE - Name of C include file containing corresponding symbolic names of resources |
19 | RT_PLUGPLAY - Plug and play |
20 | RT_VXD - Vxd |
21 | RT_ANICURSOR - Animated cursor |
22 | RT_ANIICON - Animated icon |
23 | RT_HTML - HTML |
24 | RT_MANIFEST - Executable Manifest |
Manipulating a resource requires a Windows executable module handle for the corresponding executable file. The commands will accept NULL or 0 for this handle corresponding the the main executable for the process. To retrieve resources in other executables or DLL's, the module must be first loaded through the load_library call. Generally, the -datafile option should be passed to the load_library command if the only purpose is to access or update resources.
When the resources in a module are no longer required, it must be released through free_library call.
Once the module is loaded, the content of a particular resource can be retrieved using read_resource and read_resource_string.
You can also enumerate resources present in a module using the enumerate_resource_types enumerate_resource_names enumerate_resource_languages commands.
Note that resources themselves do not need to be explicitly freed up. In particular, do not try to close the resource handles through the CloseHandle or close_handles.
Updating a resource in a file requires that the file not be in use by any application (including the current process). The begin_resource_update command prepares the file for update. One or more update_resource commands can be used to modify the resources in the file and delete_resource commands can be used to delete resources. Finally, the the end_resource_update command is used to commit or discard the modifications.
Strings defined through a string table definition in a resource definition file are not directly stored in the resource binary. They are stored in string blocks, each containing 16 strings. It is therefore not possible to directly retrieve or update a string based on its string id.
If you call read_resource with a resource type of 6 (STRING), the resource name or id has to actually be the id of the string block, not the string. The command resource_stringid_to_stringblockid will take a string id and return a pair consisting of the id of the corresponding block and the index of the string within the block. The block id can be passed to read_resource to read the string block. Since this is in binary format, it needs to be converted into a list of strings using resource_stringblock_to_strings. The string index returned from resource_stringid_to_stringblockid can be used to then pick out the appropriate string from the this list.
If you are only interested in a single string, the command read_resource_string encapsulates this entire process.
Updating strings in a resource involves multiple steps for the same reason. First, the string block has to be retrieved and converted to a list of strings as described above. The list must then be modified as desired and converted back to a string block using strings_to_resource_stringblock and then written out using update_resource.
Deleting a string resource is similar. Once the list of strings in the appropriate block is retrieved, set the corresponding element in the list to an empty string before writing it back using update_resource.
A peculiarity in the storage format for resource strings means it is not always possible to distinguish between a resource string that is not defined and a resource string that is defined with an empty value. An attempt to read an undefined resource string may either result in an error being generated, or in the return of an empty string.
Copyright © 2010 Ashok P. Nadkarni