随心轩
歪酷博客
日 历
网志文件夹
· 所有网志
· 心情日记
· 技术随笔
· 未分类
最 新 的 评 论
搜 索
友 情 链 接
· 歪酷博客
· 管理我的Blog
· Sky of Irene
· 书卷静中缘

订阅 RSS

0031690

歪酷博客

身不沾尘土
心随青云居
用诗词,散文记录我的心路历程
东方欲晓 @ 2005-09-18 22:46

无由岂可话悲伤
自古男儿不弹泪
相思泪泣明月夜
中秋时节不是罪


中秋明月夜
依栏望蟾宫
愿借三千光
照伊一身(生)亮


 
东方欲晓 @ 2005-09-10 21:46

下面是我的网络联系方式
喜欢brew的,可以加

qq 52240523
msn mynicefuture@hotmail.com


 
东方欲晓 @ 2005-08-14 21:52

月去无影画栏阴

东风夜来冷于秋

草木有心可倾诉

西行何处觅芳踪


无绪时作此,亦是境况之写照。

月已下去,画栏没有了影子,显得很凄清,该死的东风却又来了,那种感觉,比秋天还要孤寂。我知道草木是有心的,孤寂的此刻,我可以去找他们倾诉,可是往西的路上,何处才能可以找到我可以倾诉的草木那~




 
东方欲晓 @ 2005-07-16 20:13

实在是抱歉,工作现在实在太忙了,平均一个礼拜70小时以上,我根本没时间来写博客了。在此,向仍然来我博客的xdjm们,说声,谢谢了!!!

如果来我博客是看有关brew方面的东东的,你可以去论坛 http://expert.imobile.com.cn/  其中的brew栏目我也是版主,里面还是满多专题性帖子的~

如果是来看诗词散文的,实在对不起,忙的抽不出时间写。 我想过阵子,稍松一些,一定会常常来写博客了。毕竟,它是我网上的一片世界。大家以后还是多多支持我


 
东方欲晓 @ 2005-06-13 20:52

深入BREW模块加载机制
作者:东方欲晓
2005-6-13
MSN:mynicefuture@hotmail.com
Email: mynicefuture@126.com
转载请注明出处
在BREW中,module是基本的执行单位,一个module可以包含一个或多个applet,或者多个extension class。按照module处于code space(即OEM出厂时已经将module编译进image中了)还是通过下载方式(无线下载或者数据线下载)存于文件系统可以分为static和dynamic,主要包括:dynamic module(applet),static module(applet)和dynamic extension class(module)。本文将详细阐述static和dynamic module的加载过程。由于完整的module加载过程高通没有文档公开,所以以下内容是结合我阅读的相关文档以及我的日常工作而写,是我对模块加载的理解,可能有不当之处,还请指教。
1. Module的信息
MIF文件,这个大家都知道了。原则上来说,每个module都需要有标识自身的MIF文件,从BREW 3.1开始已经强制如此了,static module也需要有相应的MIF。而在BREW3.1之前,对于static module是没有单独的MIF文件的,但有一个AEEAppInfo的结构体来表示module的信息,里面主要包括clsid,app type等信息,每个static module都需要有一个实例化的AEEAppInfo结构体,BREW从此结构中获得必要的module信息。
2. 枚举Module信息
这一步是在BREW环境初始化的时候进行的(猜测是在AEE_init中),由于通常在开机时就初始化BREW环境,所以枚举Module信息通过在一开机就进行(进行程序跟踪结果也证实如此)。对于dynamic module,BREW通过检索各个MIF文件来获得各个module的必要信息,比如clsid等。而对于static module,由于不存在MIF文件,所以过程有所不同。每个static module的实现必须提供一个XXX_getmodinfo(),在该函数中返回特定于该module的Mod_Load()函数指针,通常形式为 XXXMod_Load,同时返回特定于该module的AEEAppInfo结构数据。所有的这些XXX_getmodinfo函数指针构成了一个staticmodinfo的数组。BREW初始化时通过检索该数组(猜测执行其中的每一个函数)来获得每个static module的相关模块信息(比如clsid)以及加载函数(我们知道,对于dynamic module, load的函数是通用的AEEMod_Load,所以应用无需再提供自己的Load函数,而static module必须提供自己的Mod_Load 函数)
3. Module加载
Module的加载是在运行时才进行的,即执行该Module的时候。对于dynamic module,加载是通过通用函数AEEMod_Load实现的,而AEEMod_Load实际是调用AEEStaticMod_New,该函数的原型为int AEEStaticMod_New(int16 nSize, IShell *pIShell, void *ph, IModule **ppMod,                     PFNMODCREATEINST pfnMC,PFNFREEMODDATA pfnMF),大家在AeeModGen.c中可以看到。需要说明的是,AEEMod_Load中调用该函数时,倒数第二个参数为NULL,这说明什么?我们来看看AEEStaticMod_New具体作些什么,

int AEEStaticMod_New(int16 nSize, IShell *pIShell, void *ph, IModule **ppMod,
                    PFNMODCREATEINST pfnMC,PFNFREEMODDATA pfnMF)
{
  AEEMod *pMe = NULL;
  VTBL(IModule) *modFuncs;

  if (!ppMod || !pIShell) {
     return EFAILED;
  }

  *ppMod = NULL;
 
#ifdef AEE_SIMULATOR
  // IMPORTANT NOTE: g_pvtAEEStdLibEntry global variable is defined for
  //   SDK ONLY! This variable should NOT BE:
  //
  //      (1) overwritten
  //      (2) USED DIRECTLY by BREW SDK users.
  //
  //  g_pvtAEEStdLibEntry is used as an entry point to AEEStdLib,
  //   DO NOT REMOVE the next five lines.
  if (!ph) {
     return EFAILED;
  } else {
     g_pvtAEEStdLibEntry = (AEEHelperFuncs *)ph;
  }
#endif

  //Allocate memory for the AEEMod object

  if (nSize < sizeof(AEEMod)) {
     nSize += sizeof(AEEMod);
  }

  if (NULL == (pMe = (AEEMod *)MALLOC(nSize + sizeof(IModuleVtbl)))) {
     return ENOMEMORY;
  }
 
  // Allocate the vtbl and initialize it. Note that the modules and apps
  // must not have any static data. Hence, we need to allocate the vtbl as
  // well.

  modFuncs = (IModuleVtbl *)((byte *)pMe + nSize);

  // Initialize individual entries in the VTBL
  modFuncs->AddRef         = AEEMod_AddRef;
  modFuncs->Release        = AEEMod_Release;
  modFuncs->CreateInstance = AEEMod_CreateInstance;
  modFuncs->FreeResources  = AEEMod_FreeResources;


  // initialize the vtable
  INIT_VTBL(pMe, IModule, *modFuncs);

  // initialize the data members

  // Store address of Module's CreateInstance function
  pMe->pfnModCrInst = pfnMC;

  // Store Address of Module's FreeData function
  pMe->pfnModFreeData = pfnMF;

  pMe->m_nRefs = 1;
  pMe->m_pIShell = pIShell;

  // Set the pointer in the parameter
  *ppMod = (IModule*)pMe;

  return SUCCESS;

上述代码在sdk中的AeeModGen.c可以找到,概括起来,就是在为module分配内存,并且实例化vtbl表,其中有两行代码值得注意:
modFuncs->CreateInstance = AEEMod_CreateInstance;
pMe->pfnModCrInst = pfnMC;

第一行是指定module的创建函数为AEEMod_CreateInstance,而第二行是指定该module具有自身特殊的创建函数,该函数即为参数pfnMC指定的函数。而在AEEMod_Load中调用AEEStaticMod_New时该参数为NULL,即所有dynamic module采用通用的createinstance 函数(该函数实际上即为AEEClsCreateInstance)
大家或许已经猜到了,对于static module,其实其自身的XXXMod_Load加载函数和通用的AEEMod_Load具体实现几乎一样,最主要的区别在于其调用AEEStaticMod_New时指定了pfnMC参数,即static module需要指定自身的createinstance函数。
4. Module 创建
这是通过 在AEEStaticMod_New中代码
modFuncs->CreateInstance = AEEMod_CreateInstance;指定的
AEEMod_CreateInstance函数来创建的。我们来看一下AEEMod_CreateInstance的庐山真面目:
static int AEEMod_CreateInstance(IModule *pIModule,IShell *pIShell,
                                AEECLSID ClsId,void **ppObj)
{
  AEEMod    *pme = (AEEMod *)pIModule;
  int        nErr = 0;

  // For a dynamic module, they must supply the AEEClsCreateInstance()
  //   function. Hence, invoke it. For a static app, they will have
  //   registered the create Instance function. Invoke it.
  if (pme->pfnModCrInst) {
     nErr = pme->pfnModCrInst(ClsId, pIShell, pIModule, ppObj);
#if !defined(AEE_STATIC)
  } else {
     nErr = AEEClsCreateInstance(ClsId, pIShell, pIModule, ppObj);
#endif
  }

  return nErr;
}

可见对于dynamic module,由于pme->pfnModCrInst为NULL,所以调用通用的创建函数AEEClsCreateInstance(ClsId, pIShell, pIModule, ppObj)来进行创建。而对于static module,因为指定了自身的Createinstance函数,所以pme->pfnModCrInst不为NULL,从而执行特定于该module自身的createinstance函数
5. Applet创建
之后,不管是 AEEClsCreateInstance还是pme->pfnModCrInst其实都是类似的,通过AEEApplet_New(除extension class外通常都是调用该函数)来最终创建applet,AEEApplet_New无非是具体分配applet内存,初始化applet的vtbl(这里最重要的是实例化applet_handleevent)并返回Iapplet指针,供运行时使用
6. 程序运行
通常就是在applet_handleevent中进行各种事件处理。处理前一般将传入的Iapplet指针先转换为AEEApplet或者用户自身的结构,以便可以访问其中的数据变量。

以上就是我对BREW模块加载机制的理解。大家相互交流


 
东方欲晓 @ 2005-06-08 22:17

                                           深入BREW消息处理机制(原创)
                                                 作者:东方欲晓
                                                        2005-6-8
                                           msn:mynicefuture@hotmail.com
                                               email: mynicefuture@126.com
                                       留言:希望从中能加深你对BREW消息机制的了解
                                               (转载请注明出处)


   消息处理机制,即event driven和传统的编程机制不同,如dos,unix下的c编程,他没有main loop,程序的流程不是顺序执行的。有过window编程经历的读者都会清楚这种机制。
   Windows下消息处理机制:当在交互中进行一个action(or signal, or input, etc),window产生相应的event,通过window的event dispatch机制,相应的窗口或者app得到该event,从而触发相应的 event handler fun进行处理。
   BREW下消息处理机制简而言之也相似,即BREW环境(这里是AEE Shell)捕捉到event后,dispatch到相应的app或者control,由其event handler fun处理。
   区别:我们知道BREW的体系结构采用了COM方式,即具有面向对象的类层次结构,从而其具体的event handler fun也是作为各个Interface的外露的接口函数的形式被运用。一个applet本质上来说就是一个实例化的IAPPLET类,所以这样就统一了所有在applet中运用的event handler fun都是各个Interface的外露接口函数的说法。
   具体而言,这些event handler fun还是有区别的,主要是IAPPLET_Handleevent和其他Interface的Handleevent的区别。
   IAPPLET_Handleevent是通过在AEEClsCreateInstance中的AEEApplet_New函数被注册实例化的,AEEApplet_New函数实例化用户的APPLET的Class同时也通过传入USERAPP_HandleEvent参数实例化了IAPPLET_Handleevent。
   除了IAPPLET具有handleevent外,所有的继承Icontrol接口的Interface也具有事件处理函数,允许处理事件。这些各种具体的Icontrol_handleevent有两种方式被调用。一种是在applet的handleevent中由programmer显式的调用,如:
switch (eCode)
{
     case EVT_APP_START:                            
 ………
      return(TRUE);
     case EVT_APP_STOP:    
……….
         Case EVT_KEY:
IMENU_Handleevent….
ItextCtl_Handleevent….
另一种是当这些Control包含于Dialog中,且处于focus状态时,这些事件处理函数的触发是隐式的,是由AEE机制自动触发的,无需在代码中显式的调用这些handleevent。
Idialog接口没有外露的handleevent接口函数,但是允许通过Idialog_seteventhandle来注册一个该Dialog的事件处理函数。需要注意的是,该事件处理函数是何时被触发的:一旦当一个dialog处于active时,aee shell将会把所有的event直接发往该dialog,该dialog会自动的调用处于focus的control的handleevent来处理该事件,只有当该control没有处理该事件时,dialog注册的事件处理函数才会被调用。
Brew中的handle event函数都是boolean返回类型的,这是为了实现事件处理的层次机制,当该层上的handle event没有处理该事件时,应该返回false,以便上层对该事件感兴趣的handle event来处理。 如果处理了,应该返回TRUE,说明该事件已被处理,无需其他层再处理。
有了以上知识后,下面给出完整的BREW环境下消息分发和处理的流程。
首先BREW存在于一个task中,尽管允许brew运行于一个单独的task中,但是实际oem中都是将其运行于现有的一个task中,比如ui task。
当brew运行后,首先ui task中捕捉到各种事件,此时ui task通过aee_dispatch将事件分发至brew环境中,brew环境再通过aee_sentevent具体分发事件至目的地。接着在两种不同的情况下将走不同的流程。
   如果当前没有active dialog,则紧接着IAPPLET_Handleevent被brew自动调用来处理事件,而此时调用的IAPPLET_Handleevent其实就是用户注册的自己的applet_handleevent。从而实现了允许用户app捕捉到事件并处理的机制。在用户的app handleevent中,用户可以将事件继续下发,比如通过调用IMENU_handleevent等将事件下发给各种控件处理。
   如果当前有active dialog,则紧接着Adialog_event被brew自动调用,从而使得事件被dialog最先截获,而dialog之后的处理是检查包含的控件中哪个处于focus,并将事件下发给它的handleevent来处理,同时根据其返回值来判断其是否已经处理了该事件,当其返回False后,dialog将该事件继续转发至该dialog注册的handleevent(如果有的话),如果该handleevent仍然返回false,brew继续将该事件转发至app handleevent。这种机制使得当以dialog方式来创建应用时,各种event被自动的处理,从而简化了代码量,但也使得事件流程更加晦涩,用户的程序不能直接的控制它。
   最后,结合一个我工作中的问题,来加深对brew事件处理机制的理解。
   这是一个关于输入法的问题,当在textctl中进行输入时,如果是拼音和笔画输入时,情况比较复杂,大致如下:
   app handleevent调用itextctl_handleevent来处理按键事件,itextctl_handleevent的oem实现中最后会创建一个拼音dialog(pinyindlg)用来显示输入的拼音和候选字,同时注册一个dialoghandler(pinyindlgevent), pinyindlg中包含一个control(ipinyinmanager),它的handleevent(ipinyinmanager_handleevent)主要来处理用户拼音输入时如何显示候选字等等一系列的复杂任务。
这样的话,当处于拼音输入模式时,输入第一个字母后,就创建了pinyindlg来显示候选字,同时ipinyinmanager_handleevent被激活,之后按的任何键都会直接调用该ipinyinmanager_handleevent来处理,且该handleevent均返回true,表示正确处理了。
   如此,则所有按键事件将均被ipinyinmanager_handleevent截获,app,以及itextctl均没有机会处理事件。那如何退回到text控制之下那?以便进行其他操作,比如删除,切换,保存等。
这是通过在ipinyinmanager_handleevent中对特殊的键进行特殊处理来实现的,比如定义clr为退回至text控制,则在ipinyinmanager_handleevent中当key为avk_CLR时,return false,从而使得pinyindlg注册的pinyindlgevent有机会被调用,而在这个handleevent中release pinyindlg,并且返回true。这样就release了dlg,从而使得下次的按键可被app捕获,由app handleevent 传给itextctl_handleevent,从而成功的使得event处理的焦点回到了itextctl。这里return true是为了避免同时删除最后一个汉字(false使得itextctl_handleevent再次处理该clr,就会删除一个汉字)。
   我们知道,应用可以设置maxchars来限制text中输入的最大字符数。当输入为字母,数字,符号时没有问题。但是当输入为拼音时,当达到最大输入数时会出现一种情况,就是不能输入进text了,但是拼音dlg继续存在,且随着不断的按键继续有不断的响应(比如候选字不断变化等)。这是由于oem层当输入达到最大值时的处理是,仅仅不往text buffer中存入字符而并没有实现:release掉pinyindlg,回到text 控制下,不响应用户任何输入这些功能。
   如何解决这个问题那?当对brew事件处理机制很熟悉的话,问题就迎刃而解了。只需要当输入达最大数时的同时将event处理控制权释放即可,这样下次事件处理将重新由app捕获,并传给itextctl,而在itextctl的handleevent的oem实现中进行判断,当已达最大输入时,不作任何响应。具体如下:
ipinyinmanager_handleevent中有对select事件进行处理,主要就是add char到text中,我们在add char这个处理之后,加入对最大输入数是否已到的判断,如果最大数已到,则直接return false 释放event handle的控制权。之后,pinyindlg注册的pinyindlgevent会继续处理这个事件(即select键),在这个eventhandle中release掉pinyindlg,使其不再显示,同时返回true(这是为了让该事件select不再传至app,否则app可能采取保存等操作)。这样下次按键将顺利被传至itextctl_handleevent,在该handleevent的oem实现中,我们加入对输入最大数的判断,如果已达最大数,则不作任何响应,同时返回true(对程序而已,的确是作出了响应:))。 这样就达到了当拼音输入达最大数的同时自动隐去拼音框,之后再按任何键无响应的合理效果。
   以上是我一段时间工作后的心得体会,可能有不当之处,大家相互交流。


 



 
东方欲晓 @ 2005-06-07 22:21

工作了一段时间,感觉有很多技术的东西想写下来的冲动,也算作和同道中人交流交流吧:)
现在主要打算写一些关于brew和嵌入式编程方面的心得体会.
brew的资料网上还是比较少,我将从brew-oem的角度经常写些平时工作中的心得体会,希望大家互相交流.

近期的初步打算是写以下内容:

我对brew的event handler机制的理解(结合一个工作中的实际问题)
brew的面向对象机制(com style以及class机制详细说明)
brew中static extention class, dynamic extention class, static module(applet),dynamic module(applet)的创建过程介绍与比较
对做好brew-oem工作的看法
用纯c实现面向对象机制介绍


 
东方欲晓 @ 2005-06-02 19:58

君欲扬帆去
从此千山隔
遥寄蟾娥语
夜夜照平安


 
东方欲晓 @ 2005-06-02 19:54

此处一别后
天涯遍足迹
他日雁归时
芬芳铺满地


 
东方欲晓 @ 2005-05-26 23:46

留春且住,
留人不住,
留得奈何?!

饮一杯酒,
三分滴泪,
七分滴心!!