深入BREW接口机制
2009-03-10 17:20
477 查看
初学Brew时,最烦人的就是接口的定义了,一大堆的宏,让人不知所云。这里,将以helloworld为例,我们一步一步揭开它的神秘面纱。
struct
_helloworld
{
AEEApplet a ;
//第一个成分必须是
AEEApplet
AEEDeviceInfo DeviceInfo;
// 设备信息
IDisplay *pIDisplay; // 显示
IShell *pIShell; //指向Shell
//加入自己的变量
} helloworld;
typedef
struct
_AEEApplet
AEEApplet;
struct
_AEEApplet
{
DECLARE_VTBL(IApplet)
AEECLSID clsID;
uint32 m_nRefs; // Applet
reference counter
……
//其它的变量定义
};
DECLARE_VTBL(IApplet)又是什么?
它的宏定义为:
#define DECLARE_VTBL(iname) iname
vt##iname;
解开后为
struct
_AEEApplet
{
IApplet vtApplet;
//定义了一个接口
AEECLSID clsID;
uint32 m_nRefs; // Applet
reference counter
…… //其它的变量定义
};
在AEE.h中找到如下代码:
typedef
struct
_IApplet IApplet;
#define INHERIT_IApplet(iname)
/
INHERIT_IBase(iname);
/
boolean (*HandleEvent)(iname
* po,
AEEEvent
evt,
uint16
wp,
uint32
dwp)
QINTERFACE(IApplet)
{
INHERIT_IApplet(IApplet);
};
#define IAPPLET_AddRef(p) GET_PVTBL(p,IApplet)->AddRef(p)
#define IAPPLET_Release(p) GET_PVTBL(p,IApplet)->Release(p)
还是看看解开后是什么吧:
struct _IApplet {
struct IAppletVtbl *pvt;
};
typedef struct IAppletVtbl IAppletVtbl;
struct IAppletVtbl
{
uint32 (*AddRef) (IApplet*);
uint32 (*Release) (IApplet*);
boolean (*HandleEvent)(IApplet * po, uint16
evt, uint16 wp, uint32 dwp);
};
至于宏定义
#define IAPPLET_AddRef(p) GET_PVTBL(p,IApplet)->AddRef(p)
展开来后则成了:
#define IAPPLET_AddRef(p) (IApplet
*)p->pvt->AddRef(p)
我们看到IApplet的定义中,只有一个变量,是一个指向vbtl的指针,名字为pvt,这就解释了为什么我们的Applet也会有一个pvt指针啦。
因为helloworld的第一个变量为IApplet类型的,当我们对helloworld时行向上转型到IApplet时,我们就可以使用IApplet类型中定义的成员变量。可以理解成C++中的子类与父类的继承关系。
在分配Applet内存时,分配的并不仅仅是helloworld结构内存的大小,而是helloworld结构大小再加上IappletVtbl的大小。
(AEEApplet*)MALLOC(nSize +
sizeof(IAppletVtbl))
从前面的定义我们知道,IAppletVtbl实际是一组函数指针,给vtbl分配了内存后,就要对它进行初始化,让它指向实际的函数地址。这样才可以通过我们前面的宏定义来执行实际的函数:
如#define
IAPPLET_AddRef(p) (IApplet
*)p->pvt->AddRef(p)
这一段代码如下:
appFuncs =
(IAppletVtbl
*)((byte
*)pme +
nSize);//让appFuns指向实际分配的内存块
//Initialize the
individual entries in the VTBL
appFuncs->AddRef = AEEApplet_AddRef;
//实际的AddRef函数地址
appFuncs->Release = AEEApplet_Release;//实际的Release函数地址
appFuncs->HandleEvent =
AEEApplet_HandleEvent;//实际的HandleEvent地址
下面就要对Iapplet的pvt进行符值,让它指向这一块vtbl啦。
INIT_VTBL(pme,
IApplet,
*appFuncs);
宏展开再看看:
((IApplet *)pme)->pvt = (IAppletVtbl
*)appFuncs;
对于某一接口的的实例,它的第一个变量就是指向Vtbl的指针,一般来讲,它的Vtbl表是存在这个类实例的尾端的。在这个类初始化时,必须同时对它的vtbl也要初始化。
1.helloworld:
typedefstruct
_helloworld
{
AEEApplet a ;
//第一个成分必须是
AEEApplet
AEEDeviceInfo DeviceInfo;
// 设备信息
IDisplay *pIDisplay; // 显示
IShell *pIShell; //指向Shell
//加入自己的变量
} helloworld;
2.AEEApplet
看看, 什么是AEEApplet呢?typedef
struct
_AEEApplet
AEEApplet;
struct
_AEEApplet
{
DECLARE_VTBL(IApplet)
AEECLSID clsID;
uint32 m_nRefs; // Applet
reference counter
……
//其它的变量定义
};
DECLARE_VTBL(IApplet)又是什么?
它的宏定义为:
#define DECLARE_VTBL(iname) iname
vt##iname;
解开后为
struct
_AEEApplet
{
IApplet vtApplet;
//定义了一个接口
AEECLSID clsID;
uint32 m_nRefs; // Applet
reference counter
…… //其它的变量定义
};
3.IApplet
IApplet又是什么东东呢? 这个比较难找。在AEE.h中找到如下代码:
typedef
struct
_IApplet IApplet;
#define INHERIT_IApplet(iname)
/
INHERIT_IBase(iname);
/
boolean (*HandleEvent)(iname
* po,
AEEEvent
evt,
uint16
wp,
uint32
dwp)
QINTERFACE(IApplet)
{
INHERIT_IApplet(IApplet);
};
#define IAPPLET_AddRef(p) GET_PVTBL(p,IApplet)->AddRef(p)
#define IAPPLET_Release(p) GET_PVTBL(p,IApplet)->Release(p)
还是看看解开后是什么吧:
struct _IApplet {
struct IAppletVtbl *pvt;
};
typedef struct IAppletVtbl IAppletVtbl;
struct IAppletVtbl
{
uint32 (*AddRef) (IApplet*);
uint32 (*Release) (IApplet*);
boolean (*HandleEvent)(IApplet * po, uint16
evt, uint16 wp, uint32 dwp);
};
至于宏定义
#define IAPPLET_AddRef(p) GET_PVTBL(p,IApplet)->AddRef(p)
展开来后则成了:
#define IAPPLET_AddRef(p) (IApplet
*)p->pvt->AddRef(p)
我们看到IApplet的定义中,只有一个变量,是一个指向vbtl的指针,名字为pvt,这就解释了为什么我们的Applet也会有一个pvt指针啦。
因为helloworld的第一个变量为IApplet类型的,当我们对helloworld时行向上转型到IApplet时,我们就可以使用IApplet类型中定义的成员变量。可以理解成C++中的子类与父类的继承关系。
4.AEEApplet_New
再回到AEEAppGen.c中,我们就能更好的理解AEEApplet_New的思想了。在分配Applet内存时,分配的并不仅仅是helloworld结构内存的大小,而是helloworld结构大小再加上IappletVtbl的大小。
(AEEApplet*)MALLOC(nSize +
sizeof(IAppletVtbl))
从前面的定义我们知道,IAppletVtbl实际是一组函数指针,给vtbl分配了内存后,就要对它进行初始化,让它指向实际的函数地址。这样才可以通过我们前面的宏定义来执行实际的函数:
如#define
IAPPLET_AddRef(p) (IApplet
*)p->pvt->AddRef(p)
这一段代码如下:
appFuncs =
(IAppletVtbl
*)((byte
*)pme +
nSize);//让appFuns指向实际分配的内存块
//Initialize the
individual entries in the VTBL
appFuncs->AddRef = AEEApplet_AddRef;
//实际的AddRef函数地址
appFuncs->Release = AEEApplet_Release;//实际的Release函数地址
appFuncs->HandleEvent =
AEEApplet_HandleEvent;//实际的HandleEvent地址
下面就要对Iapplet的pvt进行符值,让它指向这一块vtbl啦。
INIT_VTBL(pme,
IApplet,
*appFuncs);
宏展开再看看:
((IApplet *)pme)->pvt = (IAppletVtbl
*)appFuncs;
5.结论:
由此我们可以看到,在brew中,所谓的接口,不过是一个指针,不同类型的接口的指针指向了不同的的函数指针表,可以理解为C++中的Vtbl。对于某一接口的的实例,它的第一个变量就是指向Vtbl的指针,一般来讲,它的Vtbl表是存在这个类实例的尾端的。在这个类初始化时,必须同时对它的vtbl也要初始化。
相关文章推荐
- [深入分析BREW机制]:动手写BREW扩展接口
- [深入分析BREW机制]:BREW接口的继承特性应用
- [收录]深入BREW抽象接口机制
- [深入分析BREW机制]:BREW接口的引用计数机制
- 深入BREW消息处理机制
- 深入BREW消息处理机制
- [深入分析BREW机制]:Mod相关概念解析
- 忆龙2009:深入BREW模块加载机制
- [转]深入BREW消息处理机制
- [收录]深入BREW消息处理机制
- 忆龙2009:深入BREW消息处理机制
- [收录]深入BREW模块加载机制
- 忆龙2009:深入BREW消息处理机制
- brew 中的接口机制
- [深入分析BREW机制]:BREW的类机制
- 深入浅析Android接口回调机制
- 深入理解Android之接口回调机制
- [深入分析BREW机制]:applet的类特征
- 【摘录】深入BREW消息处理机制
- 忆龙2009:深入BREW模块加载机制