<?xml version="1.0" encoding="gb2312"?>
<rss version="2.0">
<channel>
<title><![CDATA[夫哥的技术空间]]></title>
        <image>
        <title>http://hi.baidu.com</title>
        <link>http://hi.baidu.com</link>
        <url>http://img.baidu.com/img/logo-hi.gif</url>
        </image>
<description><![CDATA[主打symbian]]></description>
<link>http://hi.baidu.com/c%5Flinuxsymbian</link>
<language>zh-cn</language>
<generator>www.baidu.com</generator>
<ttl>5</ttl>


<item>
        <title><![CDATA[AddViewL()和AddToStackL()的区别]]></title>
        <link><![CDATA[http://hi.baidu.com/c%5Flinuxsymbian/blog/item/817c770a1643df1995ca6b39.html]]></link>
        <description><![CDATA[
		
		<p>AddToStackL()完成的功能只是把容器放到控件栈上以便接受各种事件,并不是把所有权交给UI,所以在最后析构函数里需要自己释放.</p>
<p>AddViewL(iAppView1)之后iAppView1的所有权就交给了AppUi，以后由AppUi负责删除它。<br>
你再删一次就是重复删除，所以会报错。</p> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/category/Symbian%20Os%20S60">Symbian Os S60</a>&nbsp;<a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/item/817c770a1643df1995ca6b39.html#comment">查看评论</a>]]></description>
        <pubDate>2008-10-26  19:19</pubDate>
        <category><![CDATA[Symbian Os S60]]></category>
        <author><![CDATA[c_linuxsymbian]]></author>
		<guid>http://hi.baidu.com/c%5Flinuxsymbian/blog/item/817c770a1643df1995ca6b39.html</guid>
</item>

<item>
        <title><![CDATA[symbian应用程序中视图切换问题]]></title>
        <link><![CDATA[http://hi.baidu.com/c%5Flinuxsymbian/blog/item/5f7518dce20a40a7cd11663e.html]]></link>
        <description><![CDATA[
		
		<p>下面这个例子是基于<font color="#ff0000">传统<strong style="color: black; background-color: #a0ffff"><font color="#ff0000">Symbian</font></strong>   OS架构 ，</font><font size="+0">和<font color="#0000ff">Series   60特有的CAknView多视图架构</font>不一样！<br>
</font></p>
<p>最简单的办法是通过CCoeControl::MakeVisible()函数改变Container的可见性：<font color="#ff0000">&nbsp;&nbsp;&nbsp;&nbsp;<br>
</font>  1.   在AppUi::ConstructL()里创建两个Container类的实例，并调用AddToStackL()将它们加入到Constrol   Stack中，然后隐藏暂时不显示的Container   <br>
    <br>
  void   CMyAppUi::ConstructL()   <br>
          {   <br>
          BaseConstructL();   <br>
    <br>
          iContainer1   =   CMyContainer1::NewL(ClientRect());   <br>
          iContainer2   =   CMyContainer2::NewL(ClientRect());   <br>
          AddToStackL(iContainer2);   <br>
          AddToStackL(iContainer1);   <br>
    <br>
          iContainer2-&gt;MakeVisible(EFalse);   <br>
          }   <br>
    <br>
  2.在接收到命令后切换两个Container的可见性   <br>
    <br>
  void   CMyAppUi::HandleCommandL(TInt   aCommand)   <br>
          {   <br>
          switch(aCommand)   <br>
                  {   <br>
                  case   ESwitchToContainer2:   <br>
                          {   <br>
                          iContainer2-&gt;MakeVisible(ETrue);   <br>
                          iContainer1-&gt;MakeVisible(EFalse);   <br>
                          break;   <br>
                          }   <br>
                  case   EEikCmdExit:   <br>
                  case   EAknSoftkeyExit:   <br>
                          {   <br>
                          Exit();   <br>
                          break;   <br>
                          }   <br>
                  default:   <br>
                          {   <br>
  //                         Panic(EHelloWorldBasicUi);   <br>
                          break;   <br>
                          }   <br>
                  }   <br>
          }   <br>
    <br>
  3.   在AppUi的析构函数中调用RemoveFromStackL()将两个Container从Control   Stack中移除并delete掉。   <br>
  CMyAppUi::~CHelloWorldAppUi()   <br>
          {   <br>
          if   (iContainer1)   <br>
                  {   <br>
                  <strong style="color: black; background-color: #ffff66">RemoveFromStack</strong>(iContainer1);   <br>
                  delete   iContainer1;   <br>
                  }   <br>
          if   (iContainer2)   <br>
                  {   <br>
                  <strong style="color: black; background-color: #ffff66">RemoveFromStack</strong>(iContainer2);   <br>
                  delete   iContainer2;   <br>
                  }                   <br>
          }   <br>
    <br>
  　　另一个办法是一开始只创建Container1，等用到Container2时再创建Container2，并销毁Container1。</p> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/category/Symbian%20Os%20S60">Symbian Os S60</a>&nbsp;<a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/item/5f7518dce20a40a7cd11663e.html#comment">查看评论</a>]]></description>
        <pubDate>2008-10-26  19:13</pubDate>
        <category><![CDATA[Symbian Os S60]]></category>
        <author><![CDATA[c_linuxsymbian]]></author>
		<guid>http://hi.baidu.com/c%5Flinuxsymbian/blog/item/5f7518dce20a40a7cd11663e.html</guid>
</item>

<item>
        <title><![CDATA[在其他类或函数中使用appui的成员函数]]></title>
        <link><![CDATA[http://hi.baidu.com/c%5Flinuxsymbian/blog/item/0cf78c819cbde0debd3e1e63.html]]></link>
        <description><![CDATA[
		
		<p>&nbsp;&nbsp;&nbsp;<font color="#800080" size="4">((CRsSisManagerAppUi*)(iEikonEnv-&gt;EikAppUi()))-&gt;ExtractCurrentSisFile();</font></p>
<p><font color="#800080" size="4">CXXXAppUi为你自己的appui类，先通过环境iEikonEnv-&gt;EikAppUi获得你appui类的指针，然后强制转换，你就可以获取自己appui类的成员函数。</font></p>
<p><font color="#800080" size="4">无需继承，友元，回调等容易把关系搞复杂的方式使用appui的成员函数。<br>
</font></p> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/category/Symbian%20Os%20S60">Symbian Os S60</a>&nbsp;<a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/item/0cf78c819cbde0debd3e1e63.html#comment">查看评论</a>]]></description>
        <pubDate>2008-10-26  16:45</pubDate>
        <category><![CDATA[Symbian Os S60]]></category>
        <author><![CDATA[c_linuxsymbian]]></author>
		<guid>http://hi.baidu.com/c%5Flinuxsymbian/blog/item/0cf78c819cbde0debd3e1e63.html</guid>
</item>

<item>
        <title><![CDATA[CEikAppUi::Exit()和User::Exit(0)的区别]]></title>
        <link><![CDATA[http://hi.baidu.com/c%5Flinuxsymbian/blog/item/9ae7440fe3ee4febab645701.html]]></link>
        <description><![CDATA[
		
		symbian 中的HandCommandL()函数中，一般&ldquo;退出&rdquo;都是调用 Exit(),这其实是CEikAppUi成员函数。CEikAppUi::<strong style="color: black; background-color: rgb(255, 255, 102);">Exit</strong>()通过UI框架来析构各个资源。<br>
User::Exit(0)则比较暴力，直接把进程/线程干掉。<br>
<br>
但有些情况下，<strong style="color: black; background-color: rgb(255, 255, 102);">通过Exit</strong>()退出，由于自己程序某些地方资源分配和释放有问题，造成程序退出有问题。<br>
这时可以才用User::Exit(0)来直接退出程序。 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/category/Symbian%20Os%20S60">Symbian Os S60</a>&nbsp;<a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/item/9ae7440fe3ee4febab645701.html#comment">查看评论</a>]]></description>
        <pubDate>2008-09-24  21:21</pubDate>
        <category><![CDATA[Symbian Os S60]]></category>
        <author><![CDATA[c_linuxsymbian]]></author>
		<guid>http://hi.baidu.com/c%5Flinuxsymbian/blog/item/9ae7440fe3ee4febab645701.html</guid>
</item>

<item>
        <title><![CDATA[case 后面忘记写 break!!!害我调了一天，泪奔啊！！！]]></title>
        <link><![CDATA[http://hi.baidu.com/c%5Flinuxsymbian/blog/item/8f02c0a448ca9ef19152ee5d.html]]></link>
        <description><![CDATA[
		
		充分说明了，麻绳就从细处断<br>
越是你认为没问题的，偏偏就要出问题<br> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/category/%C4%AC%C8%CF%B7%D6%C0%E0">默认分类</a>&nbsp;<a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/item/8f02c0a448ca9ef19152ee5d.html#comment">查看评论</a>]]></description>
        <pubDate>2008-09-11  20:12</pubDate>
        <category><![CDATA[默认分类]]></category>
        <author><![CDATA[c_linuxsymbian]]></author>
		<guid>http://hi.baidu.com/c%5Flinuxsymbian/blog/item/8f02c0a448ca9ef19152ee5d.html</guid>
</item>

<item>
        <title><![CDATA[被包含类回调包含类函数方法]]></title>
        <link><![CDATA[http://hi.baidu.com/c%5Flinuxsymbian/blog/item/9bfd29ea24d9a7d5d539c903.html]]></link>
        <description><![CDATA[
		
		/****************************h**********************/<br>
class MNotifier //接口类 <br>
{<br>
public:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    virtual void Notify(){}<br>
};<br>
<br>
class CEO //被包含类<br>
{<br>
public:<br>
&nbsp;&nbsp;      MNotifier *iNotifier;<br>
&nbsp;&nbsp;      void MakeDecision();<br>
};<br>
<br>
class Company : public MNotifier  //包含类要继承接口类<br>
{<br>
/*From  class MNotifier*/<br>
public:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    void Notify(); //需要重写类MNotifier的虚函数<br>
private:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    CEO ceo;<br>
};<br>
/**************************cpp****************************/<br>
void CEO::MakeDecision()<br>
{<br>
&nbsp;&nbsp;    iNotifer-&gt;Notify(); //这样，被拥有类成员函数 就回调了 拥有类的成员函数；<br>
} 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/category/c%2B%2B">c++</a>&nbsp;<a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/item/9bfd29ea24d9a7d5d539c903.html#comment">查看评论</a>]]></description>
        <pubDate>2008-09-08  13:32</pubDate>
        <category><![CDATA[c++]]></category>
        <author><![CDATA[c_linuxsymbian]]></author>
		<guid>http://hi.baidu.com/c%5Flinuxsymbian/blog/item/9bfd29ea24d9a7d5d539c903.html</guid>
</item>

<item>
        <title><![CDATA[Find the UIDs and Capabilities of Symbian EXE/DLL]]></title>
        <link><![CDATA[http://hi.baidu.com/c%5Flinuxsymbian/blog/item/9c28d4a8dda309b7cb130ca8.html]]></link>
        <description><![CDATA[
		
		<a href="http://blog.oasisfeng.com/2007/12/14/enable-prio-first-last-piece-in-utorrent/">能</a> &#187;&#187;
<div >                       
<table cellspacing="0" cellpadding="0" class="main_title_wrapper" boder="0">
    <tbody>
        <tr class="main_title_date_box">
            <td class="main_title_date_num"> </td>
            <td class="main_title_box" rowspan="2"> </td>
        </tr>
        <tr>
            <td class="main_title_date_other"> </td>
        </tr>
    </tbody>
</table>
<div class="main_post">
<h3>(1) Emulator Build (Win32 PE)</h3>
<p>First, find the start address of section &ldquo;.SYMBIAN&rdquo; by typically using &ldquo;dumpbin /section:.SYMBIAN &lt;Excutable File&gt;&rdquo;.</p>
<p>The output looks like:</p>
<pre>SECTION HEADER #6<br>.SYMBIAN name<br>30 virtual size<br>17000 virtual address (00417000 to 0041702F)<br>1000 size of raw data<br>17000 file pointer to raw data (00017000 to 00017FFF)<br>0 file pointer to relocation table<br>0 file pointer to line numbers<br>0 number of relocations<br>0 number of line numbers<br>C0000040 flags<br>Initialized Data<br>Read Write</pre>
<p>According to the line containing &ldquo;virtual address&rdquo;, section &ldquo;.SYMBIAN&rdquo; starts at address 0×00017000.</p>
<p>Now, use any hex-editor to view the content at this address:</p>
<blockquote>
<p>00017000h: 7A 00 00 10 00 00 00 00 B2 97 1F 10 5E 01 00 00<br>
00017010h: B2 97 1F 10 57 B6 1F 10 <strong>B6 E1 0F 00</strong> 00 00 00 00</p>
</blockquote>
<p>The first 3 dwords are UIDs: 0×1000007A stands for &ldquo;Symbian EXE&rdquo;, 0×101F97B2 is the unique UID of this file. (no UID2 for Symbian EXE, but this field is essential for DLL to indicate the framework, eg. 0×10009D8D for ECOM)</p>
<p>The capabilities field at offset 0×18h holds all the capabilities for this executive in the form of bitmask. Thus, 0×000FE1B6 is translated to the following capabilities: (see enumerator TCapability in Symbian SDK)</p>
<p>CommDD PowerMgmt ReadDeviceData WriteDeviceData TrustedUI ProtServ NetworkServices LocalServices ReadUserData WriteUserData Location SurroundingsDD UserEnvironment</p>
<h3>(2) Target Build (Symbian PE)</h3>
<p>3 UIDs located at the very beginning of the executive file, and the capabilities field is at fixed offset 0×88h. (same meaning as described for emulator build)</p>
</div>
</div> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/category/Symbian%20Os%20S60">Symbian Os S60</a>&nbsp;<a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/item/9c28d4a8dda309b7cb130ca8.html#comment">查看评论</a>]]></description>
        <pubDate>2008-09-02  15:12</pubDate>
        <category><![CDATA[Symbian Os S60]]></category>
        <author><![CDATA[c_linuxsymbian]]></author>
		<guid>http://hi.baidu.com/c%5Flinuxsymbian/blog/item/9c28d4a8dda309b7cb130ca8.html</guid>
</item>

<item>
        <title><![CDATA[模拟器和能力（capability）检查]]></title>
        <link><![CDATA[http://hi.baidu.com/c%5Flinuxsymbian/blog/item/ab28ec33b7286ffe1a4cffd8.html]]></link>
        <description><![CDATA[
		
		From Forum Nokia Wiki              
<p>配置好后，模拟器会把和plateform security相关的信息输出到epocwind.out。这有助于开发者分析碰到的相关问题，比如查找失缺的capability。</p>
<p>使用这个功能不需要额外的工具，只是在现有的环境下做些参数配置。首先，我们需要知道模拟器输出文件epocwind.out的路径，以便以后查询。epocwind.out的路径在</p>
<pre>c:\Documents and Settings\&lt;your account&gt;\Local Settings\Temp\</pre>
<p><br>
在配置文件epoc.ini中，查看并确保以下参数被打开。</p>
<pre>PlatSecDiagnostics ON<br>PlatSecEnforceSysBin ON<br>LogToFile 1</pre>
<div class="thumb tright">
<div style="width: 182px;" class="thumbinner"><a title="图一" class="image" href="http://wiki.forum.nokia.com/index.php/Image:01_06_epocer01.png"><img height="159" border="0" width="180" class="thumbimage" src="http://wiki.forum.nokia.com/images/thumb/e/ee/01_06_epocer01.png/180px-01_06_epocer01.png" alt="图一"></a>
<div class="thumbcaption">
<div style="float: right;" class="magnify"><a title="Enlarge" class="internal" href="http://wiki.forum.nokia.com/index.php/Image:01_06_epocer01.png"><img height="11" width="15" src="http://wiki.forum.nokia.com/skins/common/images/magnify-clip.png"></a></div>
图一</div>
</div>
</div>
<div class="thumb tright">
<div style="width: 182px;" class="thumbinner"><a title="图二" class="image" href="http://wiki.forum.nokia.com/index.php/Image:01_06_epocer02.png"><img height="112" border="0" width="180" class="thumbimage" src="http://wiki.forum.nokia.com/images/thumb/f/f7/01_06_epocer02.png/180px-01_06_epocer02.png" alt="图二"></a>
<div class="thumbcaption">
<div style="float: right;" class="magnify"><a title="Enlarge" class="internal" href="http://wiki.forum.nokia.com/index.php/Image:01_06_epocer02.png"><img height="11" width="15" src="http://wiki.forum.nokia.com/skins/common/images/magnify-clip.png"></a></div>
图二</div>
</div>
</div>
<div class="thumb tright">
<div style="width: 182px;" class="thumbinner"><a title="图三" class="image" href="http://wiki.forum.nokia.com/index.php/Image:01_06_epocer03.png"><img height="116" border="0" width="180" class="thumbimage" src="http://wiki.forum.nokia.com/images/thumb/5/53/01_06_epocer03.png/180px-01_06_epocer03.png" alt="图三"></a>
<div class="thumbcaption">
<div style="float: right;" class="magnify"><a title="Enlarge" class="internal" href="http://wiki.forum.nokia.com/index.php/Image:01_06_epocer03.png"><img height="11" width="15" src="http://wiki.forum.nokia.com/skins/common/images/magnify-clip.png"></a></div>
图三</div>
</div>
</div>
<p>接下来打开模拟器，打开如图一至三所示的选项，</p>
<p>不过，在执行上述配置时可能会发生如下的错误，见图四，原因是开发者PC环境中当前所用的JRE版本没出现在另一个配置文件中，见config.properties。</p>
<pre>\Epoc32\tools\ecmt\config\</pre>
<div class="thumb tright">
<div style="width: 182px;" class="thumbinner"><a title="图四" class="image" href="http://wiki.forum.nokia.com/index.php/Image:01_06epocer04.png"><img height="103" border="0" width="180" class="thumbimage" src="http://wiki.forum.nokia.com/images/thumb/7/75/01_06epocer04.png/180px-01_06epocer04.png" alt="图四"></a>
<div class="thumbcaption">
<div style="float: right;" class="magnify"><a title="Enlarge" class="internal" href="http://wiki.forum.nokia.com/index.php/Image:01_06epocer04.png"><img height="11" width="15" src="http://wiki.forum.nokia.com/skins/common/images/magnify-clip.png"></a></div>
图四</div>
</div>
</div>
<p>比如当前所用JRE版本是1.6，为了加入config.properties，见图五。</p>
<div class="thumb tright">
<div style="width: 182px;" class="thumbinner"><a title="图五" class="image" href="http://wiki.forum.nokia.com/index.php/Image:01_06_epocer05.png"><img height="8" border="0" width="180" class="thumbimage" src="http://wiki.forum.nokia.com/images/thumb/d/d4/01_06_epocer05.png/180px-01_06_epocer05.png" alt="图五"></a>
<div class="thumbcaption">
<div style="float: right;" class="magnify"><a title="Enlarge" class="internal" href="http://wiki.forum.nokia.com/index.php/Image:01_06_epocer05.png"><img height="11" width="15" src="http://wiki.forum.nokia.com/skins/common/images/magnify-clip.png"></a></div>
图五</div>
</div>
</div>
<p>查看输出结果可以直接打开epocwind.out，也可以从Carbide.c++ IDE中查看。需要预先打开相关的view，如图六。</p>
<div class="thumb tright">
<div style="width: 182px;" class="thumbinner"><a title="图六" class="image" href="http://wiki.forum.nokia.com/index.php/Image:01_06epocer06.png"><img height="110" border="0" width="180" class="thumbimage" src="http://wiki.forum.nokia.com/images/thumb/e/e9/01_06epocer06.png/180px-01_06epocer06.png" alt="图六"></a>
<div class="thumbcaption">
<div style="float: right;" class="magnify"><a title="Enlarge" class="internal" href="http://wiki.forum.nokia.com/index.php/Image:01_06epocer06.png"><img height="11" width="15" src="http://wiki.forum.nokia.com/skins/common/images/magnify-clip.png"></a></div>
图六</div>
</div>
</div>
<p>如果存在capability的问题，在epocwind.out中应该看到警告信息。</p>
<pre>PlatSec Warning ...</pre>
<p>当然，别忘了用Carbide.c++ IDE build时，平台必须是winscw。上述方法在S60 SDK 3.0 MR + Carbide.c++ IDE 1.3中通过测试。</p> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/category/%C4%AC%C8%CF%B7%D6%C0%E0">默认分类</a>&nbsp;<a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/item/ab28ec33b7286ffe1a4cffd8.html#comment">查看评论</a>]]></description>
        <pubDate>2008-09-02  14:40</pubDate>
        <category><![CDATA[默认分类]]></category>
        <author><![CDATA[c_linuxsymbian]]></author>
		<guid>http://hi.baidu.com/c%5Flinuxsymbian/blog/item/ab28ec33b7286ffe1a4cffd8.html</guid>
</item>

<item>
        <title><![CDATA[Symbian OS Error Codes]]></title>
        <link><![CDATA[http://hi.baidu.com/c%5Flinuxsymbian/blog/item/c2409bf4073be3dff3d3855e.html]]></link>
        <description><![CDATA[
		
		<font color="Red"><font size="4">S60错误码大全！可以自己动手察看的出错内容！</font></font><br>
<br>
<br>
用S60系统的人多多少少都会有系统出错的时候，可是系统总是给你一个&ldquo;SYSTEM ERROR&rdquo;。<br>
<br>
现在有个简单的办法，就可以让系统在出错时能显示出错代码以及更进一步的错误原因说明的提示。<br>
<br>
新建一个名为&ldquo;ErrRd&rdquo;的空文本文件，放到C:\system\bootdata这个目录下就行了！<br>
<br>
以下是Generic Errors代码说明：<br>
<br>
KErrNone 0 <br>
KErrNotFound -1 找不到指定的物件<br>
KErrGeneral -2 一般（无指定）错误<br>
KErrCancel -3 操作被取消<br>
KErrNoMemory -4 不够内存<br>
KErrNotSupported -5 不支持所要求的操作<br>
KErrArgument -6 错误的要求<br>
KErrTotalLossOfPrecision -7 精确的失去总和（直接翻译）<br>
KErrBadHandle -8 错误的物件<br>
KErrOverflow -9 超出限定的界限<br>
KErrUnderflow -10 少于限定的界限<br>
KErrAlreadyExists -11 已经有了<br>
KErrPathNotFound -12 找不到指定的文件夹<br>
KErrDied -13 关闭<br>
KErrInUse -14 指定的物件正被其他程序使用中<br>
KErrServerTerminated -15 伺服器关闭了<br>
KErrServerBusy -16 伺服器正忙着<br>
KErrCompletion -17 完成的过程中出现错误<br>
KErrNotReady -18 还没准备好<br>
KErrUnknown -19 不知名的错误<br>
KErrCorrupt -20 坏了<br>
KErrAccessDenied -21 拒绝接受<br>
KErrLocked -22 锁了<br>
KErrWrite -23 读写失败<br>
KErrDisMounted -24 错误的disk<br>
KErrEof -25 出乎预料的文件到了尾端<br>
KErrDiskFull -26 Disk满了<br>
KErrBadDriver -27 坏了的器材驱动<br>
KErrBadName -28 不允许的名称<br>
KErrCommsLineFail -29 Comms线失败<br>
KErrCommsFrame -30 Comms框框错误<br>
KErrCommsOverrun -31 Comms 超频错误<br>
KErrCommsParity -32 Comms同位错误<br>
KErrTimedOut -33 时间到了<br>
KErrCouldNotConnect -34 连接失败<br>
KErrCouldNotDisconnect -35 断连接失败<br>
KErrDisconnected -36 断了<br>
KErrBadLibraryEntryPoint -37 损坏的资料库接入点<br>
KErrBadDescriptor -38 损坏的描述讯息块<br>
KErrAbort -39 被打断了<br>
KErrTooBig -40 太大了<br>
KErrDivideByZero -41 除于零<br>
KErrBadPower -42 电池快没电了<br>
KErrDirFull -43 文件夹满了<br>
KErrHardwareNotAvailable -44 <br>
KErrSessionClosed -45 <br>
KErrPermissionDenied -46<br>
<br>
S60 的都能通用。<br>
<font color="#ff0000" size="5"> 更多错误码查询：http://www.newlc.com/Symbian-OS-Error-Codes.html</font> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/category/Symbian%20Os%20S60">Symbian Os S60</a>&nbsp;<a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/item/c2409bf4073be3dff3d3855e.html#comment">查看评论</a>]]></description>
        <pubDate>2008-09-01  10:04</pubDate>
        <category><![CDATA[Symbian Os S60]]></category>
        <author><![CDATA[c_linuxsymbian]]></author>
		<guid>http://hi.baidu.com/c%5Flinuxsymbian/blog/item/c2409bf4073be3dff3d3855e.html</guid>
</item>

<item>
        <title><![CDATA[文件遍历-递归实现]]></title>
        <link><![CDATA[http://hi.baidu.com/c%5Flinuxsymbian/blog/item/866be9f7bc5de324720eec3b.html]]></link>
        <description><![CDATA[
		
		void CFilesAppUi::HandleCommandL(TInt aCommand)<br>
{<br>
&nbsp;&nbsp;&nbsp;  switch (aCommand)<br>
&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;  case EEikCmdExit:<br>
&nbsp;&nbsp;&nbsp;  case EAknSoftkeyExit:<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  Exit();<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  break;<br>
<br>
&nbsp;&nbsp;&nbsp;  case ECommand1:  <br>
    {<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  // 采用同步递归实现，遍历文件时 无法 响应其他事件<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  TBuf16&lt;20&gt; str;<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  str.Copy(_L(&quot;c:\\system\\&quot;));<br>
<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  RFs iFs; // 创建一个RFs类型的句柄  准备访问文件服务器<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  User::LeaveIfError(iFs.Connect()); // 连接到文件服务器<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  CDir* dir= NULL; // 创建一个目录列表对象指针<br>
<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  Scan(str, dir, iFs);<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  iFs.Close();<br>
&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  break;<br>
&nbsp;&nbsp;&nbsp;  <br>
 default:<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  Panic(EFilesUi);<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  break;<br>
&nbsp;&nbsp;&nbsp;  }<br>
}<br>
<br>
void CFilesAppUi::Scan(TBuf16&lt;256&gt; str, CDir *dir, RFs iFs)<br>
{<br>
&nbsp;&nbsp;&nbsp;  // 获取目录的文件列表 于dir中<br>
&nbsp;&nbsp;&nbsp;  User::LeaveIfError(iFs.GetDir(str, KEntryAttNormal|KEntryAttMatchMask,<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  ESortNone, dir));<br>
&nbsp;&nbsp;&nbsp;  for (TInt i = 0; i &lt; dir-&gt;Count(); i++)<br>
&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  if ((*dir)[i].IsDir())<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  str += ((*dir)[i].iName);<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  str += (_L(&quot;\\&quot;));<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  Scan(str, dir, iFs);<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  str.Delete(str.Length()-(*dir)[i].iName.Length()-1, (*dir)[i].iName.Length()+1);<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  else<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  CEikonEnv::Static()-&gt;InfoWinL((*dir)[i].iName, KNullDesC());<br>
&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;  delete dir;<br>
}<br> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/category/Symbian%20Os%20S60">Symbian Os S60</a>&nbsp;<a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/item/866be9f7bc5de324720eec3b.html#comment">查看评论</a>]]></description>
        <pubDate>2008-08-29  16:59</pubDate>
        <category><![CDATA[Symbian Os S60]]></category>
        <author><![CDATA[c_linuxsymbian]]></author>
		<guid>http://hi.baidu.com/c%5Flinuxsymbian/blog/item/866be9f7bc5de324720eec3b.html</guid>
</item>

<item>
        <title><![CDATA[全局的非阻塞 信息提示 对话框]]></title>
        <link><![CDATA[http://hi.baidu.com/c%5Flinuxsymbian/blog/item/57954144d4600784b2b7dcc0.html]]></link>
        <description><![CDATA[
		
		void CAppUi::ConstructL()<br>
{<br>
  .......<br>
  &nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  // Display welcome information.<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  HBufC* info = iEikonEnv-&gt;AllocReadResourceLC(R_WELCOME_INFO_TXT);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <font color="#ff0000">//函数尾为C的表示自动进栈(push)</font><br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  DisplayNote(*info);<br>
&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  CleanupStack::PopAndDestroy(); <font color="#ff0000">// 把info指向内存出栈并销毁</font><br>
}<br>
<br>
void CAppUi::DisplayNote(const TDesC&amp; aText)<br>
{<br>
&nbsp;&nbsp;&nbsp;  HBufC* temp = HBufC::NewLC(aText.Length());<font color="#ff0000">//函数尾为C的表示自动进栈(push</font>)<br>
&nbsp;&nbsp;&nbsp;  TPtr ptr = temp-&gt;Des();<br>
&nbsp;&nbsp;&nbsp;  ptr.Append(aText);<br>
&nbsp;&nbsp;&nbsp;  CAknMessageQueryDialog* dlg = CAknMessageQueryDialog::NewL(ptr);<br>
&nbsp;&nbsp;&nbsp;  TBool ret = dlg-&gt;ExecuteLD(R_INFO_NOTE);<br>
&nbsp;&nbsp;&nbsp;  CleanupStack::PopAndDestroy();<font color="#ff0000"> //把temp指向内存出栈并销毁</font><br>
}<br>
<font color="#0000ff">//R_WELCOME_INFO_TXT为字符  和 R_INFO_NOTE为对话框  要在资源文件中定义</font> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/category/Symbian%20Os%20S60">Symbian Os S60</a>&nbsp;<a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/item/57954144d4600784b2b7dcc0.html#comment">查看评论</a>]]></description>
        <pubDate>2008-08-19  11:05</pubDate>
        <category><![CDATA[Symbian Os S60]]></category>
        <author><![CDATA[c_linuxsymbian]]></author>
		<guid>http://hi.baidu.com/c%5Flinuxsymbian/blog/item/57954144d4600784b2b7dcc0.html</guid>
</item>

<item>
        <title><![CDATA[哈希表和哈希函数]]></title>
        <link><![CDATA[http://hi.baidu.com/c%5Flinuxsymbian/blog/item/09a2f5ce4cb89c3fb600c8df.html]]></link>
        <description><![CDATA[
		
		一般的线性表、树中，记录在结构中的相对位置是随机的即和记录的关键字之间不存在确定的关系，在结构中查找记录时需进行一系列和关键字的比较。这一类查找 方法建立在&ldquo;比较&rdquo;的基础上，查找的效率与比较次数密切相关。理想的情况是能直接找到需要的记录，因此必须在记录的存储位置和它的关键字之间建立一确定的 对应关系f，使每个关键字和结构中一个唯一的存储位置相对应。因而查找时，只需根据这个对应关系f找到给定值K的像f(K)。若结构中存在关键字和K相等 的记录，则必定在f(K)的存储位置上，由此不需要进行比较便可直接取得所查记录。在此，称这个对应关系f为哈希函数，按这个思想建立的表为哈希表（又称 为杂凑法或散列法）。<br>
<br>
哈希表不可避免冲突(collision)现象：对不同的关键字可能得到同一哈希地址 即key1≠key2，而f(key1)=f(key2)。具有相同函数值的关键字对该哈希函数来说称为同义词(synonym)。 因此，在建造哈希表时不仅要设定一个好的哈希函数，而且要设定一种处理冲突的方法。可如下描述哈希表：根据设定的哈希函数H(key)和所选中的处理冲突 的方法，将一组关键字映象到一个有限的、地址连续的地址集(区间)上并以关键字在地址集中的&ldquo;象&rdquo;作为相应记录在表中的存储位置，这种表被称为哈希表。<br>
<br>
注：这个函数f(key)为哈希函数。(注意：这个函数并不一定是数学函数) 哈希函数是一个映象，即：将关键字的集合映射到某个地址集合上，它的设置很灵活，只要这个地址集合的大小不超出允许范围即可。 现实中哈希函数是需要构造的，并且构造的好才能使用的好。<br>
<br>
对于动态查找表而言，1) 表长不确定；2)在设计查找表时，只知道关键字所属范围，而不知道确切的关键字。因此，一般情况需建立一个函数关系，以f(key)作为关键字为key的 录在表中的位置，通常称这个函数f(key)为哈希函数。(注意：这个函数并不一定是数学函数) <br>
<br>
哈希函数是一个映象，即：将关键字的集合映射到某个地址集合上，它的设置很灵活，只要这个地址集合的大小不超出允许范围即可。 <br>
<br>
现实中哈希函数是需要构造的，并且构造的好才能使用的好。 <br>
<br>
用途：加密，解决冲突问题。。。。 <br>
用途很广，比特精灵中就使用了哈希函数，你可 以自己看看。 <br>
具体可以学习一下数据结构和算法的书。<br>
<br>
字符串哈希函数（著名的ELFhash算法）<br>
int ELFhash(char *key)<br>
{ unsigned long h=0;<br>
&nbsp;&nbsp; while(*key)<br>
&nbsp;&nbsp; { h=(h&lt;&lt;4)+*key++;<br>
    unsigned long g=h&amp;0Xf0000000L;<br>
    if(g) h^=g&gt;&gt;24;<br>
    h&amp;=~g;<br>
&nbsp;&nbsp; }<br>
&nbsp;&nbsp; return h%MOD;<br>
} 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/category/%C4%AC%C8%CF%B7%D6%C0%E0">默认分类</a>&nbsp;<a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/item/09a2f5ce4cb89c3fb600c8df.html#comment">查看评论</a>]]></description>
        <pubDate>2008-08-11  15:22</pubDate>
        <category><![CDATA[默认分类]]></category>
        <author><![CDATA[c_linuxsymbian]]></author>
		<guid>http://hi.baidu.com/c%5Flinuxsymbian/blog/item/09a2f5ce4cb89c3fb600c8df.html</guid>
</item>

<item>
        <title><![CDATA[System panic reference常见panic]]></title>
        <link><![CDATA[http://hi.baidu.com/c%5Flinuxsymbian/blog/item/3ba54b64151131f6f73654c9.html]]></link>
        <description><![CDATA[
		
		<br>
1、E32USER-CBase 63<br>
只有Pop()；delete；<br>
2、E32USER-CBase 64<br>
只有Pop()；<br>
3、E32USER-CBase 71<br>
只有PushL()；<br>
4、E32USER-CBase 90<br>
只有PopAndDestroy()；<br>
5、Alloc:<br>
只有PushL()； Pop()；<br>
6、KERN-EXEC  3<br>
解引用NULL指针，<br>
7、USER 11<br>
字符串赋值时超过iMaxLength<br>
8、USER 44<br>
非NULL指针重复删除<br>
9、CONE 44<br>
Control being destroyed is still on the control stack，<br>
<br>
未调用RemoveFormStack();<br>
10、WSERV 14<br>
Printing with no active font.<br>
<br>
一般是调用DrawText();时未设置字体<br>
<br>
11、CONE 14<br>
<br>
Environment cannot find the specified resource in any resource file<br>
<br>
如StringLoader::LoadLC(R_HTTP_TX_SUCCESSFUL); 但R_HTTP_TX_SUCCESSFUL没在资源文件中定义<br>
<br>
更详细的可以参见SDK文档：<br>
2nd: Developer Library &#187; API Reference &#187; System panic reference <br>
3nd: Symbian OS v9.2 &#187; Symbian OS reference &#187; System panic reference<br> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/category/Symbian%20Os%20S60">Symbian Os S60</a>&nbsp;<a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/item/3ba54b64151131f6f73654c9.html#comment">查看评论</a>]]></description>
        <pubDate>2008-08-11  15:01</pubDate>
        <category><![CDATA[Symbian Os S60]]></category>
        <author><![CDATA[c_linuxsymbian]]></author>
		<guid>http://hi.baidu.com/c%5Flinuxsymbian/blog/item/3ba54b64151131f6f73654c9.html</guid>
</item>

<item>
        <title><![CDATA[symbian遍历目录文件--CDirScan类]]></title>
        <link><![CDATA[http://hi.baidu.com/c%5Flinuxsymbian/blog/item/4b9c531cb29be98d87d6b68e.html]]></link>
        <description><![CDATA[
		
		<p>使用以下函数可以遍历<strong style="color: black; background-color: rgb(255, 255, 102);">Symbian</strong>系统指定文件夹下的所有文件(包括子文件夹的文件)</p>
<p>//RLog::Log()是自定义的，相当于console-&gt;Printf()<br>
void GetPath() </p>
<p>{<br>
 _LIT(iSkinFileDir,&quot;C:\\system\\midlets\\&quot;);</p>
<p><br>
 <a name="baidusnap1"></a><strong style="color: black; background-color: rgb(160, 255, 255);">CDirScan</strong>* ds = <strong style="color: black; background-color: rgb(160, 255, 255);">CDirScan</strong>::NewLC(iCoeEnv-&gt;FsSession());<br>
 TRAPD(err,ds-&gt;SetScanDataL(iSkinFileDir,KEntryAttNormal,ESortByName|EAscending,<strong style="color: black; background-color: rgb(160, 255, 255);">CDirScan</strong>::EScanDownTree));<br>
 if (err!=KErrNone) <br>
 {  <br>
&nbsp;&nbsp; CleanupStack::PopAndDestroy(ds);<br>
&nbsp;&nbsp; return;<br>
 }</p>
<p> CDir* c = NULL; <br>
 TFileName fullname;<br>
 while(1)<br>
 {</p>
<p>&nbsp;&nbsp; ds-&gt;NextL(c);<br>
&nbsp;&nbsp; if (!c)<br>
&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp;  <br>
&nbsp;&nbsp; for (TInt i=0; i&lt;c-&gt;Count(); i++) <br>
&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp; const TEntry e= (*c)[i];<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <br>
&nbsp;&nbsp;&nbsp; fullname.Copy(ds-&gt;FullPath());<br>
&nbsp;&nbsp;&nbsp; fullname.Append(e.iName);<br>
&nbsp;&nbsp;&nbsp; RLog::Log(fullname);</p>
<p>&nbsp;&nbsp;&nbsp; TParsePtrC p(fullname);<br>
&nbsp;&nbsp;&nbsp; RLog::Log(p.NameAndExt());<br>
<br>
&nbsp;&nbsp; }<br>
&nbsp;&nbsp; delete c;<br>
&nbsp;&nbsp; c=NULL;<br>
 }<br>
  <br>
 CleanupStack::PopAndDestroy(ds);</p>
<p>}<br>
 </p>
<p>使用这个函数就可以更多地了解<strong style="color: black; background-color: rgb(255, 255, 102);">symbian</strong>的文件系统了</p> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/category/Symbian%20Os%20S60">Symbian Os S60</a>&nbsp;<a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/item/4b9c531cb29be98d87d6b68e.html#comment">查看评论</a>]]></description>
        <pubDate>2008-08-11  10:05</pubDate>
        <category><![CDATA[Symbian Os S60]]></category>
        <author><![CDATA[c_linuxsymbian]]></author>
		<guid>http://hi.baidu.com/c%5Flinuxsymbian/blog/item/4b9c531cb29be98d87d6b68e.html</guid>
</item>

<item>
        <title><![CDATA[Symbian清除栈的深入分析]]></title>
        <link><![CDATA[http://hi.baidu.com/c%5Flinuxsymbian/blog/item/922e30160328951e972b433f.html]]></link>
        <description><![CDATA[
		
		<div style="text-indent: 2em;">
<h2 align="center"><font face="宋体">Symbian清除栈的深入分析</font></h2>
<p>从表面看起来清除栈的概念还是很容易理解的，使用起来也是比较方便。市面上关于Symbian的大部分书籍都对Symbian清除栈的使用有详细的介绍。可是，到现在，很少有资料详细涉及Symbian清除栈工作原理。我们接触最多的资料一般是《<font face="宋体">Symbian OS Explained Effective C++ Programming for Smartphones》这本书，但是这本书似乎也是给人一种戛然而止的感觉，使我们只能局限于Symbian应用程序的开发，却不能深入了解Symbian操作系统本身。</font>于是，我想利用业余时间和更多的人一起探讨一下Symbian清除栈的工作原理。当然，<font style="font-size: 24px;">也不仅限于此</font>，后续我还会写更多的文章和大家一起探讨Symbian的核心工作原理，甚至一起对Symbian的<font style="font-size: 24px;">内核进行分析</font>。我希望能够吸引更多的人参与Symbian的学习和研究过程，来共同壮大Symbian开发阵营。</p>
<p>下面我们来探讨Symbian清除栈的工作原理，这是我写的第一篇关于Symbian操作系统工作原理的文章，所以还是有一些表述上的问题，希望大家多多给出意见。另外，也希望读者有一定的Symbian和C++基础，否则还是会影响阅读的。</p>
<p>清除栈实际上是一种半自动的内存回收机制，Symbian为了达到这个目的，做了很多工作，甚至付出了不少代价。与之相关的有清除栈本身的框架、TRAP宏及Leave机制。本文先从Symbian清除栈框架介绍，如果阅读过《<font face="宋体">Symbian OS Explained Effective C++ Programming for Smartphones》这本书的话，可以直接从本文图1以下的位置开始阅读。</font></p>
<h3>1.1.1.&nbsp;&nbsp;  清除栈的框架：</h3>
<p>清除栈保存了在发生异常退出时会被销毁的对象的指针，而这些对象是由TRAP宏来标定为不同的异常退出等级，即TRAP宏是可以嵌套的，每一级嵌套的TRAP宏之内如果发生异常退出，则只有该TRAP宏内推入清除栈的对象才会被销毁，下面的代码说明了这个问题：</p>
<p>CServer2* NewServerL(const TDesC&amp; aServerName)</p>
<p>{</p>
<p>// Install the active scheduler;</p>
<p>&nbsp;&nbsp;&nbsp;  CActiveScheduler* scheduler = new(ELeave) CActiveScheduler;</p>
<p>&nbsp;&nbsp;&nbsp;  CleanupStack::PushL(scheduler);</p>
<p>&nbsp;&nbsp;&nbsp;  CActiveScheduler::Install(scheduler);</p>
<p>&nbsp;&nbsp;&nbsp;   </p>
<p>&nbsp;&nbsp;&nbsp;  CSmallServServer* server = CSmallServServer::NewLC();</p>
<p>&nbsp;&nbsp;&nbsp;  User::LeaveIfError(User::RenameThread(aServerName));</p>
<p>&nbsp;&nbsp;&nbsp;  RProcess::Rendezvous(KErrNone);</p>
<p>&nbsp;&nbsp;&nbsp;  TRAPD(r, server-&gt;StartL(aServerName);</p>
<p>if (r != KErrNone)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  //…</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</p>
<p>&nbsp;&nbsp;&nbsp;  CleanupStack::Pop(2, scheduler);</p>
<p>&nbsp;&nbsp;&nbsp;  return static_cast(server);</p>
<p>&nbsp;&nbsp;&nbsp;  }</p>
<p>&nbsp;&nbsp;&nbsp;</p>
<p>TInt ThreadStart()</p>
<p>&nbsp;&nbsp;&nbsp;  {</p>
<p>&nbsp;&nbsp;&nbsp;  __UHEAP_MARK;</p>
<p>&nbsp;&nbsp;&nbsp;  TInt err = KErrNone;</p>
<p>&nbsp;&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;  // set cleanup stack manually</p>
<p>&nbsp;&nbsp;&nbsp;  CTrapCleanup* cleanup = CTrapCleanup::New();</p>
<p>&nbsp;&nbsp;&nbsp;  CServer2* server = NULL;</p>
<p>&nbsp;&nbsp;&nbsp;  if (cleanup)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  TRAP(err, server = NewServerL(KServer));</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</p>
<p>&nbsp;&nbsp;&nbsp;  else</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  err = KErrNoMemory;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</p>
<p>if (err == KErrNone)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  // start the active Scheduler</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  CActiveScheduler::Start();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  User::InfoPrint(_L(&quot;after&quot;));</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</p>
<p>&nbsp;&nbsp;&nbsp;  delete server;</p>
<p>&nbsp;&nbsp;&nbsp;  delete CActiveScheduler::Current();</p>
<p>&nbsp;&nbsp;&nbsp;  delete cleanup;</p>
<p>&nbsp;&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;  __UHEAP_MARKEND;</p>
<p>&nbsp;&nbsp;&nbsp;  return err;</p>
<p>&nbsp;&nbsp;&nbsp;  }&nbsp;&nbsp;</p>
<p>在NewServerL函数中有TRAP宏存在，如果该宏的中StartL函数发生异常退出，则NewServerL已经推入清除栈的scheduler 和server并不受到任何影响，但如果NewServerL函数中User::LeaveIfError产生异常退出，则已经推入清除栈的 scheduler和server将由清除栈自动析构。</p>
<p>那么清除栈到底如何实现这些功能呢？我们先来看看清除栈的创建过程，在一般的GUI应用程序中，我们通常不关心清除栈的创建，可以直接使用，这是因为 GUI的框架已经为我们创建好了。但有时候我们需要手动创建清除栈，比如创建一个新的非GUI进程，并且这个进程中的主线程必须用到清除栈。因 此，Symbian提供了CTrapCleanup类用于清除栈的初始化。</p>
<p>我们继续从上面代码中来看看清除栈是如何初始化的，可以看出上面这段代码是一个单独的进程启动过程，其中有这样一段代码。</p>
<p>CTrapCleanup* cleanup = CTrapCleanup::New();</p>
<p>…</p>
<p>delete cleanup;</p>
<p>经典的清除栈框架对这段代码的描述是这样，当创建CTrapCleanup类对象的时候，CTrapCleanup::New()中发生以下事件：</p>
<p>1．线程当前的异常处理程序被保存起来。</p>
<p>2．在CTrapCleanup对象中创建一个名为iHandler的TCleanTrapHandler类对象（它持有一个包含实际清除栈实现代码的CCleanup对象）。</p>
<p>3．调用User;;SetTrapHandler()，将TCleanupTrapHanlder对象作为线程中新的异常处理程序。</p>
<p align="center"> </p>
<p align="center"><a target="_blank" href="http://blog.photo.sina.com.cn/showpic.html#url=http://static7.photo.sina.com.cn/orignal/5014f6724417a996d6656"><img height="377" border="0" width="438" src="http://static7.photo.sina.com.cn/bmiddle/5014f6724417a996d6656" style="width: 437px; height: 353px;"></a></p>
<p align="center"><a name="_Ref185686128"></a><a name="_Ref185686151">图</a>1 清除栈结构</p>
<p>当调用CleanupStack::PushL()或CleanupStack::Pop()时，这些静态函数会调用User::TrapHandler()来获取已经安装TCleanupTrapHandler对象，从而可以访问CCleanup对象（见图 1）。正如前面所说，CCleanup对象是实现清除栈代码的核心类，它真正的负责CleanupStack类中静态函数的实现。</p>
<p>现在我们来看CCleanup及其他一些辅助类如何实现清除栈的功能，以CleanupStack类中的三个推入函数为例来逐渐揭开清除栈的真相，这三个函数在Symbian应用开发过程中是再熟悉不过的了，分别是：</p>
<p>IMPORT_C static void PushL(TCleanupItem anItem);</p>
<p>IMPORT_C static void PushL(TAny* aPtr);</p>
<p>IMPORT_C static void PushL(CBase* aPtr);</p>
<p>这三个函数将分别调用CCleanup对象中的以下三个函数：</p>
<p>EXPORT_C void CCleanup::PushL(TCleanupItem anItem)</p>
<p>{</p>
<p>&nbsp;&nbsp;&nbsp;  …// check consistency</p>
<p>&nbsp;&nbsp;&nbsp;  iNext-&gt;Set(anItem);</p>
<p>&nbsp;&nbsp;&nbsp;  iNext++;</p>
<p>&nbsp;&nbsp;&nbsp;  if (iNext + 1 &gt;= iTop)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  …// reallocate memory to cleanup stack</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</p>
<p>&nbsp;&nbsp;&nbsp;  }</p>
<p>EXPORT_C void CCleanup::PushL(TAny* aPtr)</p>
<p>{</p>
<p>&nbsp;&nbsp;&nbsp;  PushL(TCleanupItem(User::Free, aPtr);</p>
<p>&nbsp;&nbsp;&nbsp;  }</p>
<p>EXPORT_C void CCleanup::PushL(CBase* anObject)</p>
<p>{</p>
<p>&nbsp;&nbsp;&nbsp;  PushL(TCleanupItem(TCleanupOperation(doDelete), anObject);</p>
<p>&nbsp;&nbsp;&nbsp;  }</p>
<p>可以看到在CCleanup对象中也有类似的三个PushL重载函数，我们先来看看CCleanup::PushL(TCleanupItem anItem)函数，因为CCleanup::PushL(TAny* aPtr)和CCleanup::PushL(CBase* anObject)在内部实际上也是在调用它。</p>
<p>首先，该函数内部的iNext和iTop是用来控制清除栈指针的，这和数据结构中栈的处理是一样的，我们来看看e32base.h中iNext和iTop的定义：</p>
<p>  //Pointer to the top of the cleanup stack.</p>
<p>  TCleanupStackItem* iTop;</p>
<p>&nbsp;&nbsp; //Pointer to the next availaible slot in the cleanup stack.</p>
<p>&nbsp;&nbsp; TCleanupStackItem* iNext;</p>
<p>请注意注释部分，iNext原来就是指向清除栈的下一个空闲槽，该空闲槽的类定义是TCleanupStackItem，且该类对象的集合组成清除栈。那么CCleanup::PushL(TCleanupItem anItem)函数就是在清除栈中将所传过来的对象放入空闲槽（Set(anItem)）并且&ldquo;推入&rdquo;清除栈（iNext++），即让iNext指向清除栈下一个空闲槽。</p>
<p>现在我们已经知道在Push过程中清除栈是如何被控制的，但是用户所传过来的对象是如何保存的呢，这就需要TCleanupItem类，该类是CCleanup::PushL(TCleanupItem anItem) 函数的参数类型，并且被放入清除栈的空闲槽（Set(anItem)），我们继续从e32base.h寻找TCleanupItem类的定义，很幸运，发现它是这样定义的：</p>
<p>typedef void (*TCleanupOperation)(TAny*);</p>
<p>class TCleanupItem</p>
<p>&nbsp;&nbsp;&nbsp;  {</p>
<p>public:</p>
<p>&nbsp;&nbsp;&nbsp;  inline TCleanupItem(TCleanupOperation anOperation);</p>
<p>&nbsp;&nbsp;&nbsp;  inline TCleanupItem(TCleanupOperation anOperation,TAny* aPtr);</p>
<p>private:</p>
<p>&nbsp;&nbsp;&nbsp;  TCleanupOperation iOperation;</p>
<p>&nbsp;&nbsp;&nbsp;  TAny* iPtr;</p>
<p>&nbsp;&nbsp;&nbsp;  friend class TCleanupStackItem;</p>
<p>&nbsp;&nbsp;&nbsp;  };</p>
<p>原来TCleanupItem将用户要推入清除栈的对象及其销毁处理的方法分别放入iPtr和iOperation函数指针中，在发生异常退出或是CleanupStack::PopAndDestroy就可以将所指向的对象&ldquo;就地处理&rdquo;了（后面还会详细介绍）。</p>
<p>说到这里，对清除栈的Push机制，我们就有了一个比较完整的了解，再来看CCleanup::PushL(TAny* aPtr)就比较容易理解了。该函数将User::Free作为对象销毁的处理方法和对象的指针一起放入TCleanupItem对象并推入清除栈的空闲 槽，在发生异常退出或是CleanupStack::PopAndDestroy时就可以调用User::Free来释放TAny*指向对象的内存空间 了。</p>
<p>同理，CCleanup::PushL(CBase* anObject)函数也是这样处理的，该函数将doDelete函数指针放入TCleanupItem对象并推入清除栈的空闲槽，在发生异常退出或是 CleanupStack::PopAndDestroy时就可以调用doDelete来释放CBase*指向对象的内存空间了。那么doDelete又 是如何处理的呢？有些读者可能已经猜出十之八九。不过，为了表示清楚，还是列出来：</p>
<p>LOCAL_C void doDelete(CBase* aPtr)</p>
<p>&nbsp;&nbsp;&nbsp;  {</p>
<p>&nbsp;&nbsp;&nbsp;  delete aPtr;</p>
<p>&nbsp;&nbsp;&nbsp;  }</p>
<p>原来就是这样简单，因为CBase的析构函数是虚函数，从CBase继承下来的C类，只要简单的delete就可以！</p>
<p>我们再看看CleanupStack::PopAndDestroy()或异常退出时是如何删除清除栈对象的，iNext会调用成员函数Cleanup()，该函数会执行下面一行代码：</p>
<p>(*iOperation)(iPtr);</p>
<p>其中iOperation的定义为</p>
<p>typedef void (*TCleanupOperation)(TAny*);</p>
<p>TCleanupOperation iOperation;</p>
<p>可以看出，iOperation指向的函数被调用，比如说，对于CBase继承下来的C类，就会调用刚讲过的doDelete，对于TAny*就会调用User::Free()来直接释放内存，以此类推。</p>
<h3>1.1.2.&nbsp;&nbsp;  TRAP宏</h3>
<p>这是Symbian SDK中关于TRAP宏的定义：</p>
<p>TRAP(_r,_s){&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \</p>
<p>&nbsp;&nbsp;&nbsp;  TInt&amp; __rref = _r;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   \</p>
<p>&nbsp;&nbsp;&nbsp;  __rref = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>&nbsp;&nbsp;&nbsp;  { TRAP_INSTRUMENTATION_START; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>&nbsp;&nbsp;&nbsp;  try {&nbsp;&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  __WIN32SEHTRAP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp; TTrapHandler* ____t = User::MarkCleanupStack();&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  _s;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  User::UnMarkCleanupStack(____t);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  { TRAP_INSTRUMENTATION_NOLEAVE; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  __WIN32SEHUNTRAP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>&nbsp;&nbsp;&nbsp;  catch (XLeaveException&amp; l)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  __rref = l.GetReason();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  { TRAP_INSTRUMENTATION_LEAVE(__rref); }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>&nbsp;&nbsp;&nbsp;  catch (...)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  User::Invariant();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>&nbsp;&nbsp;&nbsp;  { TRAP_INSTRUMENTATION_END; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>}</p>
<p>这段代码看起来似乎并不重要，但就是这段看似不起眼的代码决定了Symbian整个清除栈及其异常退出的框架。</p>
<p>先来看Symbian是如何实现TRAP嵌套与清除栈挂钩的：</p>
<p>TTrapHandler* ____t = User::MarkCleanupStack();&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>_s;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>User::UnMarkCleanupStack(____t);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>这里User::MarkCleanupStack()实际上还是求助于CCleanup对象的代码实现，它调用CCleanup::NextLevel()函数。</p>
<p>EXPORT_C void CCleanup::NextLevel()</p>
<p>{</p>
<p>…</p>
<p>&nbsp;&nbsp;&nbsp;  iNext-&gt;MarkLevel();</p>
<p>&nbsp;&nbsp;&nbsp;  iNext++;</p>
<p>…</p>
<p>&nbsp;&nbsp;&nbsp;  }</p>
<p>看起来似乎有点让人费解，怎么又在操作iNext？其实，MarkLevel()函数会将iNext指向的下一个清除栈空闲槽 TCleanupStackItem对象设定为一个标记，该标记将不再会放入任何用户推入对象，仅仅作为标记，然后iNext指向再下一个清除栈空闲槽， 于是新的用户推入对象只会放入该标记之上，如图2所示：</p>
<p align="center"> <a target="_blank" href="http://blog.photo.sina.com.cn/showpic.html#url=http://static12.photo.sina.com.cn/orignal/5014f6724417ace3ffe4b"><img height="353" border="0" width="452" src="http://static12.photo.sina.com.cn/bmiddle/5014f6724417ace3ffe4b" style="width: 450px; height: 339px;"></a></p>
<p align="center"><a name="_Ref185686232">图</a>2 TRAP嵌套</p>
<p>同样，User::UnMarkCleanupStack()实际上也是求助于CCleanup对象的代码实现，它调用 CCleanup::PreviousLevel()函数，这个函数就是将iNext减一，位置回退一位并将标志所占空闲槽改为可以推入对象的空闲槽，如 下所示：</p>
<p>EXPORT_C void CCleanup::PreviousLevel()</p>
<p>{</p>
<p>…</p>
<p>&nbsp;&nbsp;&nbsp;  --iNext;</p>
<p>if (!iNext-&gt;IsLevelMarker())</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  Panic(ENotEmpty);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</p>
<p>…</p>
<p>&nbsp;&nbsp;&nbsp;  }</p>
<p>这里有人就要问了，为什么iNext需要判断是否为标记？而且如果不是，竟然会将整个程序Panic！那是什么原因造成这么严重的错误？其实，这就是防止 Symbian开发新手经常犯的错误，即只Push对象进入清除栈却没有及时的将其Pop出清除栈。因此，TRAP宏执行到这里时就会检查清除栈该标记以 上部分是否还有未清除的对象，如果有，就说明有对象忘Pop了，于是整个程序便Panic。需要提醒的是，实际清除栈的代码远比上面描述的要复杂，其中还 有许多问题需要考虑，在此就不一一描述了。</p>
<p>我们再来看Symbian的异常退出（Leave），异常退出机制也是清除栈实现的重要组成部分，经常使用的异常退出函数如下：</p>
<p>IMPORT_C static void Leave(TInt aReason);</p>
<p>IMPORT_C static void LeaveNoMemory();</p>
<p>IMPORT_C static TInt LeaveIfError(TInt aReason);</p>
<p>IMPORT_C static TAny* LeaveIfNull(TAny* aPtr);</p>
<p>这些函数都实现了如下代码：</p>
<p>TTrapHandler* t = GetTrapHandler();</p>
<p>if (t)</p>
<p>t-&gt;Leave(aReason);</p>
<p>throw XLeaveException(aReason);</p>
<p>TTrapHandler对象的Leave函数最终又是求助于CCleanup对象的代码，CCleanup则是这样实现的，即清除该TRAP宏中所有已经推入的用户对象：</p>
<p>while(!(--iNext)-&gt;IsLevelMarker())</p>
<p>&nbsp;&nbsp;&nbsp;  {</p>
<p>&nbsp;&nbsp;&nbsp;  iNext-&gt;Cleanup();</p>
<p>}</p>
<p>可以看到，如果iNext指向的不是标记，则循环进行对象的清除工作。</p>
<p>到此为止，似乎清除栈的相关内容我们已经介绍完了，但还有一些问题需要解释，我们看到在异常退出的那些函数里，有这样一行代码：</p>
<p>throw XLeaveException(aReason);</p>
<p>而在TRAP宏里有这样的catch模块：</p>
<p>catch (XLeaveException&amp; l)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  __rref = l.GetReason();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  { TRAP_INSTRUMENTATION_LEAVE(__rref); }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  \</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }&nbsp;&nbsp;&nbsp;&nbsp;</p>
<p>原来Symbian在实现TRAP和异常退出时，还是使用的标准C++异常机制。那么就有人要问了，为什么不让Symbian应用开发人员使用呢？这可能 有历史遗留方面的原因，但有一个理由很明显，如果让Symbian应用开发人员使用标准C++异常机制，一旦发生标准C++异常，谁来清除清除栈内的对象 呢？显然，不能让开发人员来维护这件事情，而使用TRAP宏就可以在发生异常时强制清除所需要清除的对象。所以，Symbian为清除栈真是费尽了心机 啊。</p>
</div> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/category/Symbian%20Os%20S60">Symbian Os S60</a>&nbsp;<a href="http://hi.baidu.com/c%5Flinuxsymbian/blog/item/922e30160328951e972b433f.html#comment">查看评论</a>]]></description>
        <pubDate>2008-08-07  10:44</pubDate>
        <category><![CDATA[Symbian Os S60]]></category>
        <author><![CDATA[c_linuxsymbian]]></author>
		<guid>http://hi.baidu.com/c%5Flinuxsymbian/blog/item/922e30160328951e972b433f.html</guid>
</item>


</channel>
</rss>