[Book] Developing Series 60 Applications for Symbian OS (1-3)

A good book for Symbian C++ developer

https://files.cnblogs.com/nickong/Addison.Wesley.Developing.Series.60.Applications.A.Guide.for.Symbian.OS.C.Developers.rar

My Reading Diary(读书笔记)

(一)Getting familiar with Symbian OS generic technology structure



1. Symbian OS Base Layer : The developer interface to most of the base Operating System functionality is through the EUser Library, via a huge range of static function calls beginning with User::  or example, User::After(), which causes the current thread of execution to be suspended until a specified time interval has expired.
 
2.Series 60 Structure
as shown as below:

3.The Avkon library defines many user interface components and application framework components. Some key examples are:

  • Status pane:framework and contents

  • Main pane:listbox, form, options menu, grid, query, note, soft notification and settings page

  • Control pane:soft keys and scrolling indicator

可编译为三种格式输出: S60 Binary format ARMI,ARM4,THUMB
长剑格式类型:.h , .cpp, .rss (user interface resource (.rss) files)

(二)Getting familiar with Development Process

 1. Two universal project files "Projectname.mmp" and "bld.inf",These two text files can be used as a starting point.The "bld.inf" file specifies the names of all the project component(s) to be built, with each component specified in its own .mmp file.
       Typically you employ a Symbian tool called bldmake, using the two project specification files as input, to generate a command file called abld.bat. You can then use abld.bat, from the command prompt, to perform a number of project-related actions. For example, abld.bat can be used to generate platform- and IDE-specific project makefiles. If the project source code exists, and is complete, abld can be used to build the project for one or more platforms.
      A project definition (.mmp) file specifies the properties of a project component in a platform- and compiler-independent way. It may then be used, along with the bld.inf file, by the SDK build tools (abld.bat) or an IDE to produce platform-specific makefiles. 
      A mmp project file sample:

 // HelloWorld.mmp file
TARGET           HelloWorld.app
TARGETTYPE  app
UID                    0x100039CE 0x101F6148
TARGETPATH \system\apps\HelloWorld
LANG                01
SOURCEPATH ..\src
SOURCE           HelloWorldApplication.cpp
SOURCE           HelloWorldAppUi.cpp
SOURCE           HelloWorldDocument.cpp
SOURCE           HelloWorldContainer.cpp
RESOURCE       ..\data\HelloWorld.rss
RESOURCE       ..\data\HelloWorld_caption.rss
USERINCLUDE . ..\inc
SYSTEMINCLUDE \epoc32\include
LIBRARY          euser.lib apparc.lib cone.lib eikcore.lib
LIBRARY          eikcoctl.lib avkon.lib commonengine.lib
AIF                   HelloWorld.aif ..\aif HelloWorldaif.rss c12 context_pane_icon.bmp context_pane_icon_mask.bmp list_icon.bmp list_icon_mask.bmp    (Notes:  bitmap (.mbm) and icon (.aif) files )
 

.mmp Statement

Function

TARGET

The name of the application, which must have the correct filename extension: .exe, .app,.dll and so on.

TARGETTYPE

Defined as app (this option determines the value of UID1), meaning this is a GUI application. There are many other types, including dll, exe, tsy, csy and ldd.

UID

Specifies a unique system identifier (UID2) for a GUI application: 0x100039CE and 0x101F6148 that is absolutely unique to the application itself (UID3). UID2 and UID3 are not required for .exe applications. UIDs are explained in the next section of this chapter.

TARGETPATH

The location of the final built application and its components梩his is always under \system\apps\relative to the root of a device drive or an emulated drive such as c: or the emulated ROM (z:) drive.

LANG

This statement is used if an application is to support different languages. Each language supported has a two-digit code. This is described later in this chapter in the Localization of Applications and Resources subsection. It is also covered in more detail in Chapter 4.

SOURCEPATH

The location path of the source files for the project.

SOURCE

This statement refers to the name(s) of the source file(s) for the project. This statement can occur multiple times and can have multiple filenames on each statement line.

RESOURCE

Refers to a source file that defines the majority of the user interface elements, such as menus, dialogs, text strings and so on. Also the source file for the application captions.

USERINCLUDE, SYSTEMINCLUDE

These statements refer to the location of the application-specific header files for the project with path information for system header files. All Symbian OS projects should specify \epoc32\include\for their SYSTEMINCLUDE path梤elative to the root of the SDK.

LIBRARY

Lists the application framework and graphics libraries required for linking to梩hese are the .lib files corresponding to the shared library DLLs whose functions you will be calling at runtime.

AIF

The statement refers to an Application Information File (.aif) that contains icons and other application properties defined in the application resource file. .aif files are explained later in this chapter. The application details and characteristics are specified in the text-based resource file HelloWorldaif.rss, and the source bitmaps and masks for the icons are listed as a series of Windows .bmp files. The c12 parameter refers to the color depth (12-bit) to be used when the files are converted from .bmp to Symbian OS .mbm format as part of the icon creation.


在程序包含的头文件中,还可以惊喜地发现许久未谋面的C++关键字inline。看样子真的是手机编程,不能滥用资源啊。
缺省情况下S60的栈大小是8KB,堆(Heap)的大小是1M。当然,可以在MMP文件中通过修改EPOCSTACKSIZE 来进行更改。
来看这个例子,NOKIA的FORUM上下下来的例子:S60_Platform_Map_and_Location_Example_v1_0。
在被包含的文件目录..\inc下看这个文件 mapexample.pan


#ifndef __MAPEXAMPLE_PAN__
#define __MAPEXAMPLE_PAN__

enum TMapExamplePanics
    {
    EMapExampleViewsBasicUi = 1
    };

inline void Panic( TMapExamplePanics aReason )
    {
    _LIT( applicationName,"mapexample" );
    User::Panic( applicationName, aReason );
    }

#endif // __MAPEXAMPLE_PAN__

关于内联,啰唆两句:在c++中,为了解决一些频繁调用的小函数大量消耗栈空间或者是叫栈内存的问题引入了内联函数。
内联函数缺陷:1.只适合函数体内简单函数的调用,不能包含复杂的结构控制语句(WHILE,SWITCH)
                           2.不能递归调用
下面有个图,It will enable us to unstand the applicition very well.


Warnning about the project name :  Keep the name of your application to 16 characters or less (case is not significant)!

2.Source Code Structure

File Name

Contents

Class Module

Comments

HelloWorldApp.h

Class and function declarations

The application

Application creation/initialization

HelloWorldApp.cpp

Class and function definitions

   

HelloWorldAppUi.h

Class and function declarations

The application UI

Command handler/controller

HelloWorldAppUi.cpp

Class and function definitions

   

HelloWorldDocument.h

Class and function declarations

The document

Owns the data or application model

HelloWorldDocument.cpp

Class and function definitions

   

HelloWorldContainer.h

Class and function declarations

The application's data view

Displays the application's data

HelloWorldContainer.cpp

Class and function definitions

 
from this table, 我们可以看出来,程序和各个功能模块之间的对应关系。基本上,书看到这里,第一次接触S60的很多疑问已经烟消云散了。可以说,已经可以开始动手写程序了。当然,before that, we still need to know something about the application UI design. we are going to get to know Resource Files.

3.Resource Filse & Other Header files
      Resource Source Script (.rss) files (for example, HelloWorld.rss) are used by applications in Symbian OS to define the way a GUI application will look on screen. Much of the information that defines the appearance, behavior and functionality of an application is stored in a resource file. Created external to the main body of the executable, everything from the status pane, menus, general user interface controls, through to individual dialog boxes can be defined in the resource file. Compilation of resource files generates a binary output file plus an .rsg header file that is #included into C++ code to identify specific user interface resources such as text strings, dialogs and menu components.
      Note that avkon.hrh (located in \epoc32\include) contains many enumerated constants defined by the Series 60 user interface and application framework. This is a very important file for Series 60 applications.

4.Localization of Applications and Resources
      If your application is to be distributed outside of your own locale, then localization needs should be considered from the outset of a project. Each supported language has a two-digit identifier code; for example, English is 01, French is 02 and German is 03. These language codes are all defined in \Epoc32\Include\e32std.h. For each language you will typically create a specific text file by having the default language file translated. Each language file can then be conditionally included in the main application resource file at build time. The process of localizing an application in this way is demonstrated by a variant of the HelloWorld example used in this chapter, called HelloWorldLoc. Each specific text file typically has the two-digit language code forming the last two characters of the filename extension. So, in the HelloWorldLoc variant of this example project you will see there are three variants of the included text file with extensions of .l01, .l02 and .l03 for the English, French and German variants.
      Resource files compiled for specific languages will typically have filename extensions such as .r01, .r02, .r03 and so on, and the user may be given a choice of language at install time. The default compiled resource file has the extension .rsc; any language variant can be renamed to this extension during installation. A Series 60 project file (.mmp) can list the supported languages via the LANG statement.
LANG 01 02 03

When a full project build is performed, the system will compile the English (01), French (02) and German (03) resources for the application.


(三) Basic concepts in Symbian OS development (Symbian编程基础)


1.Naming Conventions 命名规则
类名由以大写字母为前缀的单词构成例如: T,S,C,R,M或者N. 其它和标准C++类似。
注意:栈和堆的区别 

    1)SYMBIAN中栈是大小固定的后进先出(LIFO)的一块内存,为各个程序保留的。存放临时数据。比如,局部变量。

    2)堆是由系统根据程序的需要动态分配的。其大小可由程序控制,比如:malloc函数在C中的功能就是个例子,当然NEW在C++中也是这个道理,在SYMBIAN中,需要更为复杂的方法来分配堆。

1.1 T类

所有带有T字母为前缀的类,都表示一个简单类,没有堆或其它资源,因此,她们不需要显式析构。当然,这中简单的类也可以具有简单的接口。比如TRect类,用于显示一个矩形区域,具有Width(),Height(),Shrink()等等接口。T类没有基类的哦,所以使用前务必构造好。

1.2 S类

这种类很少被用到,本书中可将S类视为T类

1.3 C类

所有带C开头的类均表示该类从CBase类继承而来。这些类被设计为在堆中构造,而非栈。前缀C表示“CleanUp”(清洁)。这里不敷述了。CBase类有一个重载的NEW运算符来初始化所有的成员数据。意味着:不需要对CBase类对象进行成员数据的初始化。(仅仅用于C类),C类的例子有CActive和CArray。

1.4 R类

带R字母开头的类表示一个资源的客户端句柄(Client-side handle)。这些资源实际上并不属于某个程序,而是属于该设备上的其它某个Symbian的服务器。客户端可以使用这些句柄访问这些由该服务器管理的资源。

For example, the CElementsEngine class connects its file system session (iFs, an RFs instance) when the class is constructed, and closes it in its destructor:

void CElementsEngine::ConstructL()
{
User::LeaveIfError(iFs.Connect());
}
CElementsEngine::~CElementsEngine()
{
iFs.Close();
}
注意:Symbian oS有两个命名数据的规则:所有的类属性(成员数据)必须以小写的"i"作为前缀,如iFs,
   所有的函数参数都以小写字母"a"作为前缀。自动类型无转换。
1.5 M类
   M类是混合类,表示一个接口,只包含纯虚函数,这些虚函数需要继承接口的派生类来实现。
 

1-1                                  主要类

   

   

    

T类、类型

TdesCTPointTFileName

T类没有析构函数。它们的操作类似内置类型。这就是为什么全部内置类型的typedefT开始。T类可以分配为自动量(如果它们不是太大的话),作为其他类的成员,或分配到堆上。

C

CAvtiveCBase

派生于CBase的类。C类总是在默认堆上分配。当分配对象时,CBase的运算符New()总是将全部成员数据初始化为零。CBase也包括一个虚析构函数,所以,通过在CBase*指针上调用delete,正正确销毁它指向的所有C对象。

R

RFileRTimerRWriteStreamRWindow

任何拥有不在默认堆上的资源的类。通常分配为成员变量或自动变量:在少数情况下,可以在默认堆上分配。大多数R类使用Close()释放它们的关联资源。

M类、接口

MGraphicsDeviceMapMGameViewCmdHanlerMEikMenuObserver

由虚函数组成的接口。实现该接口的类应该从它派生。在Symbian OS中,只赞成M类使用多重继承;它们的操作与Java中的interface类似。旧的技术术语是“混合类”,所以使用了“M”。

静态类

UserMathMemConeUtils

只由不能实例化为对象的静态函数组成的类。这样的类是库函数的有用容器。

结构

SEikControlInfo

C风格的结构,没有任何成员函数。在Symbian OS中,只有少数结构:大多数较新的代码使用T类(甚至对于struct也是如此)。

TCR之间的差别对于清除非常重要。一般而言,T类不需要清除,因为它们不分配资源,R类获得需要关闭或释放的资源,C类需要被删除。
2. Macro(宏)及清理栈
常见的有 IMPORT_C, _LIT,_UHEAP_MARK等。IMPORT_C在E32DEF.H中定义,表示从DLL中导入函数。告诉编译器,这个函数可以在DLL中找到。
最近在看nokia上下载下来的源代码的时候,经常看到CleanupStack::PushL(...);这样的语句,这是系统用来清理栈空间的手段。手机编程不比在
WIN上面,要养成良好的编程习惯。比如调用可能异常的函数时,我们要这样:
void mySampleCall()
{
CSampleInstance* myInstance = new(ELeave)CSampleInstance;
CleanupStack::PushL(myInstance);
myInstance->DoSomethingL();
CleanupStack::Pop();
delete myInstance;
}

 注意
:类成员不需要压入清理栈中,因为释放类成员是由析构函数来做,如果压入清理栈,就会出现二次删除。程序会产生二次删除异常。

清除栈能解决栈中分配对象的清除问题,但是拥有指针指向的是自动变量。如果分配了对象的函数异常退出,则需要清除该对象。

下面的代码摘自示例cleanup;菜单项“User 3”由如下代码处理:

case ECleanupCmdUse3:

     {

     CX x*=new (ELeave) CX;

     x->UseL();

     delete x;

     }

函数UseL()分配内存,而且可能异常退出。代码如下:

void CX::UseL()

     {

     TInt* pi new (Eleave) Tint;

     delete pi;

     }

这段代码在两个地方可能出错。第一个地方是,配置CX时可能失败,如果这样,代码将立即异常退出,而不会产生任何危害行为。第二个地方是,如果TInt的分配在UseL()中失败了,则函数UseL()异常退出,同时,仅被函数HandleCommandL()中的自动变量x所指向的对象CX永远都不会被删除。内存成为独立的内存,即发生了内存泄漏。
case ECleanupCmdUse3:

     {

     CX x*=new (ELeave) CX;

     CleanupStack::PushL(x);

     x->UseL();

     CteanupStack::PopandDestroy(x);

     }

  如果不借助于清除栈,也可以采用类似如下代码来完成:

 case ECleanupCmdUse3:

     {

     CX* x = new(ELeave)  CX;

     TRAPD(error, x->UseL() ) ;

     if(error)

         {

         delete x;

         User: :Leave (error);

         }

     delete x;

     }

 不过这种方式不够完美。对于一长串操作序列,清除栈则工作得非常好,例如:

 case ECleanupCmdUse3:

     {

     CX* x = new(ELeave)CX;

     CleanupStack:: PushL(x);

     x->UseL();

     x->UseL();

     x->UseL();

     CleanupStack:: PopAndDestroy();

     }

 任何一个UseL()调用都可能失败,如果只是为了解决清除问题,而不得不为每一个L函数提供捕获装置的话,那就会显得非常凌乱。
如名称所暗示,清除栈是一个栈,可以向该栈中加入多个数据项。例如,可以编写如下代码:

case ECleanupCmdUse3:

     {

     CX* xl = new(ELeave) CX;

     CleanupStack::PushL(xl);

     CX* x2 = new(ELeave)CX;

     CleanupStack::PushL(x2);

     xl->UseL();

     CleanupStack::PopAndDestroy(2);

     }

调用PopAndDestory(2)中的2导致最后两项从栈中移除并销毁。
当这么做时,必须注意,从清除栈中移除的项不要多于放到它上面的项,否则程序将出现严重出错。

当不需要清除栈时,不要使用它。





 3. 描述符(Descriptor)

描述符就是一个用来存储文本或二进制数据的基本类。该类提供了数据存储以及访问的一系列操作。
主要有以下几种:
-------------------------------------
_LIT 宏
TBuf和TBufC 缓冲区描述符
TPtr和TPtrC 指针描述符
HBufC 堆缓冲区描述符
-------------------------------------

使用举例:

_LIT(KMessage,"The quick brown fox jumps over the lazy dog.\n\n");    //KMessage赋值为 字符串
_LIT(KMessage1,"Cool lar. \n\n");
_LIT(KMessage2,"fox. \n\n");


TBuf<40> buf;      //定义一个TBuf类对象buf

buf=KMessage;     //初始化buf

buf.Append(KMessage1);   //在buf末尾添加KMessage2

buf.Insert(10,KMessage2);



How to convert the contents of TBuf to TInt?

TInt iNum1(123456789009876);// 15-digcit number

iBuf.Num(iNum1);           // set the content of the buffer to iNum1

TLex iLex(iBuf);// create TLex object using iBuf containing the 15 digit number

TInt iNum2;     // To retrieve value from iBuf and later compare with iNum1

iLex.Val(iNum2);//iNum2 contains the 15 digit number now




4.活动对象(Active Object)

简要分析事件处理线程活动规划器活动对象一起的工作方式:
 

线程可以有许多活动对象。每个活动对象只与一个具有请求函数的对象关联,该函数使用TRequestStatus&参数。当程序调用活动对象的请求函数时(在前面看到的延迟hello示例中为SetHello()函数),活动对象将请求传递给异步服务提供器。它将自己的iStatus成员作为TRequestStatus&参数传递给请求函数;调用请求函数以后,它立即调用SetActive()

TRequestStatus是一个32位对象,应当带有一个完成代码。在开始执行请求函数之前,异步服务提供器设置TRequestStatus的值为KRequestPending(定义为0x80000001)。

当异步服务提供器完成处理请求,它产生一个事件。这意味着,它以信号通知发出请求线程的请求信号量,也给TRequestStatus传递一个完成码(例如KErrNone或其他标准错误码,除了不允许KRequestPending外)。

活动规划器负责检测事件的发生,以便关联它和请求它的活动对象,并在该活动对象上调用RunL()

活动规划器调用User::WaitForAnyRequest()检测事件。这个函数挂起该线程,直到一个或多个请求完成为止。然后活动规划器扫描它的全部活动对象,搜索哪个活动对象已经发出请求(设置iActive),哪个活动对象的请求已经完成(iStatus为非KRequestPending值)。它清除该对象的iActive,并调用它的RunL()。当RunL()完成,规划器再次调用User::WaitForAnyRequest()

因此,对于每个User::WaitForAnyRequest(),规划器只处理一个事件。如果多个事件未处理,也不会发生问题:下一个User::WaitForAnyRequest()将立即完成,而不挂起该线程,规划器将查找与完成的事件关联的活动对象。

如果规划器不能发现与事件关联的活动对象,这表示发生了所谓的“游离信号”编程错误。活动规划器使该线程出错
 

     向异步服务提供器发出请求函数,记住在完成后调用SetActive()

     使用RunL()处理完成的请求

     使用DoCancel()能够取消请求

     设置合适的优先级

     使用RunError()处理RunL()的退出

实际上,在活动规划器可以处理活动对象的RunL()之前,如果多次收到信号,它必须决定首先服务于哪个活动对象。这是给活动对象分配优先级的原因。具有最高优先级值的活动对象首先处理。

CActive类定义一组基本优先级值(由TPriority枚举封装),应用程序框架定义另外一组TActivePriority。大多数应用程序将使用CActive::EPriorityStandard作为它们的标准优先级值,但是如果对于自己的活动对象,需要使用非零值,那么将需要分析枚举值,以便可以保证使用它们是合适的。








posted @ 2007-08-30 11:35  RayG  阅读(1102)  评论(2)    收藏  举报