开发 BREW Extension

来源:互联网 发布:美国最高法院 知乎 编辑:程序博客网 时间:2024/05/16 00:44
开发 BREW ExtensionDeveloping the BREW Extension 田海立2006-5-7 摘要BREW Extension。 摘要... 11 BREW概览... 11.1 BREW简介... 11.2 BREW中的几个基本概念... 21.3 BREW模拟开发环境... 22 开发BREW Extension. 32.1 Extension的应用场景... 32.2 文件组成... 42.3 Module Extension 中的关系... 52.4 实现Extension. 62.4.1 类型定义... 62.4.2 AEEClsCreateInstance() 的实现... 72.4.3 构造函数的实现... 83.2.4 SampleExt 对IBase 中方法的实现... 93.2.5 JustSayHello() 方法的实现... 103.2.6 ClinetApp 事件处理... 102.5 执行序列... 11总结... 13参考资料及进一步参考... 13关于作者... 13 1 BREW概览1.1 BREW简介BREW(Binary Runtime Environment for Wireless,即无线二进制运行环境)是QUALCOMM 公司的产品。它以组件(COM)的组织形式封装了底层平台提供给应用开发的服务,屏蔽了底层的实现细节,而提供给应用层统一的API。它所提供的API描述的是Spec而非实现细节,不管今后QUALCOMM的平台技术如何发展,其实现的功能和实现该功能的API规范应该是确定并向后兼容的。BREW上接受的OEM或其他第三方软件厂商提供的最终软件实体是Module的执行体——Win32模拟环境下是 *.dll,真实机器上是 *.mod,这也体现了BREW中的Binary。另外,也可以在BREW运行时从网络上下载BREW所接受的实体,加入到BREW中来运行。1.2 BREW中的几个基本概念BREW中的有Applet和Extension,Applet是一个独立运行(从应用开发角度看)的实体,有Applet Context,简记为ACONTEXT;Extension通过实现它所定义的接口提供服务给Applet或其它Extension,Extension不是独立的运行实体,它运行在调用它的Applet(直接或间接地,当前Extension Ext1的某个服务Ext1::srv可能不是由Applet直接调用,但是调用Ext1::srv的Extension Ext2归根到底还是可以追溯到某个Applet)的ACONTEXT中。Applet和Extension都是被包含在Module里面的,它们之间的关系如图一所示。 图一、BREW中几个概念之间的关系 BREW最终接受的是Module,所以你所提供的Applet和Extension必须在某个Module中;另一方面,一个Module里可以有0…n个Applet或Extension,也可以同时有Applet和Extension,还可以两者都没有,不过两者都没有的Module也没有实际意义。Module的属性和它所包含的Applet和Extension的信息,以及Dependency关系都描述在MIF(Module Information File)文件里,BREW通过该描述文件检索它所需要的信息,并通过相应的Module二进制文件完成相应的操作。 BREW加载Applet或Extension时,首先检查包含它的Module是否已经被加载到内存里,如果还没在内存里,BREW要做的工作是先把该Module加载;接着BREW通过该Module的IMODULE_CreateInstance() 来创建Applet或Extension的一个实例,然后才完成Applet或Extension的真正加载。1.3 BREW模拟开发环境本文所描述的BREW环境和概念都是基于BREW 3.0.1,采用的程序在下面软件环境中调试通过:BREW SDK 3.0.1,包含 API手册 BREW Simulator, MIF Editor, etc. Header files & some src filesMicrosoft Visual studio,包含 Visual studio 6.0 Visual studio 6.0 Service Package 5 Additions BREW Application Wizard BREW Addins for vs60 2 开发BREW Extension有了上面BREW的概念以及开发调试所需的软件环境,下面我们看如何实现一个BREW Extension。BREW中的Extension虽然与Applet是两个概念,但是实现起来却基本相同,不同之处只是在于,Applet必须实现事件处理,而Extension没有这个要求。 2.1 Extension的应用场景假定下面场景:一个Extension SampleExt 通过 Interface ISampleExt 提供服务给它的调用者 ClientApp。ClientApp首先通过 ISHELL_CreateInstance() 创建一个ISampleExt的实例,然后调用该接口实例的方法ISAMPLEEXT_xxx() 通过SampleExt提供的该功能,来实现特定的操作。这里只是通过 SampleExt 的 ISAMPLEEXT_JustSayHello() 来演示如何应用ISampleExt。ISampleExt和SampleExt的定义如图二所示。 图二、ISampleExt和SampleExt 的层次结构 ISampleExt继承了IBase,SampleExt实现了ISampleExt。这里不详细介绍BREW中的COM模型,具体信息参看《BREW COM模型实战》。 有了ISampleExt的接口形式,下面看该Interface的典型应用场景。 图三、SampleExt 的典型应用场景 2.2 文件组成一个Module里可以有Applet,也可以有Extension,我们参照《BREW Applet 框架》中一个Module实现多个Applet那样来组织这个工程。不同之处是把其中一个Applet换成Extension,也就是在 Extension 这个 Module 里实现 ClientApp 和 SampleExt。 在ms vs60环境中通过BREW Application Wizard创建一个 Extension 工程,并把工程的文件组织成图四所示。 图四、Extension工程中的文件 BREW装载Module里的Applet或Extension时,都会通过AEEClsCreateInstance() 函数,完成Applet或Extension的创建,我们可以在这个函数里面做些处理,根据不同的AEECLSID,来创建ClientApp或SampleExt的实例。Factory.c文件中实现AEEClsCreateInstance() 函数,根据不同的AEECLSID,调用各自的构造函数来创建相应的实例。ClientApp.c是Client Applet的对IApplet接口的实现。具体来说就是要实现事件处理函数,以及AddRef() 和Release() 函数,另外还要实现Factory 所引用的构造函数ClientApp_Constructor()。SampleExt.c是SampleExt的实现。具体来说就是要实现ISampleExt中定义的方法,以及 Factory 所引用的构造函数SampleExt_Constructor()。ClientApp.h 定义ClientApp类型。CSampleExt.h 定义接口ISampleExt中的函数,和ISample的各种操作方法的方便店用形式ISAMPLEEXT_xxx(),以及SampleExt类型。 Extension 这个 Module 中要实现一个 Applet 和一个 Extension,所以要把这个Module的描述文件Extension.mif编辑成图五所示。 图五、编辑Extension.mif 2.3 Module Extension 中的关系现在Factory 与 SampleExt和 ClioentApp之间的类图如下: 图六、SampleExt、ClientApp 以及 Factory 之间的关系 图中省略了AEEModGen,我们利用它来实现Module。AEEClsCreateInstance() 是BREW 通过Module 创建 Module 内 Applet 或 Extension 的入口,这里我们把它定义在 Factory 中,它根据参数 ClsId 的值决定调用 ClientApp 还是 SampleExt 的 Constructor。ClientApp 利用 AEEAppGen 实现Applet,并保留对 ISampleExt 的实例的引用。 2.4 实现Extension2.4.1 类型定义定义 ISampleExtISampleExt 继承 IBase,IBase 是 BREW 里所有 Interface 的基接口。在 ISampleExt中只是加入 JustSayHello() 方法。为了给调用者调用方便,定义操作ISampleExt的方法的三个宏 ISAMPLEEXT_AddRef、ISAMPLEEXT_Release 和 ISAMPLEEXT_JustSayHello。 typedef struct _ISampleExt ISampleExt; #define INHERIT_ISampleExt(iname) / INHERIT_IBase(iname); / void (*JustSayHello)(iname*) QINTERFACE(ISampleExt) { INHERIT_ISampleExt(ISampleExt); }; /* These Macroes are provided for Client to Use */ #define ISAMPLEEXT_AddRef(p) / AEEGETPVTBL((p),ISampleExt)->AddRef(p) #define ISAMPLEEXT_Release(p) / AEEGETPVTBL((p),ISampleExt)->Release(p) #define ISAMPLEEXT_JustSayHello(p) / AEEGETPVTBL((p),ISampleExt)->JustSayHello(p)代码片断一、定义ISampleExt 定义 SampleExt对比《BREW Applet 框架》中HelloBREW的定义,成员中没了 AEEApplet 这个Applet的缺省各种结构。由于没了AEEApplet,所以SampleExt中必须自己添加指向虚表的指针 pvt和引用计数m_nRefs。指向虚表的指针 pvt 必须在第一个成员位置,因为BREW默认的各种方法的操作都是基于这个指针指向的实现函数的虚表的。引用计数m_nRefs 是为了使这个组件能够被重复利用而采用计数所需设置的。关于BREW中的组件实现技术,参见《BREW COM的实现》。 typedef struct _SampleExt { // First element of this structure must be pvt AEEVTBL(ISampleExt) *pvt; // Reference Count int m_nRefs; IDisplay *m_pIDisplay; IShell *m_pIShell; IModule *m_pIMod; } SampleExt;代码片断二、定义SampleExt定义 ClientAppClientApp的定义参见《BREW Applet 框架》中Applet的定义,这里不再赘述。 2.4.2 AEEClsCreateInstance() 的实现函数原型为:int AEEClsCreateInstance(AEECLSID ClsId, IShell *pIShell, IModule *po, void **ppObj)函数实现的主体根据不同的AEECLSID,调用 Applet 或 Extension 的构造函数来创建相应的Applet。 switch (ClsId) { case AEECLSID_CLIEBTAPP: return ClientApp_Constructor( ClsId, pIShell, po, (IApplet**)ppObj); case AEECLSID_SAMPLEEXT: return SampleExt_Constructor( ClsId, pIShell, po, (ISampleExt**)ppObj); default: return EFAILED; } return (EFAILED);代码片断三、Factory.c 中 AEEClsCreateInstance() 的实现 2.4.3 构造函数的实现ClientApp 的构造函数如同BREW提供的缺省的 AEEClsCreateInstance() 函数那样,ClientApp 在构造函数 ClientApp_Constructor() 里把事件处理函数ClientApp_HandleEvent() 和程序退出时的清理函数注册到BREW里。 SampleExt 的构造函数如同BREW提供的缺省的 AEEApplet_New () 函数那样,把SampleExt 的构造函数 SampleExt_Constructor() 实现成下面的形式。 SampleExt *pThis = NULL; AEEVTBL(ISampleExt) *pFuncs; int nSize = sizeof (SampleExt) + sizeof (AEEVTBL(ISampleExt)); pThis = (SampleExt*)MALLOC(nSize); *ppObj = pThis; if (pThis == NULL) return ENOMEMORY; pFuncs = (AEEVTBL(ISampleExt) *)((byte*)pThis + sizeof (SampleExt)); pFuncs->AddRef = SampleExt_AddRef; pFuncs->Release = SampleExt_Release; pFuncs->JustSayHello = SampleExt_JustSayHello; INIT_VTBL(pThis, ISampleExt, *pFuncs); pThis->m_nRefs = 1; pThis->m_pIShell = pIShell; pThis->m_pIMod = pIModule; pThis->m_pIDisplay = NULL; ISHELL_CreateInstance(pIShell, AEECLSID_DISPLAY, (void **)&pThis->m_pIDisplay); if (!pThis->m_pIDisplay) { // Cleanup FREE_VTBL(pThis, ISampleExt); FREE(pThis); return (EFAILED) } ISHELL_AddRef(pThis->m_pIShell); if (pThis->m_pIMod) IMODULE_AddRef(pThis->m_pIMod); return (AEE_SUCCESS);代码片断四、SampleExt_Constructor() 的实现 这其中牵涉到BREW中的COM模型,这里暂不解释,详情参见《BREW COM模型实战》。 3.2.4 SampleExt 对IBase 中方法的实现参照BREW提供的缺省的 AEEAppGen 中 AddRef() 和 Release() 函数那样,把SampleExt 中的 IBase 接口的方法实现成下面的形式。 static uint32 SampleExt_AddRef(ISampleExt *pExt) { return ++(((SampleExt *)pExt)->m_nRefs); } static uint32 SampleExt_Release(ISampleExt *pExt) { IShell * pIShell = NULL; SampleExt * pme = (SampleExt *)pExt; if (--pme->m_nRefs) return (pme->m_nRefs); if (pme->m_pIDisplay) IDISPLAY_Release(pme->m_pIDisplay); IMODULE_Release(pme->m_pIMod); pIShell = pme->m_pIShell; // delete this SampleExt object FREE_VTBL(pme, ISampleExt); FREE(pme); ISHELL_Release(pIShell); // Release the Shell return 0; }代码片断五、SampleExt 中 IBase 中方法的实现 3.2.5 JustSayHello() 方法的实现ISAMPLEEXT_JustSayHello() 是由 SampleExt_JustSayHello() 实现的,只是通过在屏幕上输出“Hello Extension”。 static void SampleExt_JustSayHello(ISampleExt *pExt) { AECHAR szText[] = L"Hello Extension"; SampleExt *pThis = (SampleExt *)pExt; IDISPLAY_DrawText(pThis->m_pIDisplay, // Display instance AEE_FONT_BOLD, // Use BOLD font szText, // Text -1, // -1 = Use full string length 0, // Ignored - IDF_ALIGN_CENTER 0, // Ignored - IDF_ALIGN_MIDDLE NULL, // No clipping IDF_ALIGN_CENTER | IDF_ALIGN_MIDDLE); IDISPLAY_Update(pThis->m_pIDisplay); }代码片断六、ISAMPLEEXT_JustSayHello() 方法的实现 3.2.6 ClinetApp 事件处理ClientApp 收到 EVT_APP_START 事件时,通过ISHELL_CreateInstance() 创建 ISampleExt 的一个实例,收到 EVT_APP_STOP 事件时,将该实例销毁。ClientApp 在 Active 状态,点击左软键将通过 JustSayHello 来问候大家。实现如下: int result = EFAILED; switch (eCode) { case EVT_APP_START: result = ISHELL_CreateInstance(pMe->pIShell, AEECLSID_SAMPLEEXT, (void**)&pMe->m_pISampleExt); if (AEE_SUCCESS == result) return (TRUE); return (FALSE); case EVT_APP_STOP: if (NULL != pMe->m_pISampleExt) ISAMPLEEXT_Release(pMe->m_pISampleExt); return (TRUE); case EVT_KEY: switch (wParam) { case AVK_SOFT1: if (NULL != pMe->m_pISampleExt) { ISAMPLEEXT_JustSayHello(pIExt); } break; ... } break; // end of EVT_KEY ... } // switch (eCode)代码片断七、ClientApp 对事件的处理 2.5 执行序列ClientApp 和 SampleExt 实现在一个 Module 中。AEEClsCreateInstance() 是BREW创建Applet 或 Extension的入口,它根据clsId分别调用相应构造函数。在各自的构造函数中,Applet 和 Extension 有机会来初始化自己的数据并注册函数。ClientApp 和 SampleExt 以及 BREW 的之间的执行过程如图七所示。 图七、ClientApp 和 SampleExt 的执行过程 启动 ClientApp 或 SampleExt 之前首先要装载它的Module [序列1]。 装载完成之后,BREW才通过 IMODULE_CreateInstance() 来创建 ClientApp 的实例,IMODULE_CreateInstance() 通过调用 Factory 的 AEEClsCreateInstance() 来实现 [序列 3 ~ 6 ]。 ClientApp 创建并装载完成之后,会收到EVT_APP_START事件,ClientApp收到这个事件之后,用ISHELL_CreateInstance() 创建 ISampleExt 的实例 [序列7 ~ 9]。 因为 SampleExt 所在的 Module 已经被转载进内存,不需要再装载,BREW再次通过 IMODULE_CreateInstance() 来创建 SampleExt 的实例。处理同创建 ClientApp 过程一样,只是这里的 ClsId 变为 AEECLSID_SAMPLEEXT,所以执行 SampleExt_Constructor() [序列10 ~ 14]。 点击左软键,ClientApp 通过ISAMPLEEXT_JustSayHello() 利用 SampleExt 提供的功能来问候 [序列15 ~ 18];因为 SampleExt 运行在 ClientApp 的Applet 上下文(ACONTEXT),所以创建SampleExt的实例和调用它的函数,都不会引起 ClientApp 收到 Suspend 之类的事件。 总结Extension 的实现同 Applet,它给BREW的扩展提供了很好的机制。按照QUALCOMM BREW的扩展规约,你可以开发Extension给别人使用,同时也能使用别人开发的Extension。得益于社区的同时,贡献社区。 参考资料及进一步参考[1] QUALCOMM, BREW API Reference Manual, v3.0.1[2] BREW Applet框架 http://blog.csdn.net/thl789/archive/2006/05/08/712453.aspx[3] Ray Rischpater, Writing BREW Extensions[4] Extension Source Code 关于作者田海立,硕士,国家系统分析师,中国系统分析员协会专业顾问。您可以通过 haili.tian(at)csai.cn 或 tianhaili(at)nju.org.cn 与他联系,到 http://blog.csdn.net/thl789/ 看他最新的文章。 版权声明:◇ 本文为作者原创作品,版权归作者所有。◇ 为了学习和研究,可转载本文,但必须与原文的内容和格式保持一致,并给出原文的原始链接! http://blog.csdn.net/thl789/archive/2006/05/08/713323.aspx Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=713323