Helloworld程序详解

lxlxll 2010-09-02 03:42:03
加精
Hello World!First step to Symbian


S60 SDK的HelloWorldBasic例子@C:\Symbian\9.2\S60_3rd_FP1\S60Ex\HelloWorldBasic\group\bld.inf

详细文档@C:\Symbian\9.2\S60_3rd_FP1\S60Ex\HelloWorldBasic\doc

导入C:\Symbian\9.2\S60_3rd_FP1\S60Ex\HelloWorldBasic\group\bld.inf进Carbide C++

详细来看下Symbian的应用程序启动

1. EXE文件自E32Main()入口(在helloworldbasic.cpp中)


E32Main()调用NewApplication()创建一个HelloWorldApplication类实例,并返回其指针。Symbian随后使用该指针完成application的创建。

/**
* A normal Symbian OS executable provides an E32Main() function which is
* called by the operating system to start the program.
*/
GLDEF_C TInt E32Main()
{
return EikStart::RunApplication( NewApplication );
}


在同文件(helloworldbasic.cpp)中可以看到CHelloWorldApplication的创建

/**
* factory function to create the Hello World Basic application class
*/
LOCAL_C CApaApplication* NewApplication()
{
return new CHelloWorldBasicApplication;
}

下面跟踪一下Symbian的具体系统实现:

在eikstart.h里面来仔细看一下EikStart::RunApplication()

class EikStart
/**
This is the API to initialise and run the application architecture for applications built as exes.
It is not intended to be used for generally running applications from other code. Use RApaLsSession for that.

@publishedAll
@released
*/
{
public:
IMPORT_C static TInt RunApplication(TApaApplicationFactory aApplicationFactory);
private:
static void RunApplication(const TApaApplicationFactory& aApplicationFactory,CApaCommandLine* aCommandLine);
};

#endif

定义里面有一个工厂类TApaApplicationFactory,该类可以看作是建立应用程序的工厂。

在E32Main()函数中EikStart::RunApplication( NewApplication ),参数却是指向NewApplication函数的指针。

到apparc.h中去看TApaApplicationFactory类的定义:

class TApaApplicationFactory
/** Encapsulates the functionality of creating an application, whether it be via a factory function
or an ECOM plugin. Instances of this class can usually be created implicitly when required as
function parameters - just specify the function pointer, ECOM plugin UID or CImplementationInformation
reference.

@publishedAll
@released
@see CApaProcess
@see EikStart */
{
public:
typedef CApaApplication* (*TFunction)();
public:
IMPORT_C TApaApplicationFactory();
IMPORT_C TApaApplicationFactory(TFunction aFunction);
IMPORT_C TApaApplicationFactory(const CImplementationInformation& aEmbeddedApplicationInformation);
IMPORT_C TApaApplicationFactory(TUid aEmbeddedApplicationUid);
CApaApplication* CreateApplicationL() const;
HBufC* AppFileNameL() const;
TUid AppFileUid() const;
private:
enum TType
{
ETypeFunction, // if iType is this, iData is a TFunction
ETypeEmbeddedApplicationInformation, // if iType is this, iData is an ECOM CImplementationInformation
ETypeEmbeddedApplicationUid // if iType is this, iData is an ECOM implementation TUid
};
private:
static CApaApplication* CreateEmbeddedApplicationL(TUid aUid);
static HBufC* EmbeddedApplicationDisplayNameLC(TUid aUid);
static HBufC* FullAppFileNameL(const TDesC& aAppName);
static void CleanupImplementationArray(TAny* aImplementationArray);
private:
TType iType;
TUint iData;
mutable CApaApplication* iApplication; // used to be iSpare1
TInt iSpare2;
};

调用EikStart::RunApplication过程中,编译器创建一个TApaApplicationFactory对象,其构造函数的参数是NewApplication的函数指针。

这里面有隐式转换,可以查一下C++primer

we saw that a nonexplicit constructor that can be called with one argument defines an implicit conversion.the complier will use that conversion when an object of the argument type is suupplied and an object of the class type is needed .

可以以一个实参调用的非explicit构造函数(可能有默认参数)定义了一种隐式转换。
当我们需要该类类型对象时,而如果我们只提供了该类构造函数的形参类型的实参,这种转换就发生。
摘自C++primer 原版第四版 p535最后一段


conversion function can be defined for any type (other than void)that could be a function return type.in particular,convesions to an array or function type are not permitted.conversions to pointer types--both data and function poiters--and to reference types are allowed.

a conversion function must be a member function .the function may not specify a return type,and the parameter list must be empty.

摘自C++primer 原版第四版 p538第一段

这里还需要提到的是,CHelloNewApplication并没有使用Symbian最常见的new(ELeave)方式,而是使用了C++的new方式。这是因为在程序刚开始运行,TRAP harness还没有构建成功。如果系统不能为这个应用程序实例分配内存,则返回的实例指针为NULL,系统是可以处理这种异常的。

2. 系统获取UID

系统获取UID比较简单,在CHelloWorldApplication::AppDllUid()返回。

本示例UID宏定义如下,0xA0000000 到 0xAFFFFFFF属于非保护UID,一般供测试使用。

const TUid KUidHelloWorldBasicApp = { 0xA000017F };

3. 建立Document实例

系统调用CHelloWorldApplication::CreateDocumentL()创建Document实例并返回其指针。

注意,此时创建实例已经使用了Symbian中推荐的NewL静态函数来创建实例

CApaDocument* CHelloWorldBasicApplication::CreateDocumentL()
{
// Create an HelloWorldBasic document, and return a pointer to it
return (static_cast<CApaDocument*> ( CHelloWorldBasicDocument::NewL( *this ) ) );
}

具体来看一下其NewL函数实现内容:

在NewLC()中分配指针,PushL到清栈中,然后调用构造函数进行创建

在NewL()中,对上述操作后追加Pop弹栈处理

为什么要有两个NewL和NewLC?

NewL和NewLC都返回指针,区别就在于使用NewL已经弹栈,而使用NewLC还在清栈。

如果后续立即就使用该指针,在Symbian OS中必须要在清栈中处理这些指针防止内存泄露。如果使用NewL创建,还需要重新PushL进清栈,使用完毕再PopL。对于这类使用,请使用NewLC。

// -----------------------------------------------------------------------------
// CHelloWorldBasicDocument::NewL()
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CHelloWorldBasicDocument* CHelloWorldBasicDocument::NewL( CEikApplication& aApp )
{
CHelloWorldBasicDocument* self = NewLC( aApp );
CleanupStack::Pop( self );
return self;
}

// -----------------------------------------------------------------------------
// CHelloWorldBasicDocument::NewLC()
// Two-phased constructor.
// -----------------------------------------------------------------------------
//

CHelloWorldBasicDocument* CHelloWorldBasicDocument::NewLC( CEikApplication& aApp )
{
CHelloWorldBasicDocument* self = new ( ELeave ) CHelloWorldBasicDocument( aApp );

CleanupStack::PushL( self );
self->ConstructL();
return self;
}


5. 创建AppUI实例

系统调用Document类中的CreateAppUiL函数CHelloWorldBasicDocument::CreateAppUiL()创建AppUI实例并返回其指针。系统调用CHelloWorldBasicAppUi::ConstructL() 构造函数完成AppUI实例创建。

AppUI实例构造暂不介绍,有兴趣可以查阅CHelloWorldBasicAppUi::ConstructL()

再次注意的是,创建AppUI并没有使用两阶段构造。因为AppUi所属于系统,Document类实例并不需要也没有权限去销毁。

CApaDocument* CHelloWorldBasicApplication::CreateDocumentL()
{
// Create an HelloWorldBasic document, and return a pointer to it
return (static_cast<CApaDocument*>
( CHelloWorldBasicDocument::NewL( *this ) ) );
}

6. 创建AppView实例

使用两阶段构造法,调用 CHelloWorldBasicAppView::NewL() 创建AppView实例。

7. Draw the AppView

调用CHelloWorldBasicAppView::Draw() 。需要注意的是此Draw() 只能响应系统,在编程过程中不能直接调用,而需要使用DrawNow()。

8. 响应Menu菜单

在CHelloWorldBasicAppUi::HandleCommandL() 中响应Menu菜单各指令。

详细不做介绍,最后提一下,case default中panic为Symbian的系统严重异常处理。

void CHelloWorldBasicAppUi::HandleCommandL( TInt aCommand )
{
// clear possible old user-given text
iAppView->GetText().Zero();

switch( aCommand )
{
case EEikCmdExit:
case EAknSoftkeyExit:
Exit();
break;

case EHelloWorldBasicCommand1:
{
// Load a string from the resource file and display it
HBufC* textResource = StringLoader::LoadLC( R_HEWB_COMMAND1_TEXT );
CAknInformationNote* note = new ( ELeave ) CAknInformationNote;

// Show the information Note with
// textResource loaded with StringLoader.
note->ExecuteLD( *textResource );

// Pop HBuf from CleanUpStack and Destroy it.
CleanupStack::PopAndDestroy( textResource );
}
break;

case EHelloWorldBasicCommand2:
{
RFs fsSession;
RFile rFile;

// Connects a client process to the fileserver
User::LeaveIfError(fsSession.Connect());
CleanupClosePushL(fsSession);

//Open file where the stream text is
User::LeaveIfError(rFile.Open(fsSession,KHelloFileName, EFileStreamText));
CleanupClosePushL(rFile);

// copy stream from file to RFileStream object
RFileReadStream inputFileStream(rFile);
CleanupClosePushL(inputFileStream);

// HBufC descriptor is created from the RFileStream object.
HBufC* fileData = HBufC::NewLC(inputFileStream, 32);

CAknInformationNote* note = new ( ELeave ) CAknInformationNote;

// Show the information Note
note->ExecuteLD( *fileData );

// Pop loaded resources from the cleanup stack:
// filedata, inputFileStream, rFile, fsSession
CleanupStack::PopAndDestroy(4, &fsSession);
}
break;

case EHelloWorldBasicCommand3:
{
// Load a string from the resources and use it as a default value
HBufC* defaultText = StringLoader::LoadLC( R_HEWB_FILE_TEXT );

CHelloWorldQueryDialog *dlg = new (ELeave)
CHelloWorldQueryDialog( iAppView->GetText(), defaultText );

dlg->ExecuteLD( R_DIALOG_TEXT_EDIT_QUERY );

// Pop HBuf from CleanUpStack and Destroy it.
CleanupStack::PopAndDestroy( defaultText );
}
break;

default:
Panic( EHelloWorldBasicUi );
break;
}
}
...全文
6599 142 打赏 收藏 转发到动态 举报
写回复
用AI写文章
142 条回复
切换为时间正序
请发表友善的回复…
发表回复
zlqljlove 2010-09-18
  • 打赏
  • 举报
回复
听说这里牛 人很多
jechxx 2010-09-08
  • 打赏
  • 举报
回复
看不懂。。。
PengYuZhu 2010-09-08
  • 打赏
  • 举报
回复
一个HW程序都这么长
cxz6938561 2010-09-08
  • 打赏
  • 举报
回复
楼主好帅
furtherchan 2010-09-08
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 yuanjiao_jiang 的回复:]

楼主好犀利啊
[/Quote]只有引用的内容不允许回复!
xiaoxiuping 2010-09-07
  • 打赏
  • 举报
回复
S60 SDK的HelloWorldBasic例子@C:\Symbian\9.2\S60_3rd_FP1\S60Ex\HelloWorldBasic\group\bld.inf

zx246212 2010-09-07
  • 打赏
  • 举报
回复
谢谢,学习了
johnyabc 2010-09-07
  • 打赏
  • 举报
回复
真厉害,研究的很深,佩服,是我的学习的榜样,我收藏了,谢谢!
jueshifuqing 2010-09-07
  • 打赏
  • 举报
回复
学习了
ttgzs 2010-09-07
  • 打赏
  • 举报
回复
学习了!
jin328 2010-09-07
  • 打赏
  • 举报
回复
学习了
jin328 2010-09-07
  • 打赏
  • 举报
回复
写的太好了 佩服
pclizheng 2010-09-07
  • 打赏
  • 举报
回复
回帖是美德
uncleon 2010-09-07
  • 打赏
  • 举报
回复
很有难度
A12121AA 2010-09-06
  • 打赏
  • 举报
回复
号好评
nikigeng 2010-09-06
  • 打赏
  • 举报
回复
学写一下,谢谢啊!
maimang09 2010-09-06
  • 打赏
  • 举报
回复
受教了
jebai0521 2010-09-05
  • 打赏
  • 举报
回复
谢谢分享哦
gui2005 2010-09-05
  • 打赏
  • 举报
回复
学习了,希望后续有深入的介绍,谢谢
gui2005 2010-09-05
  • 打赏
  • 举报
回复
学习了,希望后续有深入的介绍,谢谢
加载更多回复(109)

3,120

社区成员

发帖
与我相关
我的任务
社区描述
塞班系统(Symbian系统)是塞班公司为手机而设计的操作系统,它的前身是英国宝意昂公司的 EP ( Electronic Piece of cheese)操作系统。
社区管理员
  • Symbian社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧