Storing Constants in RCDATA Resources

Glossary

Constants can slip through the cracks of the localization process, because unlike dialogs or text strings, it's not always obvious that constants need to change. In general, you should design your program carefully to minimize the number of constants that must change from language to language, but you might not be able to eliminate all constants. For example, you might need constants to represent values, such as the average length of a word, in language-dependent calculations.

As with any other localizable resource, don't put constants in header files or you will be forced to recompile some source files. Win32 supports a customizable resource type called RCDATA, which is ideal for storing numeric constants.

For example, suppose you plan to customize default toolbar layouts for different language editions of your program because market research has shown that users in different countries have different preferences. The research tells you that your German toolbar (at left, below) should contain buttons for File Open, File Save, and Spell-checker. Your Japanese toolbar (at right) should contain buttons for Cut, Copy, and Paste.

It's easy to change the default appearance of the toolbar by customizing the large bitmap contained in the resource file. To change the commands, you need to change the default command identifier associated with each button's position in the toolbar. The toolbar declarations are as follows:

// German
TBBUTTON tbDefaultToolbar[] = {
{ 0, IDM_FILEOPEN, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
{ 1, IDM_FILESAVE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
{ 2, IDM_SPELLCHECK, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
};

// Japanese
TBBUTTON tbDefaultToolbar[] = {
{ 0, IDM_CUT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
{ 1, IDM_COPY, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
{ 2, IDM_PASTE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
};

Since the command IDs are different for German and Japanese, you can store them in an RCDATA structure and load them into the toolbar declarations at run time.

// GERMAN.RC
ID_TBCMDS RCDATA
LANGUAGE LANG_GERMAN, SUBLANG_GERMAN_STANDARD
BEGIN
IDM_FILEOPEN,
IDM_FILESAVE,
IDM_SPELLCHECK,
END

...

// JAPANESE.RC
ID_TBCMDS RCDATA
LANGUAGE LANG_JAPANESE, SUBLANG_JAPANESE
BEGIN
IDM_CUT,
IDM_COPY,
IDM_PASTE,
END

...

// TOOLBAR.C
#define nMaxDefaultButtons 3
#define iTBCmd 1
lpVoid lpDefaultCommands;

// Load toolbar resource.
HGLOBAL hglb = LoadResource(hMod,
FindResource(hMod, ID_TBCMDS, RT_RCDATA));
lpDefaultCommands = LockResource(hglb);

for (int i = 0; i < nMaxDefaultButtons; i++)
tbDefaultToolbar[i][iTBCmd] = lpDefaultCommands++;

UnlockResource (hglb);
FreeResource (hglb);

As mentioned in the beginning of this chapter, you shouldn't put strings in RCDATA structures unless you are willing to write localization tools to edit them.