by Jeremy Gordon
A "Go" development tool:
see http://www.GoDevTool.com
Introduction
Starting the Resource Compiler
Directives (eg. #define,#if,#include)
Other symbols
Numbers
Arithmetic
Strings and String Manipulation
Windows character set
Raw data resources (eg. cursor,bitmap,RCDATA etc)
Stringtable resource
Versioninfo resource
Accelerators resource
Menu resource
Dialog resource
Version and characteristics
Language
Capitalisation of nameIDs and types
Legal stuff
This document assumes that the reader has some knowledge of resources, what they are and how they work.
This document is intended for use with the GoRC resource compiler. There are some slight differences in the permitted syntax between the Microsoft Resource compiler and GoRC. In general GoRC will accept all RC source files that the Microsoft Resource compiler will accept but is slightly more flexible in its syntax.
RC source files (those with an ".rc" extension) should be text without formatting codes, other than carriage return, linefeed or tabs, such as produced by most simple text editors. More sophisticated word processors can also produce such files if they are instructed to produce TXT files, ASCII or ANSI files.
The resource script and include files can be in Unicode format. If so, GoRC expects a Byte Order Mark (BOM). GoRC can read the UTF-8 Unicode format with BOM, or the UTF-16LE Unicode format with BOM.
GoRC can make
two types of binary resource files from a resource script. It can
make an OBJ file in COFF format, which is suitable for linking with other
OBJ files to produce the final EXE or DLL. It can also produce a RES file,
which is an intermediate file in binary format. GoRC can also convert a
RES file to an OBJ file.
The OBJ file made by GoRC can either be in Win32 format (the default)
or Win64 format if you specify the /machine AMD64 or /machine X64 switch
in the command line.
Here are the syntax rules which are used in this reference:-
Normal text shows words as they actually appear in your
source code.
Italic text describes only the type of entry in your
source code- look for the description to see what can be put there.
[Text in square brackets means that the material is optional].
Starting the Resource Compiler
Back to top
The command line syntax is:-
GoRC [command line switches] filename[.ext]
Where,
filename is the name of the resource script
Command-line Switches
/h or /? help
/d define a word
/o create OBJ file
/r create RES file
/fo specify output file
/machine AMD64 or
/machine X64 object output file will be in 64-bit format
/ni no information messages
/ne no error messages
/nw no warning messages
/no no output messages at all
Input and Output files
The default action of GoRC is RC > RES and OBJ
If no extension is given in the command line and GoRC
cannot find filename.RC then it looks for filename.RES. If
found, this results in the action RES > OBJ.
The default action can be overridden to achieve RC > RES in the following ways:-
You can ensure the action is RES > OBJ by giving the input file with the extension RES.
By default, the output filenames will be the same as those of the input file, but you can use the /fo switch to change this. This is used as follows:-
GoRC can work with Unicode input and output filenames, but the extensions used must be as set out above.
Errors and Warnings
Errors will cause the Resource Compiler to stop and no
output files will be made. The console then shows the nature of the error
and where it occurred. (unless the command line switch /ne has been specified).
The Resource Compiler will also return with a code of 1, which will be
likely to halt the build process if you are using a make file.
Warnings do not stop the Resource Compiler. A warning will be given (unless the command line switch /nw has been specified) if:-
Directives
Back to top
Directives are words in the resource script which give instructions to the Resource Compiler.
There are 3 types of directives:-
Evaluating types
These are #define macros which evaluate to a number or
to a quoted string
#define name value
Examples
#define IDC_BUTTON 0x20
#define DLGCONTROL 0x20 | 0x40
#define DLGTEXT "Hello world"
#define OTHER DLGCONTROL + IDC_BUTTON
#define WINNT
(this sets the name WINNT to a value of 1, that is, TRUE)
You can define a name from the command line:-
Examples
GoRC /d WINVER=400h mainres
This compiles the resource script mainres, on the basis
that WINVER is equal to hex 400 throughout.
GoRC /d WINNT mainres
This compiles the resource script mainres, on the basis
that WINNT has the value of 1 (that is, TRUE)
GoRC /d WINNT=55h /d good=0x44
mainres
Example of more than one definition.
GoRC /d WINNT=330, good=0x44
mainres
Example of more than one definition using comma.
Examples
#undef IDC_BUTTON
#undef DLGCONTROL
#define name value1 value2 value3 ……
Syntax for the macro in which the arguments are declared:-
#define name(arg1,arg2,arg3….) use of arguments
Syntax to supply the arguments:-
name(arg1,arg2,arg3….)
The Include Directive
#include path\filename
This will cause the Resource Compiler to load and look at the specified file if necessary.
path\filename can be either:-
To the Resource Compiler there are two types of #include files.
There are "header" files, with the file extension ".h". These files are not treated as part of the resource script, but are regarded only as containing defining directives. This enables the Resource Compiler to work more quickly because it will not bother to search an ".h" file unless it has an expression which it is trying to evaluate. Any ordinary resource script statements in an ".h" file will be ignored by the Resource Compiler.
Note that the Resource Compiler is itself aware of most if not all of the usual styles and expressions used in a resource script. For this reason it will not normally be necessary to include any header files. However you will need to define your own expressions and identifiers if you wish to use those.
The second type of #include files are non ".h" files. These are treated as part of the resource script itself by the Resource Compiler. When an #include directive if found for a non ".h" file, the Resource Compiler will divert its attention to the #include file and when it has finished looking at that file it will return to the original script where it left off.
You can nest #include files but it is probably good practice to avoid this as far as possible.
Definition Priority
A #define directive in an ".h" include file is regarded
as of lower priority than a #define directive in the command line, resource
script or in a non ".h" include file. Therefore if there is any conflict
between the #defines, the #define in the ".h" include file will be ignored.
With these directives you can select at compile-time that part of the resource script or of the defining directives which you want to be compiled. This may be useful if, for example, you want to make different versions of your program from the same resource script.
The syntax of the basic structure of a conditional directive in its simplest form is as follows:-
#if condition
text A
#endif
Here if the condition is TRUE text A will be compiled. If, however, the condition is FALSE, the compiler will jump over text A and will continue compiling from the #endif.
You can add something to do if the condition is FALSE as follows:-
#if condition
text A
#else
text B
#endif
Here if the condition is TRUE, text A will be compiled, but text B will not be compiled.
If, however, the condition is FALSE, text A will be jumped over but text B will be compiled.
The #endif indicates the end of the conditional frame, so that all text after that will be compiled.
The #else statement must always be next before the #endif.
You can add a further condition to the frame:-
#if condition1
text A
#elif condition2
text B
#endif
Here if condition1 is TRUE, text A will be compiled, but text B will be jumped over and compilation will continue from the #endif. If, however, condition1 is FALSE, text A will be jumped over to the #elif when condition2 will be tested. If then condition2 is TRUE, text B will be compiled. "#elif" is the same as "#elseif".
Adding the #else to the above conditional frame produces:-
#if condition1
text A
#elif condition2
text B
#else
text C
#endif
Here if condition1 is TRUE, text A will be compiled, but text B and text C will be jumped over and compilation will continue from the #endif. If, however, condition1 is FALSE, text A will be jumped over to the #elif when condition2 will be tested. If then condition2 is TRUE, text B will be compiled, and text C will be ignored; if, however condition2 is FALSE text B will be jumped over to the #else and text C will be compiled.
You can have as many #elifs as you like in each conditional frame, but there can only be one #else per frame, and each #if must have a corresponding #endif. Some programmers nest the conditional frames, but this can become very confusing and may not be good programming practice. If this is done it is recommended that you label each #endif with a comment so that you can see to which #if it refers.
Types of #if statements
#ifdef expression
the relational operator can be one of the following:-
>= greater than or equals
<= less than or equals
== equals
= equals
!= not equal
> greater than
< less than
expression2 can be a number or a word which is defined elsewhere in the file, in an include file or in the command line, which evaluates to a number.
For example, #if WINVER>=400h
will return TRUE if WINVER is defined as 400h or more.
#if ! this reverses the result of the condition, so that (for example) #if!0 would return TRUE
Other symbols
Back to top
These are some other symbols which may be used in the resource script or a header file and which have a special meaning to the Resource Compiler.
; or // a comment line - everything after this to the
end of the line is ignored
;;......;; or
/*.........*/ a continuous comment - everything between
the marks is ignored
\ (at the end of a line or just before a comment) -
the material is continuing on the next line (cannot be used in quoted strings
or filenames)
{ same as BEGIN
} same as END
-number means the number is negative eg. -22h if
a dword becomes 0FFFFFFDEh
~number means the number is inverted eg. ~22h if
a dword becomes 0FFFFFFDDh
+ plus eg. 22h + 3h produces 25h
- minus eg. 22h - 3h produces 1Fh
| or ¦ bitwise OR eg. 22h | 3h produces 23h
& bitwise AND eg. 22h & 3h produces 2h
!value in arithmetic this causes the value to be
inverted and then ANDed with the existing and is the same minus value
NOT value same as above
# in a #define macro, this causes quotes to be added to
what follows
eg. #HELLO becomes "HELLO"
eg. #(MAJOR.MINOR) becomes "MAJOR.MINOR"
## in a #define macro, this joins two elements, removing
all spaces in between
eg. PATCH ## WORK becomes PATCHWORK
(…..) in a #define macro the material within the parentheses
is evaluated first
Numbers
Back to top
The Resource Compiler recognises the following types of numbers, for example:-
6666666h a hex number
3434343H a hex number
9999999D a decimal number
22553388d a decimal number
34567789 a decimal number
0x456789 a hex number
456L specifies the number is to be recorded as a dword
where otherwise it would be a word
Arithmetic
Back to top
The resource compiler can perform limited arithmetic on the following:-
identifiers, styles, flags and dialog and control positions
and dimensions
defining directives
expressions in conditional directives
Strings and String Manipulation
Back to top
Quoted strings in the stringtable resource and in all text for dialogs and menus must be kept in the binary resource files and in the EXE in Unicode. If the resource script is an ANSI text file, however, the strings will be in ANSI characters. In that case the Resource Compiler converts them to Unicode using the API MultiByteToWideChar. This API uses the current codepage for this conversion, so you need to ensure that at compile time your machine is set to use the same codepage as was used when the source script was made.
If the resource script is a Unicode file, then codepages are not used: the strings are used as they appear in the resource script.
The strings are put in the RES file (or OBJ file) in Unicode whether or not you use the "C" style Unicode indicator L"string". The Resource Compiler regards the L"string" indicator as implicit for these types of strings. So there is no need to use that indicator in your resource script (unless you want to insert special Unicode characters - see below).
There is no implicit L"string" indicator for quoted strings in the raw data resources (eg. RCDATA). Therefore in an ANSI file such strings are not converted to Unicode unless L"string" is specified.
All quoted strings may contain escape sequences which are dealt with in a special way by the Resource Compiler:-
In all quoted strings which are converted by the Resource
Compiler you can have:-
\number
This then will cause the character represented by number
to be inserted in the text
For example, "Copyright \251 2005" inserts a © symbol
in the text.
Strange! The © symbol, as everybody knows, is ANSI
value 169, or A9 in hex.
However, the Resource Compiler uses octal numbers in this feature rather than decimal, ie. all digits are to base 8. Why? This is simply to provide compatibility with existing resource scripts.
Sometimes \number can look rather odd. For example "The entrance fee was \4423", is converted to "The entrance fee was $23". Here the Resource Compiler does not try to find character 442 octal or 4423 octal because it knows that this value is too high. This works fine for characters above 38 octal, but for characters with values less than this, for example 12 octal which is the value 0Ah (linefeed) there could be confusion, for example "We found on average about\1223 flies in each of the soups". This should be written "We found on average about\01223 flies in each of the soups". This is because the Resource Compiler will only look at 3 octal digits and no more, so it stops after the \012 (linefeed), and the value 23 is kept in the text properly. Of course you could use \n instead to ensure there is no chance of confusion and this would be better.
\number in hex rather than in octal
You can also use hex values when entering \number, by including x after the backslash. For example the hex version "Copyright \xA9 2005" is the same as "Copyright \251 2005" which is the octal version. Again the Resource Compiler will not look beyond the second hex digit for the value, so ensure that where small values are used you insert the zero if there is any danger of confusion. For example in "The capacitor had a value of 3\xb5farads" the Resource Compiler does not take the hex number b5f, but looks only at b5 hex. However, in the string "It returned to Earth\x0aafter 44 years with 5 more people on board", the zero is required to avoid using the hex number aa as the special character.
\number in Unicode strings
The Resource Compiler looks at up to four hex digits in \number if the string is expressly declared to be a Unicode string. You can do this by using the "C"-style indicator L"string" for the string. So, for example to create a string for a dialog button which displays a Shekel you would use the following string:-
L"\x20AA"
This creates the Unicode special character 20AAh (the Shekel sign).
You would not need to do this if you used Unicode format files, since
you could display the Shekel normally and it would be coded properly by
the Resource Compiler.
The character set used when the string is written to the
screen by the menu, dialog or other method, depends on which character
set is in use in the computer running the EXE. For computers used in English
this is usually the Windows Character Set. A table of octal values may
be difficult to find so one is provided here on the next page for your
use, and on the following page a table of hex values.
Space | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 50 | 51 | 52 | 53 | 54 | 55 |
. | / | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; |
56 | 57 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 70 | 71 | 72 | 73 |
< | = | > | ? | @ | A | B | C | D | E | F | G | H | I |
74 | 75 | 76 | 77 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 110 | 111 |
J | K | L | M | N | O | P | Q | R | S | T | U | V | W |
112 | 113 | 114 | 115 | 116 | 117 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 |
X | Y | Z | [ | \ | ] | ^ | _ | ` | a | b | c | d | e |
130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 140 | 141 | 142 | 143 | 144 | 145 |
f | g | h | i | j | k | l | m | n | o | p | q | r | s |
146 | 147 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 160 | 161 | 162 | 163 |
t | u | v | w | x | y | z | { | | | } | ~ | | ||
164 | 165 | 166 | 167 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 200 | 201 |
‚ | ƒ | „ | … | † | ‡ | ˆ | ‰ | Š | ‹ | Œ | |||
202 | 203 | 204 | 205 | 206 | 207 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 |
‘ | ’ | | | • | | | ˜ | ™ | š | › | œ | ||
220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 230 | 231 | 232 | 233 | 234 | 235 |
Ÿ | ¡ | ¢ | £ | ¤ | ¥ | ¦ | § | ¨ | © | ª | « | ||
236 | 237 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 250 | 251 | 252 | 253 |
¬ | ® | ¯ | ° | ± | ² | ³ | ´ | µ | ¶ | · | ¸ | ¹ | |
254 | 255 | 256 | 257 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 270 | 271 |
º | » | ¼ | ½ | ¾ | ¿ | À | Á | Â | Ã | Ä | Å | Æ | Ç |
272 | 273 | 274 | 275 | 276 | 277 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 |
È | É | Ê | Ë | Ì | Í | Î | Ï | Ð | Ñ | Ò | Ó | Ô | Õ |
310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 320 | 321 | 322 | 323 | 324 | 325 |
Ö | × | Ø | Ù | Ú | Û | Ü | Ý | Þ | ß | à | á | â | ã |
326 | 327 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 340 | 341 | 342 | 343 |
ä | å | æ | ç | è | é | ê | ë | ì | í | î | ï | ð | ñ |
344 | 345 | 346 | 347 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 360 | 361 |
ò | ó | ô | õ | ö | ÷ | ø | ù | ú | û | ü | ý | þ | ÿ |
362 | 363 | 364 | 365 | 366 | 367 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 |
Space | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 2A | 2B | 2C | 2D |
. | / | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; |
2E | 2F | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 3A | 3B |
< | = | > | ? | @ | A | B | C | D | E | F | G | H | I |
3C | 3D | 3E | 3F | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
J | K | L | M | N | O | P | Q | R | S | T | U | V | W |
4A | 4B | 4C | 4D | 4E | 4F | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
X | Y | Z | [ | \ | ] | ^ | _ | ` | a | b | c | d | e |
58 | 59 | 5A | 5B | 5C | 5D | 5E | 5F | 60 | 61 | 62 | 63 | 64 | 65 |
f | g | h | i | j | k | l | m | n | o | p | q | r | s |
66 | 67 | 68 | 69 | 6A | 6B | 6C | 6D | 6E | 6F | 70 | 71 | 72 | 73 |
t | u | v | w | x | y | z | { | | | } | ~ | | ||
74 | 75 | 76 | 77 | 78 | 79 | 7A | 7B | 7C | 7D | 7E | 7F | 80 | 81 |
‚ | ƒ | „ | … | † | ‡ | ˆ | ‰ | Š | ‹ | Œ | |||
82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 8A | 8B | 8C | 8D | 8E | 8F |
‘ | ’ | | | • | | | ˜ | ™ | š | › | œ | ||
90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 9A | 9B | 9C | 9D |
Ÿ | ¡ | ¢ | £ | ¤ | ¥ | ¦ | § | ¨ | © | ª | « | ||
9E | 9F | A0 | A1 | A2 | A3 | A4 | A5 | A6 | A7 | A8 | A9 | AA | AB |
¬ | ® | ¯ | ° | ± | ² | ³ | ´ | µ | ¶ | · | ¸ | ¹ | |
AC | AD | AE | AF | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 | B8 | B9 |
º | » | ¼ | ½ | ¾ | ¿ | À | Á | Â | Ã | Ä | Å | Æ | Ç |
BA | BB | BC | BD | BE | BF | C0 | C1 | C2 | C3 | C4 | C5 | C6 | C7 |
È | É | Ê | Ë | Ì | Í | Î | Ï | Ð | Ñ | Ò | Ó | Ô | Õ |
C8 | C9 | CA | CB | CC | CD | CE | CF | D0 | D1 | D2 | D3 | D4 | D5 |
Ö | × | Ø | Ù | Ú | Û | Ü | Ý | Þ | ß | à | á | â | ã |
D6 | D7 | D8 | D9 | DA | DB | DC | DD | DE | DF | E0 | E1 | E2 | E3 |
ä | å | æ | ç | è | é | ê | ë | ì | í | î | ï | ð | ñ |
E4 | E5 | E6 | E7 | E8 | E9 | EA | EB | EC | ED | EE | EF | F0 | F1 |
ò | ó | ô | õ | ö | ÷ | ø | ù | ú | û | ü | ý | þ | ÿ |
F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | FA | FB | FC | FD | FE | FF |
Resource statements
Resource statements are the instructions to the Resource Compiler which contain the information from which the output file is actually made. They fall into four main categories:-
Raw data resource types (a) taking data from a file
Back to top
With these resources the Resource Compiler merely takes raw data from an input file and adds it to the output file (sometimes with some extra processing). Hence the data from these files makes its way to the EXE, when the file is linked, for use during run-time. This is a convenient way to keep the data from such files in the EXE. An alternative would be to ship the individual files with the product for loading at run-time, but this runs the risk that those files may get lost.
The data (as raw data) can be used at run-time by calling the FindResource and LoadResource APIs, but there are some specific APIs which also provide manipulation of the data. The various raw data resource types which work using files, their resource type numbers, and the specific API (if any) to load them during run-time are:-
The general syntax for these resource types in the resource script (using CURSOR as an example) is:-
nameID CURSOR filename
Where, in the normal case,
nameID can be either:-
nameID can be either:-
Raw data resource types (b) taking data from resource script
These resources allow you to insert raw data into the EXE via the binary resource file. The Resource Compiler makes no alteration to the raw data. Unless use is being made of the ability of the system to distinguish between resources of different languages, assembler programmers would probably not find much use for this as it is so simple to use the data segment to keep data..
The data (as raw data) can be used at run-time by calling the FindResource and LoadResource APIs.
This type of resource is RCDATA (type number 10) when used with BEGIN and END, and not with a filename. Alternatively you can choose any name for the resource in which case it works the same way as RCDATA except that the resource type has a name. This is called a user-defined resource. Alternatively you can also simply provide any 16 bit number above 0FFh for the resource type.
The syntax for RCDATA used in this way is:-
nameID RCDATA
[defining-statements]
BEGIN
raw-data
END
Or, in the case of a user-defined resource:-
nameID type
[defining-statements]
BEGIN
raw-data
END
Where,
nameID can be either:-
see below for details
MyRes RCDATA
BEGIN
MyRes MyResType
BEGIN
34h 100h
BEGIN
The STRINGTABLE resource enables strings to be kept in
the EXE to be recovered when needed at run time. For assembler programmers
this would be an alternative to keeping the strings in the data segment.
Even if you need to use Unicode strings, if you are using GoAsm as your
assembler it is usually
easier to keep the strings in data rather than to use the STRINGTABLE resource.
If the source file is in ANSI format, strings in the STRINGTABLE resource
are automatically converted to Unicode by the Resource Compiler, so there is
no need to use the "C" style Unicode indicator L"string". The Resource
Compiler regards the L"string" indicator as implicit. The conversion
is carried out using the API MultiByteToWideChar. This API uses
the current codepage for this conversion, so you need to ensure that at
compile time your machine is set to use the same codepage as was used when
the source script was made.
If the source file is in Unicode format, then no conversion takes place
and codepages are not used: the strings are used as they appear in the resource
script.
One reason why the assembler programmer might wish to keep strings in a STRINGTABLE resource rather than in the data segment would be to take advantage of the ability of the system to distinguish strings of different languages at run-time.
The strings are kept in blocks of 16 strings. Each block will have the same language and also the same upper 12-bits of the ID which was specified in the resource script. The least significant 4 bits are blanked out and are not be recorded because it is assumed that the IDs run in sequence in each block from 0 to 0Fh. To make this assumption valid, if the string IDs are not in sequence the Resource Compiler has to insert empty strings. To reduce space requirements, therefore, it is best to keep the identifiers sequential.
To recover one of the strings call LoadString giving the string identifier. It will then be copied into a buffer with a nul terminator.
The syntax for the STRINGTABLE resource is as follows:-
STRINGTABLE
[defining-statements]
BEGIN
stringID "string"
.........
END
Where,
stringID is
If the string straddles more than one line the Resource
Compiler inserts a space and a line feed character (ASCII 0Ah) at the line
break and all leading spaces on the next line in your resource script are
suppressed.
These types of resources are used to keep information about the EXE in a certain format, for use by tools or for information to the user.
There are two types of such resources.
Firstly DLGINCLUDE (resource type17) which contains a filename which is read by the Microsoft Dialog Editor. This filename is that of the include file containing definitions when making dialogs. This information is not actually kept in the EXE, and is disgarded by the linker.
Its syntax is:-
nameID DLGINCLUDE filename
Where,
nameID can be either:-
Secondly, the VERSIONINFO resource (resource type 16), which is used to keep information about the version of the EXE, which may be required during its installation or if it is updated.
The version information can be retrieved in various ways using the APIs GetFileVersionInfo, GetFileVersionInfoSize, and VerQueryValue. Also it is the information which appears in the "Version" property sheet when looking at the "Properties" of an Executable file in Windows.
The syntax for this resource is:-
Where,
The names of the fixed-info statements are fixed and are used by the Resource Compiler to decide where in the VS_FIXEDFILEINFO structure to put the specified value. As you can see, certain values have definite meanings reserved by Microsoft, but there seems to be no reason why you cannot use your own values which may have a special meaning to your application.
lang-charset is a quoted string containing (in numbers) a hex number which gives the language and character set used in the string-value statements which follow. The most common value found here is "040904E4" meaning US English + Windows, multilingual character set
lang/char statements are two 16-bit numbers separated by a
comma. The first represents a language and the second a character set
supported by the application. If a lang/char statement is included in the
VERSIONINFO resource, the system will initialise the "Version" property
sheet found when looking at the "Properties" of the executable file, and
will include a "Language" key.
The most common value found is 0x409,1252 which is US English + Windows,
multilingual character set, the latter being given in its decimal value,
but 4E4h would do just as well
string-value statements are a series of statements containing two quoted strings with the following syntax:-
"name", "value"
"name" is a string which would be given to the API VerQueryValue in order to retrieve the value
The following strings are looked for by the system when showing the "Version" property sheet:-
"FileVersion", "FileDescription" and "LegalCopyright", and the value appears at the top of the property sheet adjacent to the words "File Version", "Description" and "Copyright" respectively.
Other strings appear in listboxes in the property sheet. You can use whatever string you like, although there if they are too long they are truncated in the property sheet and they always appear in alphabetical order.
You often see one of the following strings being used - "Comments" "CompanyName" "InternalName" "LegalTradmarks" "OriginalFilename" "PrivateBuild" "ProductName" "ProductVersion" "SpecialBuild"
"value" is a user defined value in a quoted string
which corresponds to one of the standard strings and will be returned by
VerQueryValue.
These types of resources make it easy to create accelerators, menus, and dialogs - three basic ingredients for the user interface. In each case it is possible to use the APIs instead of using the resource file, but this is normally much less convenient, and no advantage can be taken of the system being able automatically to discriminate between menus and dialogs of different languages.
In order to use these resources, in a single language application a specific API is called to obtain a handle to the resource.
The five resource types under this heading, the resource type numbers and the APIs used to use the resources are:-
The ACCELERATORS resource
Back to top
The syntax for the ACCELERATORS resource is:-
nameID ACCELERATORS
[defining-statements]
BEGIN
event, result [,type/options]
...........
END
Where,
nameID can be either:-
The syntax for the MENU resource is:-
nameID MENU
[defining-statements]
BEGIN
MENUITEM "text", id [,type/state]
POPUP "text" [,type/state]
BEGIN
MENUITEM "text", id [,type/state]
END
MENUITEM SEPARATOR
...........
END
The syntax for the MENUEX resource is:-
nameID MENUEX [,helpID]
[defining-statements]
BEGIN
MENUITEM "text", id [,type/state]
POPUP "text", [id] [,type/state]
[,helpID]
BEGIN
It can be:-
a 16-bit number (MENU) or a 32-bit number (MENUEX)
an expression which evaluates to the above number
helpID which is used in MENUEX only, is a value sent to the window procedure of the window which owns the menu if F1 is pressed when the menu is active. It can be:-
an expression which evaluates to a 32 bit number
MENUITEM SEPARATOR creates a horizontal line in the menu which is useful for separating different types of menu items
Example of MENU resource
#define IDM_NEW 10h
#define IDM_OPEN 20h
GENERIC MENU
BEGIN
BEGIN
MENUITEM "&Open...", IDM_OPEN,GRAYED
MENUITEM SEPARATOR
BEGIN
END
POPUP "View"
BEGIN
Example of MENUEX resource
#define IDM_NEW 10h
#define IDM_OPEN 20h
GENERIC MENUEX 99999999h
BEGIN
BEGIN
MENUITEM "&Open...", IDM_OPEN,GRAYED
MENUITEM SEPARATOR
BEGIN
END
POPUP "View"
BEGIN
The DIALOG resource
Back to top
The syntax for the DIALOG resource is:-
nameID DIALOG x, y, width, height
The syntax for the DIALOGEX resource is:-
nameID DIALOGEX x, y, width, height [,helpID]
[defining-statements]
[dialog-statements]
BEGIN
iconcontrol
textcontrol [,helpID]
non-textcontrol [,helpID]
generic-control [,helpID]
END
Where,
nameID can be either:-
CLASS class
this statement is used if you have registered your own
private window class for the dialog because you want to intercept dialog
messages before they go to the system’s default dialog window procedure.
class can be:-
a 16-bit number
a quoted string
EXSTYLE exstyle allows an extended style to be specified see window types and styles
FONT pointsize, "typeface" ;if DIALOG
FONT pointsize, "typeface" [,weight, italic]
;if DIALOGEX
this statement must be present if the dialog has the DS_SETFONT
style and it contains the information which the system uses to write the
text within the dialog box and its controls. If this statement is present
the dialog box is given the style DS_SETFONT automatically.
pointsize is a 16 bit number giving the size of
the font
typeface is a quoted string giving the name of
the typeface
weight (DIALOGEX only) is either:-
MENU menuname
this statement if present specifies a menu for the dialog
box and menuname is either:-
a 16-bit number identifying the menu. This would be the
number given as the nameID of the menu resource.
an expression which evaluates to that number, or
the name of a menu resource if the nameID of the
menu was a name
STYLE styles
this statement is used to change the default dialog box
style which is:-
WS_POPUP | WS_BORDER | WS_SYSMENU, which is the same as
80000000h | 800000h | 80000h
To remove an unwanted default style you can use the word
NOT or !, for example
STYLE NOT SYSMENU
or
STYLE !80000h
would produce a dialog box with a style of WS_POPUP and
WS_BORDER only.
The following styles and their respective values can be
used in this statement:-
The syntax for an iconcontrol is:-
ICON nameID, id, x, y
Where,
The syntax for a textcontrol is:-
textcontrol "text", id, x, y, width, height, [,style
[,extendedstyle]]
BEGIN
data-elements
END
Where,
"text" is the text to appear in the control
The syntax for a non-textcontrol is:-
non-textcontrol id, x, y, width, height, [,style
[,extendedstyle]]
BEGIN
data-elements
END
The id, x, y, width, height,
style and extend style parameters are the same as for the text-control
The various non-textcontrols and their classes
are given below, together with the default styles
The syntax for the generic-control is as follows:-
CONTROL "text", id, class, style, x, y,width,height
[,extended style] [,helpID]
For the controls which do not normally take initial
text, (see non-textcontrols above) you must include an empty text
string by specifying "", for the text parameter.
style and extendedstyle are chosen to suit
the particular control being made. Note that there are no default styles,
other than WS_CHILD and WS_VISIBLE.
Example of a DIALOGEX
resource
0x45 DIALOGEX 0x30, 0x20, 0x200,
0x400,0x98
CAPTION "goodbye"
MENU mymenu
FONT 10,"Times New Roman",FW_NORMAL,1
BEGIN
,WS_EX_PALETTEWINDOW, 0x333
BEGIN
L"hello folks"
0x99,0x67,0x5555
CONTROL "hens",0x462,"Button",0x100,30005,4560,300,20
CONTROL "chickens",0x464,STATUSCLASSNAME,
0x100,30005,4560,300,20
Example of a DIALOG
resource
AboutBox DIALOG 100, 100, 160,
72
STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
FONT 8,"MS Sans Serif"
CAPTION "About it"
BEGIN
CTEXT "Version 1.2" -1, 0, 16, 160, 8
DEFPUSHBUTTON "OK" IDOK, 55,52,50,14
ICON "MyIcon" -1, 20, 10,0,0
END
Defining statements
defining-statements give some further definition
to each resource.
There are three types of defining-statement:-
The syntax for these is the same:-
VERSION value
CHARACTERISTICS value
Where, value is:-
a 32-bit number
an expression which evaluates to a 32-bit number
value is stored only in the RES file and not in
the OBJ file nor in the EXE, so it cannot be recovered at run-time. However
it could be read by tools which work with the RES file, such as the some
linkers.
Language
Back to top
The syntax of the LANGUAGE statement is:-
LANGUAGE language, sublanguage
This statement can appear anywhere in the script (outside
a BEGIN...END section). In that case the specified language applies to
all resources thereafter.
It can also appear between the resource statement itself
and the BEGIN...END section as a defining-statement. In that case
the specified language only applies to the resource in which it appears.
The actual values for language and sublanguage appear in
WINNT.H.
The most common values for language are LANG_ENGLISH
(value 9h), and for sublanguage are SUBLANG_ENGLISH_US (value 1h),
SUBLANG_ENGLISH_UK (value 2h), SUBLANG_ENGLISH_AUS (value 3h) and SUBLANG_ENGLISH_CAN
(value 4h).
If no language is specified in your resource script the
Resource Compiler uses the system language and inserts that in the binary
resource file.
Making different language versions of a resource
If your product is to be used in more than one language,
you will need to provide different menu and dialog text, warning and error
messages to suit the language. The combined features of the Resource Compiler
and the API make it reasonably easy to achieve this. The exact way this
is achieved, in the context of resources, depends on whether you want:-
The second is possible because the API FindResource will automatically return the handle of the resource which suits the default system language for the computer which is running the program. FindResource does this by obtaining the default system language and then calling FindResourceEx. If you want to specify the language of the resource to be found, rather than relying on the system default language, then you can call FindResourceEx directly giving the language ID.
FindResource can be used as follows:-
FindResourceEx can be used as follows
The return from FindResource and FindResourceEx is the handle which is needed for the call to LoadResource.. You can have several versions of a menu or dialog, for example, with the same nameID but with different languages specified. FindResource will return the handle of the correct one.
Language specific menus
Since the FindResource (or FindResourceEx) and LoadResource
combination provide an address to the resource data itself, in order to
load a language specific menu, you need to pass that address as the menu
template to LoadMenuIndirect. You cannot use LoadMenu to load a language
specific menu.
Language specific dialogs
Similarly, to make a language specific dialog box you
need to pass the address of the dialog template returned by LoadResource
to DialogBoxIndirect (modal) or CreateDialogIndirect (non-modal) rather
than using the CreateDialog and DialogBox APIs. Other language specific
components which are needed in your dialog should either be given a unique
nameID or loaded at run-time. For example, if you have a French
version of your dialog and want to include a French menu by using the MENU
defining-statement in the resource script, a nameID must
be given in the MENU statement which uniquely refers to the French menu.
Alternatively if you have several language versions of the menu all with
the same nameID you could load the menu at run-time upon the INIT_DIALOG
message. This would be done by calling FindResource or FindResourceEx,
then LoadResource (to get and address for the menu template of the correct
menu), LoadMenuIndirect (to get the menu handle) and then SetMenu (to load
the menu into the dialog box).
Language specific strings and raw data
When loading language specific strings, you can use LoadString
directly. This loads a string to suit the system default language. Alternatively
the address of the string itself can be obtained using FindResource, or
FindResourceEx and LoadResource.
The same method works for RCDATA and for a user-defined
resource (and indeed for any resource which can be used by obtaining an
address of the raw data of the resource).
Examples for viewing
Testbug.Exe provides examples of loading language specific
menus, dialogs, strings and raw data. The relevant functions to look at
with the debugger are:-
Menus, dialogs and raw data example, click "use of resources/different
language versions/various resources in English" or "same showing French
versions" in the menu, watching with the debugger the functions RESOURCES_IN_ENGLISH
and RESOURCES_IN_FRENCH, which create dialog boxes using the dlg wndproc
called MDLangDlgProc.
Strings, click "Language specific string" in the menu,
watching with the debugger the function STRINGTABLES_BY_LANGUAGE.
Language search criteria
When searching for language specific resources, the system
looks for a language match but has certain defaults if an exact match is
not found. The system carries out the search for a resource of the correct
type and ID in this order, moving down the list if the resource is not
yet found:-
Own language values
You can specify your own language values if you wish,
and by this method it would be possible to make several versions of menus,
dialogs and strings for your product in the same language if you
wished, using the automatic language selection referred to above. To keep
the system happy, ensure that your language value is between 200h
and 3FFh, and the sublanguage value is between 20h and 3Fh. These
values are carefully chosen. The actual languageID inserted in the binary
resource file and kept in the EXE is only 16 bits long, the language
value occupying the most significant 10 bits (hence a maximum value of
3FFh) and the sublanguage value occupying the least significant
6 bits (hence a maximum value of 3Fh).
456h RCDATA
LANGUAGE LANG_FRENCH, SUBLANG_FRENCH
BEGIN
STRINGTABLE
BEGIN
LangMenu MENU
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
BEGIN
LangMenu MENU
LANGUAGE LANG_FRENCH, SUBLANG_FRENCH
BEGIN
MENUITEM "Version française" 22h
END
Capitalisation of nameIDs and types
Back to top
We have seen that a resource nameID can either be a string of
characters or a number. For each type of resource with a
particular language the nameID must be unique. Ie. two dialogs can have
the same nameID provided they have different language values.
We have also seen that a user-defined resource will have a resource
type identified by a string of characters or a number.
Now, the Resource Compiler will always convert the nameID or type to upper case when inserting them in the RES file or OBJ file. The reason for this is that this is expected by Windows. In practice this does not affect the way you use the resource because the system will also capitalise any nameIDs or types given to the resource APIs. For example suppose you have a dialog with a nameID of "MyDlg". Then to use the dialog you would pass the string "MyDlg" to the API CreateDialog. But in fact, the system converts the string to MYDLG and then looks for that string (as converted) in the executable.
This has two implications which you may need to be aware of.
Firstly it means that there would be a conflict in the above example if you had a second dialog (with the same language value) called MYDLG. This would be picked up at link-time by the linker.
Secondly, the Resource Compiler must ensure that not only English nameIDs or user-defined types are converted properly to upper case. So the Resource Compiler relies on the API CharUpper to do this conversion. This API can handle a number of languages properly, but it does rely on language mapping. Ensure that the machine used for compiling does support the language used in the nameIDs and user-defined types. Many languages do not actually have an upper case at all, in which case no conversion will take place.