This section lists concepts essential to working with Symbian OS, and provides links to further information about them.
If you are new to C++ programming on Symbian OS, there are a few fundamental aspects to grasp before starting to develop applications on the platform, mostly related to the design of the operating system, which is purpose-built to run on portable devices. These, by their very nature, have limited memory, battery life and processing power. To manage these characteristics, Symbian OS provides, for example, lightweight string classes and an efficient event handling framework which will differ slightly from those offered by other operating systems.
This section will briefly summarise some of the features that you’ll find used most widely in Symbian OS code. For more detail on these and other Symbian OS APIs and techniques, you are recommended to consult the Essential Idioms section of the Symbian OS Library which also contains a number of example projects to illustrate the key points. The Resources section of this tutorial provides links to other comprehensive sources of information about Symbian OS, including the Symbian Developer Network site ('DevNet') and a range of books published by Symbian Press.
This section explains the most common Symbian OS naming conventions that are used in the example application. These conventions help to clarify the code; for instance, they tell you if a function can leave or if a class is allocated on the heap. See Naming conventions in the Symbian OS Library for more information.
If you browse through the class names typically used in Symbian OS
applications, you will notice that they begin with either C
,
M
, R
or T
. This letter indicates the
class's characteristics, and, in particular, its cleanup requirements:
classes that are allocated on the heap and need to be explicitly
deleted, begin with a C
. Other properties of C
classes are described in the Symbian OS Library under
Class types.
classes that do not own any resources and therefore don't have a
destructor use a T
prefix (for type). Typedefs
and enumerations also use an initial T
. T
objects are
normally used as automatics, allocated on the stack.
classes that use a handle to resources that are owned elsewhere, for
instance by a server, have an R
prefix (for
resource). Such classes normally use a Close()
function instead of a destructor to cause the resources to be cleaned up and
set the handle to zero.
classes beginning with the letter M
(for
mixin) are interface definition classes that normally consist
of only pure virtual functions, and never have member data.
Most Symbian OS header files contain occurrences of TInt
and
TBool
used instead of the C++ built-in types int
and
bool
. These, and some others, are typedefs (hence the
T
suffix) for the fundamental C++ types. You should use these
Symbian OS types rather than the C++ equivalent to guarantee compiler
independence. The basic types are documented in the Symbian OS Library: see
Basic Types.
As an aside, TBool
represents a Boolean, whose value may be
true (ETrue
in Symbian OS) or false (EFalse
). Because
C++ interprets any non-zero value as true, you should test the value of a
TBool
using code like:
if (boolVal) { ... };
or
if (!boolVal) { ... };
rather than, respectively:
if (boolVal==ETrue) { ... };
or
if (boolVal==EFalse) { ... };
Many function names end with an upper-case L
or
LC
. such as NewL()
or NewLC()
. This
suffix is significant; the L
indicates that the function (or any
function it calls) can leave.
The LC
suffix denotes a function that allocates an object and then
places it on the cleanup stack. It is important to follow this convention and
name any functions you write that may leave, or may leave and return after
putting objects on the cleanup stack, so code which calls your functions can
take the necessary steps to ensure that memory leaks are prevented.
Parameter names begin with a lower case a
(for
argument) and member data names begin with lower case
i
(for instance). Local variables use lower case
and no prefix. Constant names begin with upper case K
, but
enumerated constants begin with upper case E
.
Finally, you will see many occurrences of IMPORT_C
and
EXPORT_C
. These are macros that identify functions intended to be
called from outside of their own DLL. IMPORT_C
(in front of a
class method declared in a header file) and EXPORT_C
(in the
corresponding method definition within a .cpp
file) means that the
method will be exported, so that it can be called from code in other DLLs.
In general, therefore, with the exception of virtual and inline
functions, if you see a method defined in a header file for another library
whose prototype is not preceded by IMPORT_C
, this means that you
cannot call it, even if it has a public
access specifier. It will
not cause a compilation error, but you will see "unresolved
external
" linker errors if you attempt to use it in your code.
Instead of C++ exceptions, which were not part of the C++ standard when
Symbian OS was designed, the operating system uses a lightweight
exception-handling mechanism, called a ‘leave’. Leaves may
occur as a result of an error condition or abnormal event, such as insufficient
memory or disk space to complete a request. The leave propagates the error to a
point in the calling code where it can be handled, called a TRAP
harness, unwinding the call stack as it does so.
However, because of the ‘jump’, any local resources, such as memory allocated on the heap, will be ‘orphaned’, potentially leading to memory or resource handle leaks. Developers working on Symbian OS use the cleanup stack to keep track of resources to which the only pointer is an automatic variable. In the event of a leave, the cleanup stack will destroy each of the resources placed upon it.
Most leaves are caught by a TRAP
harness provided by the UI
framework, which will display an appropriate error message. However, there are
occasions when you will need to use a TRAP
harness yourself; you
can find out more about them from the
How to use TRAP page
of the Symbian OS Library.
There are some important places in code which should never leave – namely C++ constructors and destructors. Symbian OS classes typically use two-phase construction to avoid leaves occurring in construction code; see the Two Phase Construction section of the Symbian OS Library to find out more. More information can also be found in the Symbian OS Library, under Memory Management. You should also consult a Symbian Press text book, such as Symbian OS Explained, for detailed information about, and examples of the use of, these concepts.
Descriptors are Symbian OS strings, and are so-called because they are self describing. Each descriptor object holds the length of the string of data it represents as well as its 'type', which identifies the underlying memory layout of the data it holds. Because they hold length information, they do not need to be NULL-terminated and can thus be used to store binary data as well as text. Descriptors can also exist in either 8-bit ASCII or 16-bit Unicode format.
There are separate descriptor classes for data stored within the descriptor (the ‘buffer’ descriptors) or in a separate area of memory (the ‘pointer’ descriptors) and a further distinction between those which are stack-based and those created on the heap. Furthermore, there are descriptor types which may be accessed but not modified (that is, for look-up and comparison) and those which may altered by formatting, replacing or appending to the data. The following table summarises the descriptor classes:
|
Although there are a number of descriptor classes, which initially makes mastering the Symbian OS strings quite daunting in comparison to, for example, a scripting language, the classes all share the same base classes, as shown in the table above. The base classes provide common APIs for modifiable and non-modifiable descriptor operations, which are agnostic of the implementation type.
The filesystem browser example code which accompanies this tutorial uses
a number of descriptor functions such as Format()
,
Append()
, Zero()
, SetLength()
and
LocateReverse()
. Each SDK will also include a number of examples
designed specifically to demonstrate their use. For more information about
descriptors, and examples of their usage, consult the Symbian OS Library, books
in the Symbian Press series or any relevant technical papers in the SDK
documentation for your chosen UI platform.
As with applications on other operating systems, Symbian OS applications need to make both asynchronous function calls and receive asynchronous event notifications. For UI events, most of the work is done for by the Symbian OS UI framework, but other sources of asynchronicity (such as incoming data on a communications socket, interaction with hardware or use of a timer) are not wrapped by the application framework. To handle these, you typically create a class which submits a request to an asynchronous service provider and waits for its completion, supplying a function which is called when the event is received.
Symbian OS supplies a base class, CActive
, to be used as the
base for such classes; objects of such classes are known as active
objects. The wait loop in which they run is known as the active
scheduler. Consult the High Level Asynchronous Service Handling section of the Symbian OS Library for more
information about Symbian OS event handling using active objects and the active
scheduler. Further information and example can also be found in Symbian Press
books and technical papers.
Symbian OS uses ‘panics’ to halt the flow of program execution. Unlike a leave, which can be trapped, if a panic occurs in an application running on the phone, the application will be terminated. This does not make for a good user experience, and, for this reason, panics should only be used in assertion statements, to halt code when an unrecoverable error occurs.
Typically, assertions are used in debug builds to verify code logic and
program state, and are very useful when running code on the emulator because
the panic enters the debugger and allows you to investigate the root cause
using just-in-time debugging. The simplest assertion statement is
ASSERT
, which raises a "USER 0" panic in debug builds only.
__ASSERT_DEBUG
and __ASSERT_ALWAYS
allow you to
specify what action to take if the condition fails, for debug only and for all
builds respectively.
Although the macros allow you to specify the action when the assertion condition fails, the typical, and best, response is to panic and thus terminate the application. You can find out more about the use of the assertion macros from the Symbian OS Library; the Symbian OS system panic categories and numbers are documented in the System panic reference.
Symbian OS v9.1 is said to be a secure platform because of changes to the operating system to extend its security model and ensure more protection against malicious or badly-implemented software. The security model operates at the software level to detect and prevent unauthorised access (to hardware, software or data) which may, for example, lock up the phone, compromise user data, or affect other software or the network. The secure platform prevents programs from acting in unacceptable ways, irrespective of whether these actions are intentional or unintentional.
The impact of platform security on application development is described in this tutorial where it is most relevant to the discussion. For example, data caging, capabilities, Secure IDs and Vendor IDs are described in the mmp file syntax section. Data caging is also covered in the pkg file format section and is illustrated by the filesystem browser application. Configuring the platform security settings of the emulator is described in The emulator. Certification and Symbian Signed are discussed in the Application signing section.
Further information is also available in the Symbian OS Library, under Platform security and from a forthcoming Symbian Press book devoted entirely to this subject.
This tutorial is based on S60 3rd Edition and UIQ 3.0. It does not cover the migration of application code written for earlier versions of either platform. You should consult the appropriate SDK for a guide to changes in the new UIQ or S60 releases and information about how to update code written for previous versions to run on the new platform.
The previous sections have briefly introduced a few of the basic idioms used when developing C++ code on Symbian OS. There are many other aspects of the operating system that are important to know about if your application needs to use them, such as the communications programming, the filesystem, client-server design, ECOM, threading and, for all applications, good coding techniques.
To find out more, the first place to start is the Symbian OS Library. In addition, the Resources section of this tutorial provides links to other comprehensive sources of information about Symbian OS.