Resource Files

A resource file is a text file with an .rss file extension, used to specify user -visible elements of your application separately from the source code. Resource files are used to specify layout of UI elements such as menus , dialogs and lists, as well as any user-visible text used by the application. Every Series 60 application has at least one resource file associated with it.

A resource file is compiled into a binary file and accompanying header ( .rsg ) file by the resource compiler, as part of the standard abld build process. This binary file is then opened by the application framework upon application startup, and individual resources are loaded into the C++ code as needed, by means of the resource identifiers created in the .rsg file.

Keeping resource information separate from source code offers a major advantage to developers, namely that the UI appearance of the application can be substantially modified and rebuilt without the need to change the source code or recompile the application. This in turn makes applications much easier to localize (that is, convert to different languages and regional settings), as for a well written application only the resource file needs to be recompiled.

Resource File Syntax

The syntax of resource files is similar to that of C++, but not identical. Because the C preprocessor is used as the initial step in processing resource files, you can use both C and C++ style comments in resource files, as well as preprocessor statements such as #include , #define , #if , #else and #endif . All white space appearing in the resource file is ignored, unless it is within a string. The following first few lines of a resource file show preprocessor statements in use:

 /** * * @brief Example resource file * * @copyright EMCC Software Ltd * @version 1.0 */ //  RESOURCE IDENTIFIER NAME   RSF1 // 4 letter ID //  INCLUDES #include <avkon.rh> #include <avkon.rsg> #include <eikon.rh> #include <eikon.rsg> ... 

Additionally, resource files can also contain enum definitions. This means that a header file containing only enum definitions can be shared between resource files and C++ source files, and this is a common way of defining values shared between both types of file. Such a file is conventionally given the file extension .HRh . The following is an example of a simple .HRh file, taken from the SimpleMenu example:

 /** * * @brief Constants file for SimpleMenu application * * Copyright (c) EMCC Software Ltd 2003 * @version 1.0 */ #ifndef SIMPLEMENU_HRH #define SIMPLEMENU_HRH // Command ids enum    {    ESimpleMenuCmdNewGame = 0x6000,    ESimpleMenuCmdViaIR,    ESimpleMenuCmdViaBluetooth,    ESimpleMenuCmdViaSMS    }; #endif   // SIMPLEMENU_HRH // End of File 

.hrh files must contain only enumerations and preprocessor statements. Any other C++ syntax ”such as class declarations, constant integer values, and so on ”will cause the resource compiler to fail.


Any strings appearing in the resource file need to be enclosed in double quotes. For example:

 RESOURCE TBUF r_simple_string    {    buf = "Hello world";    } RESOURCE TBUF r_quoted_string    {    buf = "includes a \"phrase in quotation marks\"";    } RESOURCE TBUF r_copyright    {    // Create the string "A9 2003"    buf = <0x00A9>" 2003";    } 

Double-quote and backslash characters should be preceded by a backslash escape character: \" and \\ , respectively. Unicode characters can be included in a string by specifying the Unicode value between < and > symbols. Characters specified this way should not be enclosed within double quotes. The r_copyright resource in the example above shows you how to achieve this.

Note that it is bad practice to actually specify text strings in a resource file ”any user-visible text should instead be supplied in a localization file, as described in the Internationalization section of Chapter 4. The examples above are for illustration only and are not taken from a real example application.

Resource File Structure

This subsection covers the structure of Series 60 resource files. This structure can be divided broadly into two parts :

  • A header part containing include statements and some standard information about the resource file which is used by the resource compiler and application framework.

  • A body part defining a number of resources. Each resource declaration starts with the keyword RESOURCE .

The following describes each of these parts in detail:

Header Part

A resource file's header part consists of the following elements:

  • Name ” This is defined in a NAME statement, which must be the first meaningful line in your resource file (except, that is, for comments and white space). It specifies a four-letter name used to differentiate resource files in cases where an application uses more than one. The name therefore needs to be unique within an application, but need not be globally unique. (In other words, two resource files used by the same application must have different NAME values, but two resource files used by different applications can have the same NAME value.) You should also make sure that the name used is different from the names used in the system resource files, which are available for use by all applications.

  • Include statements ” As in C and C++, the #include statement imports other files, allowing a resource file to use symbols and structures defined elsewhere.

  • Signature ” The RSS_SIGNATURE is required by the application framework, and failure to include it in your resource file can cause a panic at runtime when the binary resource file is loaded. However, its contents are actually ignored, so you should just leave this resource empty, as shown below.

  • A document name buffer ” This is a TBUF resource which specifies the name of the default document for an application. Most Series 60 applications do not use documents, in which case the value is unimportant, but the resource must still be included. (Otherwise the application architecture will panic when loading the resource file.) Remember that you do not need to specify a file extension, as Series 60 native documents do not use extensions.

  • Application information resource ” The EIK_APP_INFO resource specifies various standard controls for an application, such as the status pane. It is common to create a resource specifying the new status pane contents and then refer to it using the status_pane field of the EIK_APP_INFO resource.

All of these parts can be seen in the following resource file example, taken from Controls :

 /** * * @brief Resource file for Controls application * * Copyright (c) EMCC Software Ltd * @version 1.0 */ //  RESOURCE IDENTIFIER NAME   CONT // 4 letter ID //  INCLUDES #include <avkon.rh> #include <avkon.rsg> #include <eikon.rh> #include <eikon.rsg> #include "Controls.hrh" #include "Controls.loc" // RESOURCE DEFINITIONS RESOURCE RSS_SIGNATURE { } RESOURCE TBUF { buf = "Controls" } // Default document name RESOURCE EIK_APP_INFO    {    status_pane = r_controls_status_pane;    } 

Body Part

The body of the resource file defines the resources that the application will use. Each resource is defined using the RESOURCE statement, as follows :

 RESOURCE  STRUCTNAME resource-name  {  resource-initializer-list  } 

You should replace STRUCTNAME with the type of the resource structure ( STRUCT ) you require. These are typically defined in .rh files, which you will need to #include in your .rss file. The system resource types are defined in avkon.rh , uikon.rh and eikon.rh .

The resources in the header part ( RSS_SIGNATURE , TBUF and EIK_APP_INFO , as seen above) are anonymous and should leave the resource-name blank.


For named resources, you should also replace resource-name with a unique name for your resource. The resource name you choose must be in lower case. By convention names begin with r_ , so, for example, to define a buffer called r_buffer_1 , you would create the following resource:

 RESOURCE TBUF r_buffer_1    {    buf = "text here";    } 

When the resource file is compiled, a constant representing the resource will be added to an .rsg header file generated by the resource compiler. The name given to this constant is the same as the name given to the resource in the resource file, but in uppercase. So, for the example resource defined above, a constant named R_BUFFER_1 will be created. Note again that user-visible text would not normally be inserted into a resource file.

The .rsg file is generated in \epoc32\include , with the same base name as your application's .app file. This is included (as a system include) in your C++ source, and the values defined in it are used to access individual resources. These values are known as resource IDs.

The following code shows how the buffer defined above might be read in from resource:

 #include <example.rsg> ... HBufC* buf = iCoeEnv->AllocReadResourceLC(R_BUFFER_1); 

Unfortunately there is no special type defined for resource IDs ”they are just handled as simple TInt values. By convention, however, functions that expect a resource ID as a parameter often name the parameter aResourceId . The context will also usually make it clear that a resource ID is expected.


The resource-initializer-list defines a set of values for the fields of the resource. Each initializer in this list has to be terminated with a semicolon. Each type of resource has different fields that you can include in the initializer list.

Specific details of the fields used by each control will be covered along with each individual control in the following chapters.


There are three different ways of initializing a field, depending on the type of the field you are initializing: simple initializers, array initializers and struct initializers. All three are shown in this example:

 RESOURCE EXAMPLESTRUCT r_my_example_struct    {    simple = EEikCtLabel;        // simple initializer    array = {1, 2, 3};           // array initializer    structmember = OTHERSTRUCT   // struct initializer       {       simple1 = "hello";       simple2 = "goodbye";       };    } 

  • Simple initializers assign a single value or string to a field.

  • Array initializers assign one or more values to an array field, formatted as a list of comma-separated elements inside braces.

  • Struct initializers assign one or more values to a STRUCT field. A STRUCT field is initialized by giving it the name of the required STRUCT and then specifying each field of that STRUCT . You need to be careful when doing this, as the resource compiler does not carry out type checking. This means that if you use the wrong type of STRUCT to initialize a STRUCT field, your program will compile, but it may panic at runtime. It is up to you to make sure you are using the correct STRUCT .

String Resources

As you have seen, strings can be included in a resource file using the TBUF resource. All user-visible, locale-specific text must be specified in resources and not in source code, in order to facilitate translation to other languages.

Additionally, it is usual to define string literals in a .loc file, or a language-specific .l xx file, rather than in the .rss file. This makes translation even simpler, as translators only need to see a file containing text strings, without all the resource definitions in the .rss file.

A .l xx file takes this principle one step further and allows for multiple files to be provided, each defining the same text strings in a different language. The xx should be replaced with a two-digit locale code specified by the TLanguage enum in e32std.h . The .l xx files are then included by the .loc file according to the current build locale set in the project .mmp file. Examples of each file discussed here are shown below.

First, the .rss file includes the .loc file for all of its string definitions:

 #include "MyApp.loc" ... RESOURCE TBUF r_hello    {    buf = STR_HELLO; // note: no string literals in the .rss!    } 

The .loc file in turn includes multiple .lxx files, depending on the current locale:

 #ifdef LANGUAGE_01     // 01 = (British) English #include "MyApp.l01" #endif #ifdef LANGUAGE_02     // 02 = French #include "MyApp.l02" #endif ... 

And finally, the .l01 and .l02 files define the strings in the respective languages. The .l01 (UK English) file would look something like this:

 #define STR_HELLO "Hello world!" ... 

To ensure that the correct strings are used when the resources are compiled, you should include one or more LANG statements in your .mmp file. The following lines in an .mmp file will ensure that resources are built for both English and French, resulting in two binary resource files being built: .r01 and .r02 :

 LANG 01 LANG 02 

Chapter 4 contains more information on localization.

Punctuation

You may have noticed that some lines in the resource file end in semicolons and some do not. Use the following rules when deciding whether or not to punctuate:

  • A semicolon is needed after any assignment.

  • Elements in a list are separated by commas.

  • There should be no semicolon after a resource definition, or after the last element in a list.

For example:

 RESOURCE AVKON_VIEW r_myapp_view    {    menubar = r_myapp_menubar; // assignment: semicolon needed    cba = r_myapp_cba;         // assignment: semicolon needed    }                          // end of resource definition:                               // no                               //   semicolon needed ... RESOURCE TAB_GROUP r_myapp_tabgroup    {    tab_width = EAknTabWidthWithTwoTabs;    active = 0;    tabs = {             // start of list       TAB               // first TAB STRUCT in the list          {          id = ENavigationPaneTab1;          txt = TAB1_TEXT;          },             // comma between elements in a list       TAB               // second TAB STRUCT in the list          {          id = ENavigationPaneTab2;          txt = TAB2_TEXT;          }              // end of list: no semicolon needed       };                // end of assigning list to "tabs":                         // semicolon needed    }                    // end of resource definition:                         // no semicolon needed 

The Menus and Standard Panes sections provide more information on these resources.

Creating Resource Structures

While the RESOURCE statement creates an instance of a specific resource, the STRUCT statement defines a type of resource. This allows you to create your own resources for your own controls. You should store any STRUCT definitions you create in a file with an .rh extension.

You can think of the STRUCT statement as being the resource file's version of the C++ struct or class statement, used to define a structure or class, and the RESOURCE statement as being analogous to creating a new object of the specified class.

The STRUCT statement is followed by the STRUCT 's name and then by a list of fields defined for this structure:

 STRUCT MYCONTROL    {    BUF buf;          // non-zero-terminated text string    LONG value = 0;   // a 32-bit integer with a default value    } 

Note that a STRUCT 's name must be all uppercase, with no spaces, and start with an alphabetic character. Subsequent characters can be letters , numbers or underscores. The name must also not start with any of: GLOBAL , STRUCT , LEN , RESOURCE or any of the STRUCT field types listed in Table 5-1. The STRUCT 's fields are listed within braces.

Each field in a STRUCT is defined with a field type, followed by a field name, an optional initializer and a semicolon. The type must be all uppercase, and the field name all lowercase. If a default value is provided, then this field can be omitted in a RESOURCE definition using this STRUCT , in which case the default value will be used.

Table 5-1. Resource File STRUCT Field Types

Field Type

Description

BYTE

A single byte. This can be interpreted as either a signed or unsigned integer.

WORD

Two bytes. This can be interpreted as either a signed or unsigned integer.

LONG

Four bytes. This can be interpreted as either a signed or unsigned integer.

DOUBLE

Eight bytes. This represents a double-precision floating-point number.

TEXT

A NULL-terminated string. This is deprecated: use LTEXT instead.

LTEXT

A Unicode string. This has a leading byte holding the length of the string, and no terminating NULL.

BUF

A Unicode string. This has no leading byte and no terminating NULL.

BUF8

An 8-bit character string. This has no leading byte and no terminating NULL. Use this to put 8-bit data into a resource.

BUF<n>

A Unicode string with a maximum length of n. This has no leading byte and no terminating NULL.

LINK

A 16-bit ID of another resource. This is like having a reference to the specified resource.

LLINK

A 32-bit ID of another resource.

SRLINK

The 32-bit ID of the resource in which this field is defined. This allows you to create a STRUCT with a reference to itself (SRLINK stands for Self-Referencing LINK). The value for a field of this type is assigned automatically by the resource compiler ”you cannot supply an initializer yourself.

STRUCT

A STRUCT. This creates a field that is itself a STRUCT, allowing you to embed STRUCTs within STRUCTs.


As well as these simple fields, a field can also be defined as an array of values of the same type. To define a field to be an array, add a pair of square brackets after the field name, as follows:

 STRUCT MENU_PANE    {    STRUCT items[]; // MENU_ITEMs    LLINK extension = 0;    } 

This shows the MENU_PANE STRUCT defined in \epoc32\include\uikon.rh . The Menus section of this chapter will explain the MENU_PANE and MENU_ITEM STRUCT s in more detail; but for now, the items field provides an adequate example of an array field.

The items field allows you to have any number of MENU_ITEM STRUCT s in this resource, each separated by a comma. Each element in this array should be a STRUCT of type MENU_ITEM s. Further information on resource files can be found in the Resource File Format section of the SDK documentation.



Developing Series 60 Applications. A Guide for Symbian OS C++ Developers
Developing Series 60 Applications: A Guide for Symbian OS C++ Developers: A Guide for Symbian OS C++ Developers
ISBN: 0321227220
EAN: 2147483647
Year: 2003
Pages: 139

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net