zoukankan      html  css  js  c++  java
  • symbian mtm操作

    symbian mtm操作

    MTM ==> Message Type Modules

      一、消息存储基本知识:

      SymbianOS提供的消息传送架构也是基于Client/Server机制,Server端负责管理手机上的各种消息,在进行消息相关操作之前我们需要了解SymbianOS是如何组织和存储消息的。

      手机中的各种消息都是以数据项(Entry)形式供程序操作,数据项有4种类型,SymbianOS为每种数据项提供了相应的常量标识UID,这些UID保存在msvuids.h文件中:

      1、文件夹类型,对应常量UID为KUidMsvFolderEntry,和PC上的文件夹系统一样,每个文件夹可以包含其它数据项也可能是其它数据项的子数据项。

      2、消息类型,对应常量UID为KUidMsvMessageEntry,它表示数据项是一条消息。

      3、附件类型,对应常量UID为KUidMsvAttachmentEntry,它表示某条消息的附件。

      4、服务类型,对应常量UID为KUidMsvServiceEntry,服务数据项包含某个消息服务的配置信息,在一般情况还拥有通过该服务收发的消息数据项。

      除了上面提到的四种类型UID还有常用到的UID是KUidMsvRootEntry(msvids.h),它指的是根数据项,根数据项包含了4个标准文件夹数据项,分别是收件箱(KMsvGloballnBoxIndexEntryld),发件箱(KMsvgGlobalOutBoxIndexEntryld)、草稿箱(KMsvDraftEntryld)和已发送项(KMsvSentEntryld),另外根数据项下面还包含有各种消息服务项.

      SymbianOS中的消息服务器负责保存各种类型的数据项,这里有两个基本概念需要了解:消息存储和消息索引。消息存储保存了数据项的数据,保存的数据格式取决于消息服务,服务数据项使用消息存储保存服务配置信息,文件夹数据项不使用消息存储(即存储为空),Symbian提供了CMsvStore类来访问数据项的消息存储;为了节省内存和快速检索消息,消息服务器把数据项的一些概要信息(标题,日期,类型,ID等)写到消息索引中,当消息服务器启动时索引装载到RAM中直到消息服务器关闭,Symbian提供了TMsvEntry类表示数据项索引。

      操作消息常用的类和数据类型:

      CMsvSession:该类代表客户端(客户端MTM、用户接口MTM或者客户端消息应用程序)与消息服务器端的通讯通道即C/S架构中客户端与消息服务器的回话。每一个客户端线程对应一个该类的实例,使用它获得下面将要提到的CMsvEntry上下文对象。一个消息客户端应用必须在正常使用任何MTM或CMsvEntry对象前,使用OpenSyncL()或者OpenASyncL()来新建立一个Session对象。

      接上页

      CClientMtmRegistry:Registry掌握了客户端所有目前可用的MTM有关的细节,消息客户端可以使用该类获得CBaseMtm继承的对象。

      CBaseMtm:这个类主要用来操作消息条目,比如可以新建、修改、发送消息条目。

      TMsvId:它只是一个TInt32的Typedef,消息服务器为每个数据项分配一个唯一的数据作为标识,除了上面提到的几个固定标识,其它标识都是动态分配的。想要对某个消息进行操作必须先得到他的ID,Symbian中消息相关的大部分函数都会用到TMsvId。

      CMsvEntrySelection,是一个可以存储TMsvId的数组,在使用CMsvEntry(CMsvServerEntry)的许多操作中都会作为参数或者返回对象。

      TMsvEntry:上面提到过它表示数据项的索引,只包含消息的一些概要信息,主要会用到Id()成员函数得到数据项的标识ID和公有数据成员iDetails、iDesciption和iDate,前面两个成员可以用来获取和设置索引的概要信息,iDate成员可以获取和设置数据项的日期及时间。

      CMsvEntry和CMsvServerEntry:可以理解为数据项的上下文(context),这两个类非常类似,只不过CMsvEntry用户客户端,CMsvServerEntry用户实现消息的服务端。它包含两个部分的功能:一是可以允许访问与这个Entry关联的,不同类型的数据(比如可以根据指定ID定位数据项、获取消息存储和消息索引);二是运行访问它的子entry和父entry(当然对新的条目又可以进行一的功能)。

      CMsvStore:上面提到过表示数据项的存储,可以通过CMsvEntry(CMsvServerEntry)的EditStoreL(),ReadStoreL()函数取得可编辑存储或只读存储

      二、数据项常用操作

      因为消息处理建立在C/S架构上,所以在消息操作之前,先要进行一些预处理,大致步骤如下:

      1、通过消息会话类CMsvSession连接到消息服务器,建立会话。因为通常连接都采用异步方式,所以为了或许连接的事件通知,实例化CMsvSession对象的类需要继承自MMsvSessionObserver。

      2、构造客户端MTM注册对象(通过CClientMtmRegistry::NewL(CMsvSession &aMsvSession)来实现)。

      3、构造具体的客户端MTM对象(通过CClientMtmRegistry::NewMtmL(TUid aMtmTypeUid)这里的MtmTypeUID和TMsvEntry内的消息类型ID是一致的)。

      4、接下来的操作就是根据具体需求创建、编辑、验证、发送消息条目(如果只是创建和编辑消息条目,则不用如上这么复杂,可省略MTM对象构造)。

      接上页

      下面的消息操作使用了一个CMsvEntry或CMsvServerEntry的指针对象,这两个类提供的基本功能一样,但有一部分函数名会不一样,可以查一下SDK。

      1.获得当前数据项索引和ID

      TMsvEntry oldEntry = iServerEntry->Entry(); //这里iServerEntry应该是CMsvServerEntry

      TMsvId oldContext = oldEntry.Id(); //如果使用CMsvEntry可以直接使用Id()

      2.定位到指定数据项

      在更换当前数据项之前通常先保存当前数据项索引ID,更换数据项并完成相关操作后再更换回原来的数据项,这可以避免影响其它函数,是一个很好习惯。

      TMsvId oldContext = iServerEntry->Entry().Id();

      //使用SetEntry()更换当前数据项到root

      iServerEntry->SetEntry(KMsvRootIndexEntryId);

      //具体操作后更换回原来数据项

      iServerEntry->SetEntry(oldContext);

      3.查找数据项

      下面的三个CMsvEntry成员函数都能完成在当前数据项下进行查找的功能:

      CMsvEntrySelection* ChildrenWithMtmL(TUid aMtm) const;

      根据消息服务(MTM)进行查找,查找消息索引对象(TMsvEntry)的成员iMtm等于aMtm的数据项ID。

      CMsvEntrySelection* ChildrenWithServiceL(TMsvId aId) const;

      根据消息服务ID进行查找,查找消息索引对象(TMsvEntry)的成员iServiceId等于aId的数据项ID。

      CMsvEntrySelection* ChildrenWithTypeL(TUid aEntryType) const;

      根据数据项类型进行查找,查找消息索引对角的(TMsvEntry)的成员iType等于aEntryType的数据项ID。

      CMsvServerEntry与之相对应的三个函数为GetChildrenWithMtm(), GetChildrenWithService(), GetChildrenWithType(),注意的一点是CMsvEntry的三个函数都返回一个CMsvEntrySelection对象的指针,使用完之后我们要负责释放,使用CMsvServerEntry的三个函数需要事先构造一个CMsvEntrySelection对象,用完之后也需要释放。

      找出POP3邮箱个数的代码:

      iMsvEntry->SetEntryL( KUidMsgTypePop3 );

      CMsvEntrySelection* sel = NULL;

      sel = entry->ChildrenWithMtmL( KPkiSmtpTechnologyTypeUid );

      TInt cnt = sel->Count(); //获得集合中数据项的个数

      接上页

      delete sel;

      4.更改消息索引

      TMsvEntry entry = iMsvEntry->Entry();

      entry.iDetails.Set( _L( “New details” ) );

      iMsvEntry->ChangeL( entry ); //把更改后的数据项索引写回消息索引中去(相当于commit提交)

      这里最后的ChangeL很重要,如果不进行该步调用,那么未将修改的消息索引写回到消息存储中。

      5.数据项的读写

      在进行数据项的读写之前需要使用EditStoreL(),ReadStoreL()函数得到相应的存储CMsvStore通过它提供的接口进行操作。

      void CMessageView::ViewMessageL(TMsvId aId)

      {

      // Construct the CMsvEntry

      CMsvEntry* entry = iSession->GetEntryL(aId);

      CleanupStack::PushL(entry);

      // Get the messaging store

      CMsvStore* store = entry->ReadStoreL();

      CleanupStack::PushL(store);

      // Construct the CRichText and restore the body text

      CParaFormatLayer* paraLayer = CParaFormatLayer::NewL();

      CleanupStack::PushL(paraLayer);

      CCharFormatLayer* charLayer = CCharFormatLayer::NewL();

      CleanupStack::PushL(charLayer);

      CRichText* body = CRichText::NewL(paraLayer, charLayer);

      CleanupStack::PushL(body);

      store->RestoreBodyTextL(*body);

      // Extract body text from CRichText

      TInt len = body->DocumentLength(); //get length

      HBufC *buf = HBufC::NewL( len );

      TPtr ptrBuf = buf->Des();

      body->Extract( ptrBuf, 0, len ); //get data

      //因为不同的消息的存储格式不同,还可能需要对ptrBuf进行相应的解码才能正常

      //显示

      delete buf;

      buf = NULL;

      CleanupStack::PopAndDestroy(5, entry);

      }

      三、关于SMS的一些特殊操作

      1.读取消息条目

      //读取发件箱消息条目索引

      TMsvSelectionOrdering sort;

      //全部内容排序,包括隐藏

      sort.SetShowInvisibleEntries(ETrue);

      //设置入口为outbox,也就是发信箱

      接上页

      CMsvEntry* entry = CMsvEntry::NewL(*iSession,KMsvGlobalOutBoxIndexEntryId,sort);

      CleanupStack::PushL(entry);

      //选择全部内容

      CMsvEntrySelection* entries = entry->ChildrenL();

      CleanupStack::PushL(entries);

      //读取消息索引信息,At(0)代表首信息,取其他的可以给出相应的index

      TMsvId aEntryId = entries->At(0);

      //得到消息索引的时间

      TTime time;

      time = entry->ChildDataL(aEntryId).iDate;

      iSmsMtm->SwitchCurrentEntryL(aEntryId);//iSmsMtm是CSmsClientMtm类型的指针变量,它已经初始化

      iSmsMtm->LoadMessageL(); // load the message

      CRichText& body = iSmsMtm->Body(); //sms的内容存到CRichText控件对象中

      TPtrC msg(body.Read(0));

      //弹出对话框,提示短信内容

      CAknInformationNote* informationNote = new (ELeave) CAknInformationNote;

      informationNote->ExecuteLD(msg);

      CleanupStack::PopAndDestroy();

      2.删除消息条目

      //删除草稿箱中的消息条目

      TMsvSelectionOrdering sort;

      sort.SetShowInvisibleEntries(ETrue);

      CMsvEntry* entry = CMsvEntry::NewL(*iSession,KMsvDraftEntryId,sort);

      CleanupStack::PushL(entry);

      CMsvEntrySelection* entries = entry->ChildrenL();

      CleanupStack::PushL(entries);

      TInt i = entries->Count();

      for(TInt ncount=0;ncount< p>

      {

      entry->DeleteL(entries->At(ncount));

      }

      // information to the user

      iEikonEnv->InfoMsg(_L("DeleteAll Done!"));

      CleanupStack::PopAndDestroy(2);

      3.创建消息条目

      创建消息条目部分在收件箱和草稿箱两个地方是不一样的,具体代码如下:

      //在草稿箱中创建短信

      const TInt LEN = 12;

      //转入收件箱

      iSmsMtm->SwitchCurrentEntryL(KMsvDraftEntryId);

      接上页

      //构建消息索引

      TMsvEntry newIndexEntry;

      newIndexEntry.iDate.HomeTime();

      newIndexEntry.iMtm = KUidMsgTypeSMS;

      newIndexEntry.iType = KUidMsvMessageEntry;

      //in 3rd edition crashes here if capabilities are wrong

      newIndexEntry.iServiceId = iSmsMtm->ServiceId();

      newIndexEntry.iDetails.Set(aName);//aName为收件人名称

      newIndexEntry.iDescription.Set(aContent.Left(LEN));

      newIndexEntry.SetUnread(ETrue);

      iSmsMtm->Entry().CreateL(newIndexEntry);

      TMsvId smsId = newIndexEntry.Id();

      iSmsMtm->SwitchCurrentEntryL(smsId);

      //填充消息存储区

      iSmsMtm->AddAddresseeL(aAddr);//aAddr为收件人号码,信息位于消息头中

      CRichText& body = iSmsMtm->Body();//消息正文

      body.Reset();

      body.InsertL(0, *iSmsContext);

      //提交保存

      iSmsMtm->SaveMessageL();

      注:当然如果要发送的短信,还需要进行具体的设定,这部分将在发送消息里面详述,这里只是做为普通的创建消息,与收件箱中消息进行比较,具体见下面代码示例。

      //在收件箱中创建短信

      const TInt LEN = 12;

      //转入收件箱

      iSmsMtm->SwitchCurrentEntryL(KMsvGlobalInBoxIndexEntryId);

      //构建消息索引

      TMsvEntry newIndexEntry;

      //newIndexEntry.iDate.HomeTime();//收件箱短信索引头在CSmsHeader中设置

      newIndexEntry.iMtm = KUidMsgTypeSMS;

      newIndexEntry.iType = KUidMsvMessageEntry;

      //in 3rd edition crashes here if capabilities are wrong

      newIndexEntry.iServiceId = iSmsMtm->ServiceId();

      newIndexEntry.iDetails.Set(aAddr);

      newIndexEntry.iDescription.Set(aContent.Left(LEN));

      newIndexEntry.SetUnread(ETrue);

      iSmsMtm->Entry().CreateL(newIndexEntry);

      TMsvId smsId = newIndexEntry.Id();

      iSmsMtm->SwitchCurrentEntryL(smsId);

      //填充消息存储区

      接上页

      //CSmsHeader& header = iSmsMtm->SmsHeader();

      //header.SetFromAddressL(aAddr);//这里我采用了两种方法,均不能正确设置发件人号码

      //iSmsMtm->AddAddresseeL(aAddr);//后来才知道这里为收件人号码,所以必须在以后修改

      CRichText& body = iSmsMtm->Body();

      body.Reset();

      body.InsertL(0, *iSmsContext);

      //提交保存

      iSmsMtm->SaveMessageL();

      //完善消息头,设置发件人号码和发送时间

      CMsvStore* messageStore = iSmsMtm->Entry().EditStoreL();

      CleanupStack::PushL( messageStore );

      CSmsHeader* hdr = CSmsHeader::NewL( CSmsPDU::ESmsDeliver, body );

      CleanupStack::PushL( hdr );

      hdr->SetFromAddressL(iNumber);

      TTime nowTime;

      nowTime.HomeTime();

      hdr->Deliver().SetServiceCenterTimeStamp(nowTime);

      hdr->StoreL(*messageStore);

      messageStore->CommitL();

      CleanupStack::PopAndDestroy(hdr);

      CleanupStack::PopAndDestroy(messageStore);

      // 修改当前消息索引为只读,这样收件箱列表处浏览会有回复选项

      //但是如果在之前就设置ReadOnly就会导致SaveMessageL出错

      newIndexEntry.SetReadOnly(ETrue);

      //消息索引提交更改

      iSmsMtm->Entry().ChangeL(newIndexEntry);

      4.发生消息条目

      其实发送消息可以使用客户端MTM方法,但是一般都是在活动对象中实现,或者实现Send-As API、CSendAppUi类来实现。以下代码简单给出客户端Mtm的方法:

      //发送消息

      //iMtm是在新建sms阶段设定

      TMsvEntry msvEntry = iMtm->Entry().Entry();

      //重新设定TMsvEntry

      msvEntry.iDetails.Set(iRecipient->Des()); // set recipient info in details

      msvEntry.SetInPreparation(EFalse); // set inPreparation to false

      msvEntry.SetSendingState(KMsvSendStateWaiting); // set the sending state (immediately)

      msvEntry.iDate.HomeTime(); // set time to Home Time

      接上页

      // 得到sms内容

      CRichText& mtmBody = iMtm->Body();

      mtmBody.Reset();

      mtmBody.InsertL(0, KGDSMSTag); //插入我们的短信内容

      // 使用CSmsClientMtm类处理sms

      CSmsClientMtm* smsMtm = STATIC_CAST(CSmsClientMtm*, iMtm);

      smsMtm->RestoreServiceAndSettingsL();

      //CSmsHeader封装sms消息的参数,像服务中心号码和发送设定

      CSmsHeader& header = smsMtm->SmsHeader();

      //CSmsSettings类用来详细设定sms Header

      CSmsSettings* sendOptions = CSmsSettings::NewL();

      CleanupStack::PushL(sendOptions);

      sendOptions->CopyL(smsMtm->ServiceSettings());

      sendOptions->SetDelivery(ESmsDeliveryImmediately);//设定立即发送

      header.SetSmsSettingsL(*sendOptions);

      //检查服务中心号码有效性

      if(header.Message().ServiceCenterAddress().Length() == 0)

      {

      // 如果没有设定,则查找默认中心号码

      CSmsSettings* serviceSettings = &(smsMtm->ServiceSettings());

      //中心号码列表为空

      if(!serviceSettings->NumSCAddresses())

      {

      // 错误消息

      iEikonEnv->InfoWinL(_L("No service center number"),_L("cannot send this one."));

      }

      else

      {

      // 设定为默认服务中心号码

      CSmsNumber* sc = 0;

      sc = &(serviceSettings->SCAddress(serviceSettings->DefaultSC()));

      header.Message().SetServiceCenterAddressL(sc->Address());

      }

      }

      CleanupStack::PopAndDestroy();

      ... ...

      CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;

      CleanupStack::PushL(selection);

      selection->AppendL(movedId); // 添加我们要发送的sms,movedId在省略部分有定义,是TMsvId型变量

      // 调用的这个函数是用于发送的,具体的代码后面介绍

      SetScheduledSendingStateL(selection);

      接上页

      CleanupStack::PopAndDestroy(); // selection

      return ETrue; // 到这里sms已被发送

      ---------------------------------------------------------------------------------------------------

      ---------------------------------------------------------------------------------------------------

      void SetScheduledSendingStateL(CMsvEntrySelection* aSelection)

      {

      CBaseMtm* smsMtm = iMtm;

      // 添加entry到任务列表

      TBuf8<1> dummyParams;

      CCommandAbsorbingControl::NewLC();

      CMsvOperationWait* waiter = CMsvOperationWait::NewLC();

      waiter->Start();

      // 这个函数是关键

      CMsvOperation* op= smsMtm->InvokeAsyncFunctionL(ESmsMtmCommandScheduleCopy,

      *aSelection, dummyParams, waiter->iStatus);

      CleanupStack::PushL(op);

      CActiveScheduler::Start(); //开始时间表中任务

      CleanupStack::PopAndDestroy(3); // waiter, op, CCommandAbsorbingControl

      }

  • 相关阅读:
    Asp.NET 4.0 ajax实例DataView 模板编程1
    ASP.NET 4.0 Ajax 实例DataView模板编程 DEMO 下载
    部分东北话、北京话
    .NET 培训课程解析(一)
    ASP.NET 4.0 Ajax 实例DataView模板编程2
    ASP.NET Web Game 架构设计1服务器基本结构
    ASP.NET Web Game 构架设计2数据库设计
    TFS2008 基本安装
    Linux上Oracle 11g安装步骤图解
    plsql developer远程连接oracle数据库
  • 原文地址:https://www.cnblogs.com/zziss/p/2110562.html
Copyright © 2011-2022 走看看