symbian开发札记

 1, 栈问题
栈空间不足或者栈被破坏,不仅能导致程序崩溃,还能造成系统自动重启.解决方案
1) 在.mmp中用 EPROCSTACKSIZE 增大栈空间。但是需注意,EPROCSTACKSIZE的有效范围是8k到80k,默认值8k,如果申明的栈空间超过这个范围,应用程序是无法运行的,连main函数就进不了。
2) 正确使用栈,特别是CleanupStack. 比如如下错误就可能导致系统自动重启:
RSocketSrv socket.
socket.Connect();
CleanupClosePushL(socket);

....

CleanupStack::PopAndDestroy(2, &socket);

2,堆问题
如果应用程序new/malloc失败,多半都是堆空间不足造成的。解决方案是在.mmp中用 EPROCHEAPSIZE 申明堆空间大小(设定最小和最大值),默认大小是:最小4k,最大1M


3,Console问题
Symbian程序在设备上运行时,可以将调试信息输出到Console,只需要调用CConsole::Printf或者C的printf即可。实现该输出功能的程序,需要连接estlib.lib和euser.lib,但不能连接elibc.lib,否则,Console将无法显示。

 

4, 清除栈
清除栈不能滥用。一般来说,若当前函数异常返回后,已分配的内存无法被释放,这样的内存地址才需要加入清除栈,如在函数内部分配,释放的指针。
以LC结尾的系统函数,在返回前,它将返回值加入了清除栈,所以要记得将其从清除栈中弹出。
在非主线程以外的其他线程中使用清除栈,需要先用CtrapCleanup::NewL初始化清除栈,并在线程退出前释放。

5, 重载CAknDialog/CEikDialog的PreLayoutDynInitL时,需要首先调用ActivateL(), 否则,会造成系统崩溃。

6, 获得CAknAppUi/CEikAppUi的指针
在CAknView子类中直接用AppUi();
在CCoeContro子类中,用iEikonEnv->EikAppUi();

7, 可以同过重载Dialog的PreLayoutDynInitL或PostLayoutDynInitL实现动态创建控件/设置控件的内容,但通常都在函数PostLayoutDynInitL中实现,因为若在PreLayoutDynInitL实现的话,会导致Dialog在弹出时出现闪烁的现象。

 

8, 怎样给Dialog中的CEikEdwin添加Vertical Scrollbar
1) 在资源文件中,将CEikEdwinInclusiveSizeFixed添加到EDWIN的flags中,以便ScrollBar显示在CEidEdwin的内部;否则,显示在CEikEdwin外部,可能落在可视区域之外而在屏幕上无法看见。
2) 在Dialog中的PreLayoutDynInitL用static_cast(CEikEdwin*)(ControlOrNull(edwin_id)获取CEikEdwin的句柄,然后调用CreateScrollBarFrameL()(注: 创建ScrollBar)和ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff, CEikScrollBarFrame::Eon)(注:显示ScrollBar)

9,在Dialog中显示Listbox
RESOURCE DIALOG r_tmp_dialog
{
    buttons = R_AVKON_SOFTKEYS_OK_CANCEL;
    flags = EEikDialogFlagWait | EEikDialogFillAppClientRect;
    items =
    {
       DLG_LINE
       {
          type = EAknCtSingleGraphicListBox;
          id = ETmpListBox;  //The id of listbox
          control = LISTBOX
          {
             flags = EAknListBoxMenuList;
          }
       }
    }
}


10, 在View中创建Container时,一定要将对Container调用SetMopParent, 将其MopParent 设置成该View, 否则,container中的control可能会显示不正确,比如listbox的scrollbar, 在设备上可能显示不出来。

11, Listbox 在添加了item之后一定要调用HandleItemAdditionL, 删除文件之后一定要调用HandleItemRemovalL, 否则,listbox可能显示不正常,比如scrollbar显示不出来或无法隐藏等。

12, 改变CEikEditor的text颜色
CCharFormatLayer* formatLayer = CEikonEnv::NewDefaultCharFormatLayerL();

TFontSpec fontspec = LatinBold16()->FontSpecInTwips();
TCharFormat charFormat( fontspec.iTypeface.iName, fontspec.iHeight );
TCharFormatMask charFormatMask;
 
charFormat.iFontPresentation.iTextColor = KRgbBlack;
charFormatMask.SetAttrib(EAttColor);

charFormatMask.SetAttrib(EAttFontTypeface);
charFormatMask.SetAttrib(EAttFontHeight);

formatLayer->Sense(charFormat, charFormatMask);
formatLayer->SetL(charFormat, charFormatMask);
iEdwin->SetCharFormatLayer(formatLayer);



13, 将TTime以系统定义的格式输出
TBuf<64> string;
TTime time;
time.HomeTime();
time.FormatL(string, _L("%/0%1%/1%2%/2%3%/3 %-B%:0%J%:1%T%:2%S%:3%+B"));


14, 在Draw函数之外使用CWindowGc, 必须先调用ActivateGc(), 使用完毕后,调用DeactivateGc(), eg:
ActivateGc();
CWindowGc & gc = SystemGc();
gc.SetBrushStyle( CGraphicsContext::ENullBrush );
gc.Clear( Rect() );
DeactivateGc();

15, 修改窗口中控件的颜色
比如:文字颜色,背景色,Label边框色、文字颜色、背景色等。
CCoeControl::OverrideColor(EColorxxx, KRgbBlack);

16, CTrapClean & CScheduler
1) 默认情况下,系统会为.app和.exe建立cleanup stack。 但是,如果是子进程,或者线程,需要自己建立,并在退出前释放:如下:
CTrapCleanup *trapHandler = NULL;
if (User::TrapHandler() == NULL)
{
    trapHandler = CTrapCleanup::New();
}
//Others codes
delete trapHandler;
如果cleanup stack已经存在,就不要再建立,否则,可能会出问题。
2)默认情况下,系统会为GUI程序建立Active Scheduler。 但是对于其他程序,如命令行程序, 线程,则需要自己建立,并在退出前释放:
ActiveScheduler *scheduler = NULL;
if (CActiveScheduler::Current() == NULL)
{
    scheduler = new CActiveScheduler;
    if (scheduler != NULL)
    {
       CActiveScheduler::Install(scheduler);
    }
}

//Other codes;

if (scheduler)
{
    ActiveScheduler::Install(NULL);
    delete scheduler;
    scheduler = NULL;
}

如果系统没有建立Active Scheduler, 且程序中又使用到了Active Object, 并不是一定会出问题。 但是若出问题,一般在在跟异步函数或活动对象相关的地方,比如在调用WaitForRequest时,或在调用异步函数时。

17,RChunk
多进程可以使用RChunk共享数据(注意用Semophore或Mutex等保护共享数据区)。S60 2nd不能有static型数据,也可以借助RChunk代替static数据。

18, 可以在TRAP中是用返回值
TRAPD(errCode, retVal = FunctionL());
但是,只有当errCode是KErrNone时,retVal才有意义。但是,不要对LC函数是用返回值,否则可能会出问题:
TRAP(errCode, retVal = FunctionLC()); //Will lead out some problems
但是可以用:
TRAP(errCode, FunctionLC()); //OK

19, Client-Server间可以传递指针,但是只能是描述符(descriptor)的指针,不能是普通的、自定义数据类型的指针。如果需要传递非描述符指针,需要用TPckg打包成描述符指针。
class TTmpDataType
{
......
};

typedef TPckg<TTmpDataType> TTmpDataPckg;
TTmpDataType iDataSend;
TTmpDataPckg iPckgSend(iDataSend);

//Client end;
Tany *p[KMaxMessageArguments];
p[0] = &iPckgSend;
SendReceive(iStatus, p);

//Server end;
TTmpDataType iDataRecv;
TTmpDataPckg iPckgRecv(iDataRecv);
iMessage.ReadL(iMessage.Ptr0(), &iPckgRecv); //iMessage is received message of RMessage

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章