【转】Symbian 开发提示(2)

如何枚举出正在运行的App 结合RApaLsSession和TApaTaskList应该可以做到. RApaLsSession: GetAppIcon() GetAppInfo() TApaTaskList: FindApp() 从收件箱读取彩信图片 mmslist实现了首先以listbox列表的形式列出了收件箱中的所以彩信,选择某一条彩信后可以显示出它的发送端号码和彩信的文本信息;现在我想让它显示发送端号码和彩信图片(假设我的彩信都是图片格式);请教两位应该怎么才能实现读彩信图片并显示的功能。 下面是读彩信文本信息的代码,你们参考一下: void CMmslController::GetMessageL( const TDesC& aItem, TDes& aMessageText ) const { //Read the message Uid from aItem TUint32 id = 0; TLex lexer( aItem ); lexer.SkipSpace(); TChar ch( lexer.Get() ); while ( ( ch != ‘/t’ ) && ( ch != 0 ) ) // Finding end of 1.st line { ch = lexer.Get(); } lexer.SkipSpace(); lexer.Val( id, EHex ); if( iCurEntries->Find( id ) == KErrNotFound ) { return; } CMsvEntry* msvEntry = iSession->GetEntryL( id ); CleanupStack::PushL( msvEntry ); const TMsvEntry& msgEntry = msvEntry->Entry(); CBaseMtm* clientMtm = iMtmReg->NewMtmL( msgEntry.iMtm ); CleanupStack::PushL( clientMtm ); clientMtm->SwitchCurrentEntryL( msvEntry->EntryId() ); // An instance of the TDesOverflow derived class used to suppress // the panic that would be generated if buffer length was exceeded // in calls to AppendFormat TOverrideOverFlow noOflo; // Text is located in iDescription field. aMessageText.AppendFormat( msgEntry.iDescription, &noOflo ); //aMessageText.AppendFormat( msgEntry.iDetails ); CleanupStack::PopAndDestroy( 2 ); // clientMtm, msvEntry } 如何让程序在安装后自动运行 如何让一个程序(或是一个server)在安装后自动运行于手机中,这是非常容易的,只需在你的PKG文件中,在包含你的app或exe文件的那行末尾加上“FR,RI”。 “FR”表示“File Run”,而“RI”则表示“Run during Installation”。请注意,务必要先开始rsc,aif,mbm文件的安装,然后才能是APP等(也就是在pkg文件的末尾进行app的安装) 举例: “/Symbian.1/Series60/Epoc32/release/thumb/urel/MyApp.rsc” - “!:/system/apps/MyApp/MyApp.rsc” “/Symbian.1/Series60/Epoc32/release/thumb/urel/MyApp_caption.rsc” - “!:/system/apps/MyApp/MyApp_caption.rsc” “/Symbian.1/Series60/Epoc32/release/thumb/urel/MyApp.aif” - “!:/system/apps/MyApp/MyApp.aif” “/Symbian.1/Series60/Epoc32/release/thumb/urel/MyApp.app” - “!:/system/apps/MyApp/MyApp.app”,FR,RI 文件类型和从属关系 下图显示了在一个典型的Symbian程序中各文件的从属关系。 [attach]457[/attach] .hrh文件中包含所有要在.rss、.h和.cpp中使用的枚举类型。它们主要使用在应用程序的菜单、工具栏等地方,下面展示了一个典型的例子: //MyApp.hrh // enum{   EMyAppCmdOpenFile = 0×6000,   EMyAppCmdEdit, }; 按照惯例这些命令ID值的范围应该从0×6000开始向上。 .rss文件中是资源文件,这些文件包括所有静态字符串、按钮、菜单和列表等的定义,都使用在应用程序UI中。此外,Nokia Series 60向导还可能生成一个.loc文件,这个文件同.rss文件很相似但只用于描述你程序中的静态字符串,利用它你可以很容易的将程序变成多语言版本。 .rsg是生成的资源文件。它们是在编译时刻由资源编译器产生的,.cpp文件将包含它们以便处理资源。 .mbm是symbian位图文件,它里面可以存储几个位图。 .mbg是在创建.mbm时生成的。这些文件一般包含在那些使用位图的RSS文件中,一个mbg文件包括在.mbm中各位图的ID。 网络通讯中正确显示中文 1。经过对照GB2312/GBK编码表,在程序中定义_LIT8(KTest, “中文测试”);是GB2312/GBK编码 2。直接从输入框取出的字符串,经过按照byte分析并比较中文和unicode对照表,发现是UTF-16LE(Sixteen-bit UCS Transformation Format, little-endian byte order)编码 3,中文对服务器的传输建议统一处理成UTF8编码进行,从对话框获得的也一样处理,服务器需要对应识别过来的字符串并做处理。 如何动态更改CEikLabel 的text CEikLabel* iLabelStatus; ….. iLabelStatus = new (ELeave) CEikLabel; iLabelStatus->SetContainerWindowL( *this ); iLabelStatus->SetTextL( this->iStatusStr ); …. //动态在这里更改 iLabelStatus->SetTextL(iStatusStr); iLabelStatus->DrawNow(); 如果初始化时就无法显示,请对照helloworld代码检查自己label是否设置正确;如果是进度进行中无法显示,请检查cactive是否正确执行,单步DrawNow是否被正确调用。 在listbox中怎么处理所选项的事件 触发事件并不是很复杂的事情, TKeyResponse CXXContainer::OfferKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType) { TInt code = aKeyEvent.iCode; switch(code) { // is navigator button pressed case EKeyOK: { // pass the key press event to view, // then view will pass it to ui class’s handler iXXView->ProcessListEvent(iListBox->CurrentItemIndex()) ; } return (EKeyWasConsumed); case EKeyLeftArrow : case EKeyRightArrow : return (EKeyWasConsumed); default: // Let Listbox take care of its key handling return iListBox->OfferKeyEventL(aKeyEvent, aType) ; } } 这个iXXView的ProcessListEvent()函数就是传入当前用户选择的那个list item的index。 2007-4-10 08:42 Moving pkg文件中指定多个操作系统版本 pkg file定义了安装文件(sis)的内容,它包括应用程序的UID,一个支持的语言列表,目标产品的UID和打包在sis的一组文件: ; MyGame.pkg ; Specifies an installation file for MyGame ;Languages &EN ;Header #,(0×1000ABCD),1,0,0 ; Required line for Series 60 devices. Defines the target product ; UID. (0×101F6F88), 0, 0, 0, “/epoc32/release/thumb/urel/MyGame.app”-“!:/system/apps/MyGame/MyGame.app” “/epoc32/release/thumb/urel/MyGame.rsc”-“!:/system/apps/MyGame/MyGame.rsc” “/epoc32/release/thumb/urel/MyGame.mbm”-“!:/system/apps/MyGame/MyGame.mbm” “/epoc32/release/thumb/urel/MyGame.aif”-“!:/system/apps/MyGame/MyGame.aif” “../MyGame/MyGameSample.wav”-“!:/system/apps/MyGame/MyGameSample.wav” Product UID定义了应用程序的目标环境,大部分的s60版本是向下兼容的。 参见下表: Nokia 7650 0×101F6F87 Nokia 3650 0×101F7962 Nokia 9210/9290 0×10005E33 Nokia N-gage 0×101F8A64 Siemens SX1 0×101F9071 Series 60 Platform v0.9 0×101F6F88 Series 60 Platform v1.0 0×101F795F Series 60 Platform v1.1 0×101F8201 Series 60 Platform v1.2 0×101F8202 Series 60 Platform v2.0 0×101F7960 如果程序需要依据各不同的平台来进行安装,那就可以使用条件语句块来处理,这时pkg里的语句如下: ; ; Files to install ; IF MachineUID=0×101fb3dd ; Nokia 6600 specific files “../MyFiles/FileFor6600.dat”-“!:/system/apps/MyGame/MyData.dat” ELSEIF MachineUID=0×101f466a ; Nokia 3650 specific files “../MyFiles/FileFor3650.dat”-“!:/system/apps/MyGame/MyData.dat” ELSE ; Files for other devices “../MyFiles/FileForOthers.dat”-“!:/system/apps/MyGame/MyData.dat” ENDIF 就可以生成一个支持多平台的安装文件,除了机器UID外,还有很多属性,如内存和CPU的标识: 注意,机器UID和Product UID是不同的,见下: Nokia 7650 0×101F4FC3 Nokia 3650 0×101F466A Nokia 6600 0×101FB3DD Nokia 9210/9290 0×10005E33 Nokia N-Gage 0×101F8C19 Win32 Emulator 0×10005F62 可以使用如下的代码来找出该设备的机器UID: #include //and link with hal.lib TInt machineUid = 0; HAL::Get(HALData::EmachineUid, machineUid); 如何按字节读取文件 1.RFile::Read() TInt Read(TDes8& aDes,TInt aLength) const; Description Reads specified number of bytes of binary data from file — synchronous overload. 2.Typedef TText8 typedef unsigned char TText8; 如何取出Symbian手机中的信 方法有两个: 1 确定出他们的路径,用文件的方式读; 2 用系统给这两个部分提供的API 通讯录方面的(别人的代码网上找的): _LIT(KNameLabel,”Name”); _LIT(KMobileLabel,”Mobile”); _LIT(KName,”Steve”); _LIT(KMobile,”+8613900000000″); // Open the default contacts database: CContactDatabase* contactsDb = CContactDatabase::OpenL(); CleanupStack::PushL(contactsDb); // Create a contact card and add some fields: CContactItem* contact = CContactCard::NewLC(); CContactItemField* field = CContactItemField::NewLC(KStorageTypeText, KUidContactFieldFamilyName); field->SetMapping(KUidContactFieldVCardMapUnusedN); field->SetLabelL(KNameLabel); field->TextStorage()->SetTextL(KName); contact->AddFieldL(*field); CleanupStack::Pop(); field = CContactItemField::NewLC(KStorageTypeText, KUidContactFieldPhoneNumber); field->SetMapping(KUidContactFieldVCardMapTEL); field->SetLabelL(KMobileLabel); field->TextStorage()->SetTextL(KMobile); contact->AddFieldL(*field); CleanupStack::Pop(); // Add the new contact to the database and set it as the own card: contactsDb->AddNewContactL(*contact); contactsDb->SetOwnCardL(*contact); CleanupStack::PopAndDestroy(2); // contact contactsDb 短信的: CMsvEntry或 CMsvServerEntry 怎么使用BUTTON 类创建一个 BUTTON S60里面好像没有BUTTON的类吧 1.好像没有必要做BUTTON,触发事件使用MENU就可以了 2.如果非要做的话,可以尝试的下面的简单方法 2.1 使用一个LABEL(设置一下边框属性可以使这个LABEL像一个所谓的BUTTON) 2.2 可以在该LABEL的所处CONTAINER的 OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType); 处理KEY事件(判断该LABEL拥有FOCUS) 图标资源的读取与储存结构 可以在AknView类中定义如下的图标数组进行储存图标数据结构,这种结构有图表位图和蒙板(mask) CArrayPtr* iIconArray; 具体实现方法: iIconArray->AppendL(CEikonEnv::Static()->CreateIconL(iMbmFile, EMbmFile1, EMbmFile1_mask)); 在需要贴图标的地方用这个数组句柄引用即可 一段左软键菜单的控制代码 要求:1点了左软键之后,就相当与点了ok键。 2 :把左软键菜单的地方由option改为select // My.rss RESOURCE EIK_APP_INFO { menubar = r_bmpmanip_menubar; // cba = R_AVKON_SOFTKEYS_OPTIONS_EXIT; cba = R_AVKON_SOFTKEYS_SELECT_BACK; // see “epoc32/include/avkon.rsg” } // MyAppUi.cpp void CMyAppUi::HandleCommandL(TInt aCommand) { switch(aCommand) { case EAknSoftkeySelect: // see “epoc32/include/avkon.hrh” { // left softkey is pressed… } … } } } 如何在CAknGrid上绘制背景图 从CAknGrid派生自己的子类,然后自己draw,如: void CYourGrid:raw(const TRect& aRect) const { CWindowGc& gc = SystemGc(); gc.DrawBitmap(aRect, aYourBitmap); CAknGrid:raw(aRect); } 2007-4-10 08:46 Moving 两种从资源文件中读取常量的方法 第一种 是老的方法了 要先 #include 才可以用 TBuf<64> buf; CEikonEnv::Static()->ReadResource(buf,R_APP_LABEL); R_APP_LABEL 就是我们在资源文件中定义的常量 第二种 新方法 要先 #include HBufC* buf; buf=StringLoader::LoadLC(R_APP_LABEL); 在此之前要求先把资源文件给加进来噢, 格式 #include < 项目名.rsg> 如何取得imei #ifndef __WINS__ TPlpVariantMachineId imei; PlpVariant::GetMachineIdL(imei); aImei.Copy(imei); #else 如何在Series 60窗体上绘制标签 这是一种在Series 60窗体上显示标签的方法。你可以在电量图标或信号图标旁边显示一个标签,为此需要用程序实现。我使用了从CCoeControl继承的CIndicatorIcon 这个类。你需要象这样创建ConstructL(): void CIndicatorIcon::ConstructL() { iMyWindowGroup = RWindowGroup(iCoeEnv->WsSession()); User::LeaveIfError(iMyWindowGroup.Construct((TUint32)&iMyWindowGroup)); iMyWindowGroup.SetOrdinalPosition(0, ECoeWinPriorityAlwaysAtFront); iMyWindowGroup.EnableReceiptOfFocus(EFalse); CreateWindowL(&iMyWindowGroup); // 默认设置指示标签静止 SetIndicatorIconL(EIndicatorIconAppActive); ActivateL(); } 在ConstructL()中,我调用了另一个函数 SetIndicatorIconL()设置标签: void CIndicatorIcon::SetIndicatorIconL(TIndicatorIcon aIndicatorIconType, TBool aRedraw) { switch(aIndicatorIconType) { case EIndicatorIconEmpty: iIndicator = CEikonEnv::Static()->CreateBitmapL(KSysIconFile, EMbmAvkonQgn_prop_empty); iIndicatorMask = CEikonEnv::Static()->CreateBitmapL(KSysIconFile, EMbmAvkonQgn_prop_empty_mask); break; case EIndicatorIconAppActive: iIndicator = CEikonEnv::Static()->CreateBitmapL(KSysIconFile, EMbmAvkonQgn_bt_connect_on); iIndicatorMask = CEikonEnv::Static()->CreateBitmapL(KSysIconFile, EMbmAvkonQgn_bt_connect_on_mask); break; case EIndicatorIconAppInactive: iIndicator = CEikonEnv::Static()->CreateBitmapL(KSysIconFile, EMbmAvkonQgn_prop_bt_audio); iIndicatorMask = CEikonEnv::Static()->CreateBitmapL(KSysIconFile, EMbmAvkonQgn_prop_bt_audio_mask); break; default: break; } SetRect(TRect(TPoint(KIndicatorPosX, KIndicatorPosY),iIndicator->SizeInPixels())); // 如果 aRedraw == ETrue 从新绘制画布 if(aRedraw) { DrawNow(); } } 你需要跳过CCoeControl的Draw()函数代码如下 : void CIndicatorIcon::Draw(const TRect& aRect) const { CWindowGc& gc = SystemGc(); gc.Clear(); gc.SetBrushStyle(CGraphicsContext::ENullBrush); gc.BitBltMasked(TPoint(aRect.iTl.iX, aRect.iTl.iY), iIndicator, TRect(TPoint(0, 0), iIndicator->SizeInPixels()), iIndicatorMask, ETrue); } 现在把这些行加入到程序AppUi类的ConstructL()中: iIndicatorIcon = CIndicatorIcon::NewL(); // 下一行将画标签并绘制到屏幕上 iIndicatorIcon->SetIndicatorIconL(CIndicatorIcon::EIndicatorIconAppInactive, ETrue); 判断E盘是否可用 TDriveInfo driveInfo; TInt error = fs.Drive(driveInfo, EDriveE); User::LeaveIfError(error); if (driveInfo.iDriveAtt == KDriveAbsent) { // drive E is absent } Reference: “How to retrieve drive and volume information” http://www.symbian.com/developer/techlib/v8.1adocs/doc_source/guide/Base-subsystem-guide/N1007E/FileServerClientSide/FileServerClientSideGuide2/DriveAndVolumeExample.guide.html 读取symbian上文件的例子 RFile igpFile; RFs fs; TInt aSeek = 0; TInt aFileSize; TBuf16 igpName16; TParse parse ; parse.Set(CEikonEnv::Static()->EikAppUi()->Application()->AppFullName(), NULL, NULL); TBuf16<128> igpFullName ; igpFullName.Copy (parse.DriveAndPath()) ; igpFullName.Append (_L(”dice1.igp”)); fs.Connect(); // Write to file for later usage igpFile.Open( fs, igpFullName, EFileRead | EFileStream ); igpFile.Seek( ESeekEnd, aSeek ); aFileSize = aSeek; aSeek = 0; igpFile.Seek( ESeekStart, aSeek ); aFileBuffer = HBufC8::NewL( aFileSize ); igpFile.Read( aFileBuffer->Des (), aFileSize ); igpFile.Close(); fs.Close(); 2007-4-10 08:48 Moving 正确响应FORM的OK和BACK事件 TBool CMyForm::OkToExitL ( TInt aButtonId ) { if (aButtonId == EAknSoftkeyOk ) { ….. } else if( aButtonId == EAknSoftkeyBack ) { …… } } 流读取windows编写的txt文件 // Open file1 _LIT(KMyFile,”c://documents//file1″); RFile myFile; User::LeaveIfError(myFile.Open(fs,KMyFile,EFileShareExclusive|EFileWrite )); // Write to current file position: start of file _LIT8(KWriteBuf,”write data”); myFile.Write(KWriteBuf); // Read from position 0: start of file TBuf8<6> readBuf1; myFile.Read(0,readBuf1); // readBuf1 is now “write ” // Read from current position TBuf8<4> readBuf2; myFile.Read(readBuf2); // readBuf2 is now “data” 得到CEikEdwin输入的数据 TBuf<128> buf; CEikEdwin* edwin = STATIC_CAST(CEikEdwin*, Control); edwin->GetText(buf); Symbian生成随机数的方法 无论开发什么程序,尤其是类似纸牌类游戏和拼图类,以及俄罗斯方块之类的游戏, 随机数发生器是必不可少的。标准c语言里面有seed()和rand()用来生成种子和数值 在symbian平台下面,用什么方法呢?下面就是一个例子 TTime theTime( KAknExNoteInitializeTime ); theTime.UniversalTime(); TInt64 randSeed( theTime.Int64() ); // 采用时间初始化随机数种子 TInt number( Math::Rand( randSeed ) % KAknExNoteRandomNumberRange ); // 这里就是调用了 生成的结果放在number中。 Symbian中把字符串变成数字的方法 我们知道C语言中又很方便的函数,很多种方法可以把字符串变成数字, 比如 char * p = “100″ ; int a; a = atoi(p) ; // 此时a的值就是100了。 或者用这种办法也可以,就是慢点: sscanf(p, “%d”, &a) ; 这样也可以达到同样的效果。 但是symbian开发环境中遇到这种情况,我们该怎么做呢? 我们可以考虑采用TLex类,来实现同样的功能。 TBufC buffer = _L(”124″) ; TLex8 lex; TInt value; lex.Assign((const unsigned char*) buffer.Ptr()); if(lex.Val(value) == KErrNone) { // 证明转换没有问题,你可以在value中使用buffer里面的字符串格式的数据了。 } 2007-4-11 08:04 Moving Symbian应用程序中如何备份和载入 在S60 3rd中,默认情况下将不被支持。支持备份将使你的应用程序用户界面更加友好,做备份的用户(或者只有一小部分)期望自己的所有应用程序可以被备份。让我们来满足这些用户的需求,大多数情况下,这是非常容易的…… 使应用程序可以备份文件的另一个原因是Symbian Signed。它不是一个强制的,但是,你的应用程序没有意识到备份的问题,你必须通知Test House 或者他们可能认为你的备份功能失败。再说一次,大多数情况下,备份是非常简单的。 程序备份基础 如果你想使应用程序具备备份功能,以下是最起码要做到的(也就是说,只能执行和相应的资源文件,没有数据可以被支持): 1. 写一个backup_registration.xml文件,内容如下: CODE: 2. 添加它到你的PKG文件 CODE: “backup_registration.xml”-”!:/private//backup_registration.xml” 添加私有数据到你的备份文件 另外一个常见的需求就是保存数据内容到你的私有文件夹(位置在/private/)。添加以下申明到你的backup_registration.xml 文件中(使用标签): CODE: 你也可以保存所有内容到”nobackup” 私有目录: CODE: 你也可以指定些文件代替文件夹: CODE: 添加公共文件到备份文件中 在前面的内容中,“/”目录被指定为应用程序的私有目录。如何保存那些在私有数据以外的数据呢?这个也很简单,你可以使用另外的一个XML标签。可以用 标签来替换 ,路径相对于你手机的根目录(不需要指定驱动器): CODE: 所知到的Bug 不幸的是,包含一些bug会影响备份和重新载入特性: 1. 位于C:/System 的数据不被支持:非工作区,除非指定数据到其他位置…… 2. 使用开发证书(developer certificate),应用程序的备份和载入会失败。这一点是很可怕的:你测应用程序的试备份恢复仅仅只能在你注册了自产生证书(self- generated certificate)的时候。如果你使用开发证书(developer certificate)是不行的,你的应用程序将能够备份,但是恢复的时候会失败。 作者不能计算在第二点上到底花费了多少时间,作者说至少花费了一个下午的时间去尝试用开发证书(developer certificate)测试它。 Symbian程序中的观察者模式 Symbian程序中的观察者模式 在这个站点上有很多关于Symbian程序外表的文章,很少有关于架构设计的观点。在以下的文中中,我介绍一下在Symbian应用程序中的观察者模式,我会用一些有意义的类名来代表整个Symbian程序的设计流程。在这个应用程序中,将告诉你在一个Symbian程序中如何使用 Engine和前台,UI接口,和用户直接的交互。在文章中,我已经给了一种解决的方案。在接下来的文章种,我将介绍另外一种方法,通过内嵌类。让我们开始应用程序的引擎类和它的观察者,我们创建了一个观察者接口 MObserver,定义如下: CODE: class MObserver { public: virtual void CallbackFunction1() = 0; }; 接口,它有一个纯虚函数,它必须被一个创建类实现。在我们的例子中,Engine(引擎类)将实现它: CODE: class Engine : public MObserver { public: Engine(CAppUi& aAppUi); void CallbackFunction1();//From MObserver void DoSomething(); Subject& GetSubject(); private: Subject* iSubject; CAppUi& iAppUi; }; 从名字可以清晰的看出,Engine类有一个Subject类,他是实际上在后台工作的类;CAppUi 类是核心与视图的用户接口。引擎创建一个Subject类,通常在Symbian程序中,CAppUi 类是通过veiw类表现数据到用户接口的(UI)。 Subject类申明如下: CODE: class Subject { public: Subject(MObserver& aObserver); void DoSomething(); private: MObserver& iObserver; }; 很明显,Subject类链接了它的观察者iObserver。Symbian程序在一般情况下,在后台通过一些异步函数,Subject类将继承至 CActive类而工作。这里有一个 DoSomething()将调用一些异步函数,这个函数也将调用MObserver中的CallbackFunction1()。 CallbackFunction1 函数将更新AppUi 应用程序或引擎和UI中相关的表现形式。因此让我们来看看CAppUi类的申明: CODE: class CAppUi { public: CAppUi(); Engine& GetEngine(); void PrintToUI(char* msg); virtual ~CAppUi(); private: Engine* iEngine; }; AppUi类的作用是,创建应用程序的引擎。记住,应用程序和Engine已经循环的引用,整个的流程如下: AppUi将创建引擎; Engine创建Subject; AppUi通过一些菜单命令调用Engine中的DoSometing函数; Engine将委派一些任务通过Subject类的DoSometing函数; Subject的DoSometing函数将通知通过CallbackFunction1创建Observer; Subject的DoSometing函数看上去如下: CODE: void Subject::DoSomething() { //Call the Asynchronous function //Now Notify the Observer regarding this. iObserver.CallbackFunction1(); } Observer中的这个回调函数将打印AppUi中消息通过函数PrintToUi。这个函数将呈现从Engine得到的消息到Veiw中。 希望这篇文章能讲清楚一些Symbian入门者对于如何使用UI的疑惑。 IMPORT_C关键字释义 在Symbian程序中我们经常会看到IMPORT_C这个关键字,它是C:/Symbian/8.0a/S60_2nd_FP2_SC/epoc32/include下e32def.h文件里面定义的一个宏. 原定义如下: #define IMPORT_C __declspec(dllexport) 那么__declspec(dllexport)又是什么东东呢? 先看代码: 以下是在dev-c++里建立自已的dll时的dll.h里面的代码,这里面有一个_declspec(dllexport) #ifndef _DLL_H_ #define _DLL_H_ //防重复定义 #if BUILDING_DLL # define DLLIMPORT __declspec (dllexport) #else /* Not BUILDING_DLL */ # define DLLIMPORT __declspec (dllimport) #endif /* Not BUILDING_DLL */ DLLIMPORT void HelloWorld (void); #endif /* _DLL_H_ */ 上面代码里面的_delcspce(dllexport)被定义为宏,这样可以提高程序的可读性!这个的作用是将函数定义为导出函数,也就是说这个函数要被包含这个函数的程序之外的程序调用!本语句中就是:void Helloword(void) 摘自msdn:在 32 位编译器版本中,可以使用 __declspec(dllexport) 关键字从 DLL 导出数据、函数、类或类成员函数。__declspec(dllexport) 将导出指令添加到对象文件 若要导出函数,__declspec(dllexport) 关键字必须出现在调用约定关键字的左边(如果指定了关键字)。例如: __declspec(dllexport) void __cdecl Function1(void); 若要导出类中的所有公共数据成员和成员函数,关键字必须出现在类名的左边,如下所示: class __declspec(dllexport) CExampleExport : public CObject{ … class definition … }; 生成 DLL 时,通常创建一个包含正在导出的函数原型和/或类的头文件,并将 __declspec(dllexport) 添加到头文件中的声明。若要提高代码的可读性,请为 __declspec(dllexport) 定义一个宏并对正在导出的每个符号使用该宏: #define DllExport __declspec( dllexport ) __declspec(dllexport) 将函数名存储在 DLL 的导出表中。 2007-4-11 08:08 Moving 如何让程序支持皮肤功能 标题: Form UI component要支持皮肤 设备, 软件 版本: S60 2nd Edition, FP3, Nokia N70, Nokia N90 S60 3rd Edition 说明: 在S60第二版,FP3设备上使用CAknForm UI component时,如果程序不支持皮肤,则该控件将无法正确绘制。 详细描述: 如果一个运行在S60第二版,FP3设备上的程序,使用了form(CAknForm),那它必须要支持皮肤,否则程序将无法绘制该表单。 我们在程序UI类(从CAknAppUi中继承)的构造函数ConstructL()中通过传递EAknEnableSkin参数来让程序支持皮肤功能。 void CMyAppUi::ConstructL() { BaseConstructL(EAknEnableSkin); … } 这个form布局的问题在S60第二版FP3模拟器上不会出现。 情景重现: 比较一下设置及不设置EAknEnableSkin情况下我们使用CAknForm的情况。 这个我们可以通过使用CAknForm类的SDK示例程序(如Form, Popupfield example)来具体。 在S60第二版,FP2设备上获取电量状态 标题: 在S60第二版,FP2设备上获取电量状态 设备, 软件 版本: S60 2nd Edition, FP2 说明: 直到S60第二版,FP2,电量值都是通过RSystemAgent中如systAgent.GetState(KUidBatteryStrength)获得的,但现在方法返回错误代码-19。那在S60第二版,FP2设备上是否有其他方法可供使用呢? 解决方案: 这些值在新版中确实有所改变,而公开文档中却并未写上。 你可以通过使用下列值来查询电量状态。 Code: // The current battery status information const TInt KUidBatteryCStatusValue = 0×100052D8; const TUid KUidBatteryCStatus = {KUidBatteryCStatusValue}; enum TSABatteryCStatus { ESACBatteryOk, ESACBatteryLow, ESACBatteryEmpty, ESACPowerOff }; // The amount of battery bars const TInt KUidBatteryBarsValue = 0×100052D3; const TUid KUidBatteryBars ={KUidBatteryBarsValue}; enum TSABatteryBars { ESABBars_0, ESABBars_1, ESABBars_2, ESABBars_3, ESABBars_4, ESABBars_5, ESABBars_6, ESABBars_7 }; 检查离线模式 在S60第三版中,我们通过读取Centrol Repository中的电话设置来检查离线模式是否启动。 要获得情景模式的设置,只有对Central Repository进行调用才行: Code: #include #include CRepository* cr = CRepository::NewLC( KCRUidProfileEngine ); TInt value; // Get ID of current profile User::LeaveIfError( cr->Get( KProEngActiveProfile, value ) ); // Check value to determine the active profile if ( value == 5 ) { // current profile is the offline profile } // … 要了解更多关于Profile Engine的信息,可阅读SDK的帮助文档和“Profiles Engine Active Profile Settings API.” 第三版中的ETel库 受争议的ETel库在第三版中已经去掉了,去掉的库包括ETel Core和ETel MM(etel.h和etelmm.h),在第三版中之后一个公共的电话API将被提供那就是CTelephony API(etel3rdparty.h和etel3rdparty.lib) 安全共享数据及数据库加密 从Symbian OS v9.x后就不再提供数据库加密机制了,保护你数据库不被其他程序访问的唯一方法就是将数据库文件存储在你的私人数据空间。不过这样其他程序也就没法访问到它了。 Symbian OS v9.x中所介绍的安全共享数据库的方法为,通过data caging机制保护并共享数据。 数据库是通过DBMS client-serve API来生成并被访问的。数据库文件被存储在DBMS server的data cage文件夹中。DBMS server根据与此数据库预先关联的安全法则允许其他客户端程序去访问它。这种安全法则可以规定客户端只能具有ReadDeviceData能力。为了向数据库写入东西,客户端得具有WriteDeviceData能力,和一个给定的Secure ID(SID) 不幸的是,安全法则目前只能存放在Z盘中。这意味着第三方开发者无法定义或安装他们自己的安全法则。同样,当第三方程序需要使用一个好的方法来同享数据库时,也没有能使用的预先配置的法则。 如果你的程序需要访问一个共享数据库,那下列选项是可以考虑的: 将数据库存放在一个共同目录下(如果不需要考虑安全性问题) 为你的服务提供一个API以访问存储在自己 If for your applications require access to a shared database, the options available are - share a database stored in a public folder (if there are no security concerns) - write your own server that provides an API to access a database stored in its own data cage folder. If data encryption needs to be used, you must provide your own encryption mechanism in both cases. S60第三版中对messaging components(MTM)的性能需求 S60第三版上,因为平台安全性的考虑,对公共DLL有很多要求。 这会在下列方面影响messaging component(MTM)的开发使用: 所有public-size MTM component都需要“ALL-TCB”属性,因为他们要被其他public-side application所加载(这些程序拥有设置其的能力) Public-side MTM component主要为:Client MTM, UI MTM, 以及UI Data MTM. 而private-side MTM component既Server MTM,要和加载进程拥有一样的能力。你的server-side MTM component应该拥有下列能力: ReadDeviceData, WriteDeviceData, ProtServ, NetworkControl, NetworkServices, LocalServices, ReadUserData. Given these heavy capability requirements any MTM implementation has to go through the Symbian Signed process and will need to assign all needed UIDs from the protected UID range (0×00000000 - 0×7FFFFFFF). 实现Tab页 carbide.c++编程非常考验人的是所有的资源必须自己定义,然后在程序中引用这些自定义的资源。这让习惯了windows可视化编程的程序员非常的头痛。不过也好,这样更能让我们清楚地了解到symbian资源文件的结构和调用方法。 实现Tab页,首先要在.rss文件中定义Tab页所需要的资源,其中包括Tab页的数量,Tab页的Title。然后在***AppUI.cpp 文件的construct函数中生成该Tab页。其次,还要在***container.cpp文件的按键处理事件中编写相关的代码,以实现Tab页的切换。 带完整键盘的S60第三版设备上的按键映射 设备, 软件 版本: S60 3rd Edition 说明: 在一些S60第三版手机上有完整的键盘,其中一些键值只有通过FEP模式下编辑框才能获得 详细描述: 在Nokia E61以及E70等带全键盘的机器上运行的程序时,如果要捕捉CCoeControl派生类下的按键事件时,在FEP模式下的编辑框中是无法获取同样键值的(通过TKeyEvent::iCode)。 这是因为QWERTY键盘的映射是依赖于当前的语言和输入模式的。例如,在Nokia E61上,CCoeControl派生类在数字键盘被按下时总是获得1,2,3。。。。而只有在FEP模式下的编辑框中(如CEikEdwin)它才能获取字母键”r”,”t”,。。。等。 注意scan codes(TKeyEvent::iScanCode)是不会受当前语言或输入模式影响的。 解决方案: 应用程序在处理文本输入时,应该使用表示准的Avkon编辑框控件。 2007-4-11 08:11 Moving S60第三版SDK中MMF框架API的问题 详细描述: S60第三版SDK中缺少MMF Controller Framework头文件和库,这样的话,我们将不会搜索到关于MMF的信息和媒体格式插件,这将导致一些MMF的相关引用。如 CVideoRecorderUtility在构造时就需要Controller和格式UIDs。 解决方案: MMF Controller Framework的支持将有望在s60第三版后面加入 SymExpat 面向OS 9.x的端口 起初我认为把SyEpxpat应用于OS 9.x的端口将会引起一系列的变化。然而,结果却并非如此。 最简单的修订是针对xmlparse.c的. 看起来expat 开发人员把返回代码枚举和错误代码枚举混为一谈,因此对于主要expat 源编码来说更改它就足够了。 一个稍微有点欺骗性的问题是由GCCE带来的。看起来其似乎对XMLCALL进行了一些定义。似乎 GCCE认为它支持微软扩展,但实际上只在有些情况下可行。 我认为这一问题的根源是_MSC_EXTENSIONS。因此为了修订它,首先,我们需要确定expat-config.h 是在源文件中expat.h文件之前定义的,之后便是定义XML调用并且停止运行expat-external.h使之恢复默认设定。 唯一的改变是让SyExpat.cpp 文件在包含expat.h 之前包含expat-config 文件,因为它设立了一套定义,并具体说明了功能是怎样输出的,同时由此选出那些并没有被正确处理的输出申明。 因此,我们仅定义了空的XML调用并将其补充进入编译器主题。更多信息请查看expat_config.h。 现在便可为OS9.x充分的建立SyExpat, 并且仍旧保留其向后的兼容性。不幸的是我遇到一个关于Carbide.vs 和标准C库的糟糕问题,详细情况如下: http://discussion.forum.nokia.com/forum/showthread.php?t=75575 因此,即使项目在维护期,目前看起来需要解决的重要问题首先是对OS9相关主题进行修订。 由HelloWorld想到的 对于一个symbian GUI应用程序,必须实现四个类: (1)应用程序类(HelloWorldApp.cpp) 该类用于定义应用程序的属性,还用于生成新的空白文档,以及传递UID信息。 (2)文档类(HelloWorldDocument.cpp) 该类表示应用程序的数据模式,负责保存和恢复应用程序的数据,以及创建应用程序的用户UI接口。 (3)应用程序UI接口类(HelloWorldAppUi.cpp) 该类是完全不可见的,它创建一个应用程序视图,并且处理菜单等32位命令的相应手段。 (4)应用程序视图类(HelloWorldContainer.cpp) 这是一个具体的控件类,它的目的是在屏幕上显示应用程序数据,并允许用户交互。 通过这几个类的作用,可以得出一个程序的启动过程如下: HelloWorldApp.cpp—–>HelloWorldDocument.cpp——>HelloWorldAppUi.cpp——>HelloWorldContainer.cpp 周期类: Cperiodic CPeriodic* iPeriodicTimer; iPeriodicTimer = CPeriodic::NewL( CActive::EPriorityStandard );//这条语句一般在ConstructL()中 void CGraphicsAppView::StartTimer()//开始启动时钟 { if ( !iPeriodicTimer->IsActive() ) {iPeriodicTimer->Start( 1, 1, TCallBack( CGraphicsAppView::Period, this ) );//TcallBack是一个方法回调函数,从使用来看,他只能回调类中的静态方法。 } } TInt CGraphicsAppView::Period( TAny* aPtr )//周期启动函数,注意,这是个静态函数,但static只在头文件中才做了申明。 { ( static_cast( aPtr ) )->DoPeriodTask(); return ETrue; } void CGraphicsAppView::DoPeriodTask()//周期真正在做的事情 { // Update the screen CWindowGc& gc = SystemGc(); gc.Activate( *DrawableWindow() ); UpdateDisplay();///这个函数是关键的关键 gc.Deactivate(); } void CGraphicsAppView::StopTiem()//停止时钟 { if ( iPeriodicTimer->IsActive() ) { iPeriodicTimer->Cancel(); 字符串类: HBufC* textResource; //两种字符串附值方法 textResource = StringLoader::LoadLC( R_HEWP_TIME_FORMAT_ERROR ); textResource =iEikonEnv->AllocReadResourceL(R_EXAMPLE_TEXT_HELLO); TBuf<32> timeAsText; timeAsText = *textResource; 编译命令 1. bldmake bldfiles 2. abld build wins udeb 3. abld makefile vc6 4. epoc 5. abld reallyclean 有了以上的基础,我们就可以编译sis文件了. 一共分为2步: 1. 进入到/group目录下, 输入bldmake bldfiles, 和以前讲过的作用一样, 然后: abld build thumb urel, “abld build”是编译命令, “thumb urel”是编译目标, 一般手机的格式都是thumb, 用命令行为windows编译的话,就可以用 abld build wins udeb (urel). “udeb” 代表debug build, “urel”代表release build, 前者用于开发,后者用于发行。 2. 进入/sis, 输入makesis Helloworldbasic.pkg, 然后Helloworldbasic.sis就被创建了。 怎么在一个view类中响应按键消息 TKeyResponse CAknExEditorContainer9::OfferKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType) { return iListBox->OfferKeyEventL(aKeyEvent, aType); } Panic的含义 原意是报错,异常,紧急状态。 也就是程序的意外情况,symbian中用于弹出系统的异常对话框,并结束程序。 举例 Most of the functions here return void because if they fail the server will panic the client. 大部分函数都返回void值,这是因为如果他们出错了,那server端会通知client出了意外情况。 S60和Symbian的头文件 #include 时会直接到系统包含路径下去寻找aknappui.h (这不同于#include “aknappui.h”,还会到用户包含路径中去寻找)。 系统包含路径也就是在工程的.mmp文件中定义的: SYSTEMINCLUDE /epoc32/include, 其真实的路径也就是: %EPOCROOT%/epoc32/include, 在你的机器上如果系统变量EPOCROOT=/Symbian/9.1/S60_3rd/,那么它就是/Symbian/9.1/S60_3rd/ Epoc32/include,也就是说本来是应该能找到的,但是依据你的错误,此时你的EPOCROOT=/Symbian/Symbian8.1b/ bin/bak/,你可以试试把EPOCROOT设置成/Symbian/9.1/S60_3rd/。 另外工程文件夹最好放在%EPOCROOT%/Series60Ex下。 通过Uid来获取应用程序的路径 TFileName f = EikAppUi( ).Application( )->AppFullName( );//得到当前应用的全路径名 TParse parse; parse.Set( f,NULL,NULL ); parse.DriveAndPath( );//得到最终的纯路径 [ 本帖最后由 Moving 于 2007-4-11 08:15 编辑 ] 2007-4-11 08:17 Moving EPOCROOT环境变量的作用和设置  .mmp经Perl脚本的处理生成VC等IDE的工程文件,Perl脚本在处理时认为EPOCROOT环境变量所指的是SDK的安装目录,由此将include等目录的路径生成到工程文件里,只要以文本方式打开.dsp文件就能看到。 如果只有一个SDK,把EPOCROOT设置成该SDK的安装目录就好。 如果有多个SDK,使用下面的办法可以很方便地解决多SDK并存的问题: 1. 首先添加一个环境变量EPOCROOT: EPOCROOT=/ 2. 然后用SUBST把SDK的安装目录虚成一个盘: subst x: C:/Symbian/Series60_1_2_CW   上面以Series 60 SDK 1.2默认安装的路径为例,如果装了多个SDK就虚成不同的盘,所有的操作(包括Build等)都在虚出来的盘上进行。这样在切换SDK时不需要其它额外操作。   如果只执行了1而没有执行2就会出错,比如”C:/EPOC32/BUILD/PROJECT/TEST1″,显然它是把C盘根目录当前了SDK的安装目录了。如果正确地虚了盘。 各种编译模式之间的区别 基于ARM设备(ARMI, ARM4和THUMB),目前有三种生成版本: ARMI—-可执行文件将与其它两种生成版本一起工作,一般情况下,应当在生成ARMI二进制版本时,实现最大数量的真实设备兼容性. ARM4—-生成以增加代码大小为代价获得最佳性能. THUMB—-生成将以稍微降低执行速度为代价而减小代码大小 WINS和WINSCW编译方式是为了在模拟器上看到效果,在程序调试完成后需要使用ARMI,ARM4,THUMB三种模式中的一种编译成为能够在手机上运行的程序,一般使用ARMI方式。 Symbian程序的生成模式 WINS和WINSCW就是编译在windows上运行的模拟器的程序,它们之间的区别仅仅是使用不同的编译器生成的而已。WINS - VC、BC; WINSCW - Code Warrior 对于在基于ARM设备的真机上运行的程序,目前则有ARMI, ARM4和THUMB这三种生成模式: ARM4 - 最快速度优化,以增加代码大小为代价。 THUMB - 最小代码优化,以降低运行速度为代价。 ARMI - 同时执行以上两种的最大优化,一般在最终的程序都以这种方式生成,但应该在尽量多的支持设备上测试,以保证兼容性。 2007-4-17 08:13 Cotuvdi SIS文件中的Vendor信息在软件各版本中不应更改 说明: 当在S60第三版上升级一个程序时,在新的SIS包中的vendor信息必须和以往安装的一致。 详细描述: Vendor信息在pkg文件中是强制需要的: ; localized vendor name(s) (corresponding to language), ; displayed during installation %{”Vendor-EN”, …} ; non-localized (global) vendor name :{”Unique Vendor”} 要注意的是,升级包中non-localized vendor string需要和已安装在设备中的一致。 这是为了和签名一致,防止未认证的升级包代替合法vendor. 如果vendor string新旧不一致的话,在安装时就会报告“Update error”的错误信息 在S60第三版SIS文件中指定平台依赖属性 说明: pkg文件中需要指定平台依赖属性那行的格式在S60第三版中已经做了更改。 详细描述: 在S60第二版中,我们要在pkg中指定软件平台依赖性时,必须遵循下列格式。 ; Supports S60 2nd Edition (0×101F7960), 0, 0, 0, {”Series60ProductID”} (0×101F7960), 0, 0, 0, 在S60第三版中,平台依赖性是从硬件依赖考虑的,而平台UID必须是用中括号来定义: ; Supports S60 3rd Edition [0×101F7961], 0, 0, 0, {”Series60ProductID”} 而老的定义形式在S60第三版中的pkg文件中仍然有效,makesis执行时不会提示错误。不过如果要安装这样形式的SIS文件到第三版设备上将会引发“Application not compatible” 错误。因为安装程序无法识别平台UID。 一些支持自定义产生pkg文件的工具及IDE可能仍然在使用老格式,这个需要注意。 解决方案: 检查那些为生成在S60第三版上SIS包的pkg文件中,关于平台依赖性设置的格式是否正确。 SIS包和本地化资源文件 概况: 当使用本地化资源文件为程序添加了多语言支持后,下面一个步骤就是将他们加入.pkg文件,并生成SIS包。 有两个方法来完成这个任务: 将资源打包在.pkg文件时,可选择语言相关方式也可以选择语言无关方式。 语言无关文件: 下列文件都别拷贝到目标机器上,而不管其语言设置或用户选择。 “MyApp.r01″ - “!:/system/apps/MyApp/MyApp.r01″ ; 01=English “MyApp.r02″ - “!:/system/apps/MyApp/MyApp.r02″ ; 02=French “MyApp.r03″ - “!:/system/apps/MyApp/MyApp.r03″ ; 03=German ; etc (see TLanguage in e32std.h for all lang. enumerations) 由程序框架根据当前语言设置决定,在程序运行时载入哪种语言。将所有资源文件都拷贝在设备将增长内存消耗,但另一个方面,程序也能支持设备当前语言(可能需要重启后才能更改语言设置) 语言相关文件: 设计一个文件列表,只能根据用户在安装时选的语言来安装一个。文件的顺序和个数必须和.pkg文件中语言行指定的一致: { “MyApp.r01″, “MyApp.r02″, “MyApp.r03″ } - “!:/system/apps/MyApp/MyApp.rsc” 因为只有一个本地化资源文件能被拷贝,程序将不支持设备上的语言设置,改变程序的语言将需要重新安装一次。 总结: 我们在选择何种方法时应该着重考虑所有本地化资源文件加在一起的大小,以及程序是否要去支持设备上的语言设置更改。 在/private目录下存储应用程序图片文件 说明: 如果图片文件存放在受保护目录下,则在S60第三版上使用AknIconUtils加载图标或图片可能会引发错误。 详细描述: 如果图片文件aFileName存放在一个受保护目录下,如/private//下,则在S60第三版中使用AknIconUitls的下列方法(akniconutils.h)时将会引发错误: void CreateIconL( CFbsBitmap *&aBitmap, CFbsBitmap *&aMask, const TDesC &aFileName, TInt aBitmapId, TInt aMaskId ) 这是因为Avkon icon server无法访问存放在保护目录下的文件。 案例重现: 在这种情况下AknIconUtils::CreateIconL()不会引发异常,不管怎么说,aBitmap和aMask参数将不会指向有效位图。如果尝试使用返回的位图将会引发错误异常。 例如,尝试使用AknIconUtils::SetSize()设置位图大小时会引发error -46(KErrPermissionDenied) 解决方案: 不要将文件名传递到CAknIconUtils,程序应当完成max-in类MAknIconFileProvider,以便提供一个打开的文件句柄给Avkon icon server. CAknIconUtils有一个可供重载的CreateIconL()方法以便接收一个MAknIconFileProvider示例。 这里提供一个完成MAknIconFileProvider 类的示例,请S60 Platform: Scalable Screen-Drawing Example, 可在http://www.forum.nokia.com/下载 注意:包含应用程序图标的.mbm和.mif文件(会在LOCALISABLE_APP_INFO资源定义中被引用)应该永远安装在/resource/apps/.目录下。 CVideoPlayerUtility::SetRotationL()崩溃或错误现象 说明: 调用CVideoPlayerUtility中的SetRotationL()方法会产生错误结果,甚至导致设备重启。 详细描述: 使用 CVideoPlayerUtility::SetRotationL(TVideoRotation aRotation)时,将参数aRotation设置为EVideoRotationClockwise180 或EVideoRotationClockwise270,这样可能导致设备重启或旋转后的画面扭曲难看。 如果参数为EVideoRotationClockwise90 那将没有这方面的问题。 解决方案: 在CVideoPlayerUtility中使用90度顺时针方面。在7-11-2005后的版本中已经修正了这个问题。 自定义CMdaAudioInputStream的buffer大小 详细描述: 对S60 MMF客户端音频程序来说,处理S60设备中输入流时,是否可以自定义buffer的大小。 解决方案: 在S60 MMF架构中缺省的声音I/O数据buffer大小是根据声音硬件和音频编码性能来分配的。使用CMdaAudioInputStream的客户端程序将考虑到下列局限: 但使用PCM16(缺省)格式时: 声音设备返回的input buffer总是320个字节(S60第二版,FP2和FP3)或4096字节(S60第三版)。这也是调用CMdaAudioInputStream::ReadL()所能返回最大数据长度,因此不建议超过此限度大小。 如果传递到客户端ReadL()中的buffer小于该大小,那服务端buffer就会被组成适合大小的块以便传入。如果这样操作后还有剩余,就不会满足这里最大长度大小。例如,当在S60第三版中使用一个 3840字节的buffer大小时,第一个返回的buffer为3840字节,而下一个就是(4096-3840)256字节,然后再这样重复继续。 当使用非PCM格式处理流时: 对一个压缩音频格式,每个返回的input buffer都典型的包括一个音频数据的单独帧。例如,当使用AMR-NB格式时(在MaiscOpenComplete()方法): iInputStream->SetDataTypeL(KMMFFourCCCodeAMR); 调用后,每次返回buffer将包括14个字节(一个单独的AMR-NB frame in ,5.15 kbit/s)可演绎20ms of audio data; 自签名程序的UID S60第三版对所有安装程序引进了强制签名机制。如果一个应用程序没有capabilites属性或仅使用了开放给所有人的capabilites属性,它可以生成一个新证书,并用它来签名。所有的免费程序都 可以这样处理。 更多关于自签名证书的信息可通过查看SDK帮助获取:Introduction to S60 3rd Edition >> How to Sign .sis Files. 使用自签名证书意味着该程序被看做不可信任的,不可信任的程序应该使用unprotected range of UIDs下的唯一标识。否则安装在第三版设备上将会导致失败。 Protected UID range: 0×00000000 … 0×7FFFFFFF Unprotected UID range: 0×80000000 … 0xFFFFFFFF 特别要指出的是,有两组重要的未保护UID范围: UIDs for self-signed app. releases: 0xA0000000 … 0xAFFFFFFF UIDs for test/development use: 0xE0000000 … 0xEFFFFFFF UID的分配是由symbian公司来管理的,要获得更多相关方面的信息请参考http://www.symbiansigned.com RHostResolver和选择接入点对话框重复显示的问题 说明: 使用一个服务器解析服务时(RHostResolver)可能会引发选择接入点对话框的重复显示 详细描述: 在S60第三版上,当前已有连接的状态下使用服务器解析服务(RHostResolver)时将导致选择接入点对话框不停重复出现。 案例重现: 连接socket server(RSocketServ),打开一个RConnection示例: iSocketServer.Connect(); iConnection.Open(iSocketServer); 这样就开始了一个internet连接: iConnection.Start(); 这时会出现一个选择接入点对话框,要选择一个适当的访问接入点。 在连接已经建立后,使用RHostResolver打开一个DNS resolver session,并开始尝试解析一个主机名: iResolver.Open(iSocketServer, KAfInet, KProtocolInetUdp); iResolver.GetByName(someHost, iResult); 这时选择接入点对话框会会再次出现。 解决方案: 传递当前RConnection示例到host resolver中: iResolver.Open(iSocketServer, KAfInet, KProtocolInetUdp, iConnection); 2007-4-17 08:18 Cotuvdi 文件存取类的改进 1、用函数取文件路径 原来我使用的静态路径,这样有很大的局限性。现在改用 TFileName strFileName = NEikonEnvironment::ApplicationDriveAndPath(); strFileName.Append(KFirewallRuleFileName); 其中黑体函数是取得应用程序所在的路径。 该函数的使用需要包含头文件EikonEnvironment.h,该文件不在系统包含路径中,需要将其和对应的CPP文件从C:/Symbian/8.1a/S60_2nd_FP3/Series60Ex/helperfunctions路径中拷贝到自己的文件目录中。 (实际使用中出现了KERN-EXEC 3的错误,正在调试) 2、用BaflUtils::FileExists(CEikonEnv::Static()->FsSession(), strFileName)判断文件的存在 原来我直接用writer.Replace(iFs, KFirewallRuleFileName, EFileWrite),该函数的特点是不论有没有该文件,都创建新的文件,那么如果文件存在则文件内容被清空,这个有点不太好,所以改之。 怎样为SettingsList赋值 为设置列表的列表项设置值,有点拗口,大体意思是,如果用户不满意自己的设置,想把它设置回默认值的操作。 问题核心:怎样为SettingsList赋值的问题。 解决方法:iListBox->LoadSettingsL() 首先看一下创建设置列表函数CreateSettingListL(TInt aIdentifier)的重载,代码如下: 1 CAknSettingItem* CFirewallSettingList::CreateSettingItemL( TInt aIdentifier) 2 { 3 CAknSettingItem* settingItem = NULL ; 4 5 switch (aIdentifier) 6 { 7 case ESettingItemSizeLogFile: 8 settingItem = new (ELeave) CAknIntegerEdwinSettingItem(aIdentifier, iData->iSizeOfLogfile) ; 9 break ; 10 case ESettingItemIsRecordLog: 11 settingItem = new (ELeave) CAknBinaryPopupSettingItem(aIdentifier, iData->iIsRecordLog) ; 12 break ; 13 case ESettingItemDefaultAction: 14 settingItem = new (ELeave) CAknEnumeratedTextPopupSettingItem(aIdentifier, iData->iDefaultAction) ; 15 break ; 16 case ESettingItemIsAutostart: 17 settingItem = new (ELeave) CAknBinaryPopupSettingItem(aIdentifier, iData->iIsAutoStart) ; 18 break ; 19 default: 20 break; 21 } 22 return settingItem ; 23 } 24 第8、11、14、17行是用来创建设置列表的列表项,可以看出我们用了三种设置列表。 例如:CAknIntegerEdwinSettingItem(aIdentifier, iData->iSizeOfLogfile) 这个函数,其中第二个参数为我们要给该项赋值的值。 通过从新设置iData的值,然后调用LoadSettingsListL()函数,就会将iData的值重新送给SettingsList,然后将新值显示出来。 在通话时捕捉到结束键(红色键) 我们可以使用下列代码在通话时捕捉到结束键。 Please note that SwEvent capability is needed to make successful calls to the mentioned Window Server functions. Code: #include // link against ws32.lib #include … RWindowGroup& groupWin = CCoeEnv::Static()->RootWin(); TInt endKey1 = groupWin.CaptureKeyUpAndDowns( EStdKeyNo, 0, 0 ); TInt endKey2 = groupWin.CaptureKey( EKeyNo, 0, 0 ); // -> End key can now be processed before the phone application of the device… … // Cancel the capture groupWin.CancelCaptureKeyUpAndDowns( endKey1 ); groupWin.CancelCaptureKey( endKey2 ); 上述代码已经在N73(SW: 2.0620.0.05)上测试通过 在ETel第三方API(CTelephony)中使用User::WaitForRequest()应注意的问题 ETel第三方API(即CTelephony)是做为异步模式来设计的,从一个活动对象调用它的方法,然后就等待这个方法的完成。做为活动对象所定义的概念来说,一次只能有个一个active request存在。 Telephony的异步工作模式使得它无论何时检测到一个方法被调用时(这时TRequestStatus参数被传入该方法),已经是KRequestPending状态的情况下,都会引发一个异常(Telephony 0)。 一般在Symbian程序员中流传的使异步变同步的方法就是调用User::WaitForRequest来锁定该线程直到方法完成(这个方法是不被提倡的) 这样做主要有两个问题: 1、异步工作模式可能会花费较长的执行时间才能完成,这样线程就一直处于阻塞模式下,这样可能会引发VIEWSERV 11异常(参考Symbian FAQ-0920) 2、该异步方法的完成可能依靠同一个线城中其他活动对象的工作,而如果阻塞线程的话,那这个异步工作将永远无法完结。 我们在一个具体的CTelephony事例中来考虑问题: CTelephony::TBatteryInfoV1 batterystrength; CTelephony::TBatteryInfoV1Pckg battery(batterystrength); CTelephony* tel = CTelephony::NewLC(); TRequestStatus status = KRequestPending; // (1) tel->GetBatteryInfo(status, battery); User::WaitForRequest(myStat); // (2) … CleanupStack::PopAndDestroy(); 这个将意味着: 1、TRequestStatus变量被初始化为KRequestPending(第(1)行),这是一个常见的错误,会引发CTelephony报Telephony 0错误(如上所述),注意一般来说是没有必要对TRequestStatus进行初始化的。 2、如果第(1)行被删除,那代码也永远无法回到第(2)行,因为在线程被阻塞的情况下CTelephony的异步方法是无法被完成的。 结论就是CTelephony应该一直使用异步工作模式,另外使用User::WaitForRequest时一定要谨慎。 程序的自启动的动态配置 目前,在S60第三版中,如果一个程序想要自启动,你可以通过启动列表管理API来完成它。具体信息可以在S60 3rd Edition SDK中找到。 为了进行Symbian Signed criteria的传递,你需要在你的程序中提供对自启动的取消功能。暂时没有公开的API可以帮助你解决这个问题,下面有两个解决方案: 1)设计一个启动程序,它可用来启动一个实际的应用程序。无论手机何时启动该启动程序需被自动开启。然后它检查配置文件(.ini),如果配置文件中该boot选项被标记为开启,那就去启动响应的实际程序,如果为关闭,那就终止自己,当然也不需要去启动实际程序了。 注意在启动程序成功启动实际程序后它不能立刻将自己结束掉,否则实际程序将因此而无法成功运行。 在实际运用中,第三方程序可以找到一个公共位置去存放配置文件,或者为两个程序(启动程序和实际程序)准备一个公共的secure ID。RVCT编译程序可以帮助你解决这个问题。 2)你也可以安排手机开启后每次都去启动实际程序,在开始阶段就去检查配置文件,如果其中的flag被标记为ON,则继续运行它自己,如果flag被标记为OFF,则需要调用CAknAppUi::Exit()函数来结束自己。 同第一个方案相比,这个方法不需要去解决两个程序同时拥有一个secure ID的问题。这样如果程序十分大,并且用户不是选择每次都自启动的话,我们可以花费更多CPU时间在加载程序上。 从Symbian Singed的角度来看,第二个方法要优于第一个。 如果控制一个进程中的堆分配 我的程序试图从堆上分配一定内存,却产生了失败。我该怎么做才能分配到更多内存呢? 我们可以在.mmp中通过EPOCHEAPSIZE命令直接来保留或压缩一定内存空间,这样进程在启动时就能使用。 Syntax: epocheapsize minimum maximum 最小值(以字节为单位,一般为4K左右)以保证进程的正常运行。 最大值说明进行所能使用内存的数量限度。 要获取更多信息可参考Symbian FAQ知识库: http://www3.symbian.com/faq.nsf/0/8D…5?OpenDocument 在S60上编写一个有发送短信功能的程序 根据下面Forum Nokia上的示例来写一个具有短信发送能力的程序是很简单的。根据不同的目标平台,有两种方法可选择,在早期的S60和S80设备上一般使用一个客户端的MTM API,而S60第三版中 则介绍了一个更为高级易用的API。 2nd Edition platforms: 在S60第二版和S80平台上如果要发送SMS程序可以直接使用SMS Client MTM来进行信息发送。早期的平台上对开发者来说主要的问题是其中一部分需要的API不是公开的,不过在S60 2nd和S80 2nd中已经解决了。 Forum Nokia已有SMS示例,它将教你一步步来生成并发送一个短信。可以通过下列连接查看: S60 Platform: SMS Example http://www.forum.nokia.com/info/sw.n…_0_en.zip.html 3rd Edition: 在S60第三版上通过新的SendAs API我们可以更加容易的发送短信。这是封装在messaging client MTMs上的API,通过它们你的程序可以去访问所有支持的messaging protocol,而不光是sms messaging。 S60第三版也支持对MTM的直接使用。 可以通过下列连接去找到在MTM方法和新的SendAs方法的示例: S60 Platform: SMS Example http://www.forum.nokia.com/info/sw.n…_0_en.zip.html Related topics: Forum Nokia Messaging examples (C++) http://www.forum.nokia.com/main/1%2c…0_11%2c00.html Messaging discussion on Forum Nokia C++ developer’s board http://discussion.forum.nokia.com/fo…splay.php?f=26 Messaging in Symbian Developer Library - online API reference http://www.symbian.com/developer/tec…reference/cpp/ 2007-4-17 08:21 Cotuvdi 存放应用程序图标的文件夹名的本地化问题 应用程序可以选择安装后存放的菜单目录文件夹,在S60第一版和第二版中,文件夹的名称可在AIF_DATA资源中进行定义,在application information file(.aif)代码为: RESOURCE AIF_DATA { … groupname = “Games”; } 在S60第三版中,该定义是放在app中完成的,registration file(_reg.rsc)代码为: RESOURCE APP_REGISTRATION_INFO { … group_name = “Games”; } 其中有一些名字可通过组名(group_name)参数被本地化识别。如果这样使用的话,那图标将放在会放置在相应合适的目录下,该目录回根据所选语言有个本地化名称。本地化名的文件夹们在设备和 S60平台版本系列中并不是一成不变的。但至少下列名称是被所有基于S60第二版FP1或更新版的机器所支持的: Communications Configurations Games SIM Tools 但是你需要知道的是,同样的组名也会被不同的机器映射为不同的名称,例如,在一些S60第三版设备上会将Tool和Configurations都映射为Tool文件夹,其他设备会将Tools映射到缺省安装的目录 下(“Extras”,“My Own”,或“Install”,具体根据设备来判断)如果该组名无法被识别或不存在,那就会产生一个新的。 并不是所有的文件夹都有个可适合本地化的组名。如果在S60第三版上使用“Office”组名,就会在非英文机上产生一个新的“Office”文件夹。 正是因为这些原因,我们一般建议为他们的图标使用缺省的组名。如果游戏类程序就用“Games”做为组名,这样被本地化并放在S60手机正确的菜单位置。 如果应用程序需要被放置在一个不能被识别的组名文件夹里,如“Office”,我们还可以去为它进行本地化注册工作。下面是一个示例,来注册“Office”文件夹以支持英语和法语。在这样的情况 下,资源编译器将生成两个版本的注册文件,_reg.r01和_reg.r02 RESOURCE APP_REGISTRATION_INFO { … #if defined(LANGUAGE_01) // English group_name=”Office”; #else if defined(LANGUAGE_02) // French group_name=”Bureau”; #else // Other languages group_name=”Office”; #endif } 如何指定最大和最小堆内存 在一台手机(或SDK的模拟器)上会有一定的物理内存大小,而你的应用程序将获取一部分做为堆内存使用。 当你程序启动后产生进程,会有一个预先分配的堆给其使用。S60第三版设备上缺省大小是4KB,早期的S60平台上是1KB。 根据需要,应用程序可以自由分配更多的堆内存,程序能使用的堆大小可在1M范围内动态增加,这是操作系统所规定最高极限了,呵呵。 如果试图分配的内存超过所能最大限制,将引发KErrNoMemory异常。 大部分Symbian C++程序在这样的堆内存安排下可以正常工作,但有时间我们需要更大的堆内存来工作。我们可以通过MMP文件中使用EPOCHEAPSIZE命令来指定最大和最小堆内存。 例如 TARGET MemoryTest.exe TARGETTYPE exe UID 0x00000000 KMemoryTestUID3 SECUREID KMemoryTestUID3 VENDORID 0x00000000 CAPABILITY NONE EPOCHEAPSIZE 0x5000 0x400000 EPOCSTACKSIZE 0x5000 .... 在上述代码中,应用程序描述了它所需要的最大和最小堆内存,分别是0x5000字节(20KB)和0x400000字节(4MB),现在该程序可以安全来分配一块3MB的堆空间。 Note: As documented, prior to S60 3rd Edition the EPOCHEAPSIZE statement has no effect on WINS32 platforms. 在上述代码中,应用程序描述了它所需要的最大和最小堆内存,分别是0×5000字节(20KB)和0×400000字节(4MB),现在该程序可以安全来分配一块3MB的堆空间。Note: As documented, prior to S60 3rd Edition the EPOCHEAPSIZE statement has no effect on WINS32 platforms. 在对一张使用逐行编码的JPG图片进行解码时,会出现“内存不够”的错误 详细描述: 在对使用逐行编码的JPG图片进行解码时将比对使用顺序编码的JPG图片解码占用更多内存。 列如当使用CImageDecoder类对一张较大的逐行编码JPEG进行解码时,CImageDecoder::Convert()将会获得KErrNoMemory(-4)错误。 应用程序增加堆的大小将有助于这类问题的解决,我们可以在.mmp文件中使用EPOCHEAPSIZE命令进行调整,如: EPOCHEAPSIZE 0×1000 0×200000 这样将初始化的堆大小从4KB(缺省)调整到2MB 解决方案: 我们可以通过在.mmp工程定义文件中使用epocstacksize命令行来修改缺省的8KB大小。 epocstacksize stacksize 堆栈的大小,可以通过十六进制或十进制来指定。但这对winscw/wins平台是无效的。 列如下面这行将堆栈大小增加到20KB epocstacksize 0×5000 同样,我们也可以在产生新线程时定义该线程的堆栈大小。 S60第三版中最小缺省堆栈大小 说明:在S60第三版中缺省的堆栈大小只有8KB,这对大多数复杂程序来说是不够的 详细描述: 在symbian OS v9中缺省的堆栈大小从20kb缩减到8kb,以优化内存的消耗。这主要是因为平台安全性导致了在系统中同时运行的进程增多。 实际上,8kb的堆栈大小对任何一个稍大的S60程序来说都是不够的。如果在当前设备上缺省的堆栈能运行你的程序,那因为堆栈的溢出(平台库的消耗而引发堆栈的增长),它也很容易引发崩溃。在S60第三版SDK中建议所有程序都增长到20KB堆栈,这需要为此重新编译。 解决方案: 我们可以通过在.mmp工程定义文件中使用epocstacksize命令行来修改缺省的8KB大小。 epocstacksize stacksize 堆栈的大小,可以通过十六进制或十进制来指定。但这对winscw/wins平台是无效的。 列如下面这行将堆栈大小增加到20KB epocstacksize 0×5000 同样,我们也可以在产生新线程时定义该线程的堆栈大小。 蓝牙L2CAP错误-6305 详细描述: 该错误是因为物理上连接和断开事件冲突所引起的。有时间物理连接中,HCI处传输状态时,程序会出现发送间隔。S60第二版,FP3在连接实际被关闭时会允许新的激活,这就是-6305错误所在原因。对这个问题一个解决方案是保持通道通讯而避免物理连接的空闲时间中断连接。 解决方案: 在S60第三版中该问题被修正了。 S60上不再支持CMdaAudioConvertUtility 说明: S60上不再支持CMdaAudioConvertUtility 详细描述: CMdaAudioConvertUility做为Symbian’ Media Client Audio API的一部分,从S60第二版SDK, FP1后就不再被支持。 当在新平台使用时,所有CMdaAudioConvertUtility::OpenL()所返回的变量将为KErrNotSupported错误代码。 解决方案: Audio convert utility在S60上不再被支持,流媒体程序不再需要将声音先转成PCM中间格式,取而代之的是我们可以直接将压缩的声音数据向流中传递或从中接收,只需在初始化流对象时提供一 个被支持的数据类型(fourCC代码)。 如,使用CMdaAudioInputStream从AMR-NB格式中直接读取声音数据: void MyStreamClass::MaiscOpenComplete(TInt aError) { iInputStream->SetDataTypeL(KMMFFourCCCodeAMR); … } 使用Ctrl+V(粘贴)上时所引发的程序错误 说明: 在可编辑的文本输入框中拷贝粘贴文本时会引发异常 详细描述: 这个情况只在E61手机上出现,并且版本号为1.0610.04.04 一些第三方的程序复制文本到剪贴板后在可编辑文本框中进行粘贴操作时(Ctrl+V),会引发WSERV 66异常而崩溃掉。这是因为该应用程序没有SwEvent兼容性。 解决方案: 在E61机型(版本1.0610.04.04)上运行的程序,当处理Ctrl+V(粘贴)时需要SwEvent兼容来避免WSERV 66异常,不过这个问题在后继版本中被修复了
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值