您的位置:首页 > 其它

深入BREW接口机制

2009-03-10 17:20 477 查看
初学Brew时,最烦人的就是接口的定义了,一大堆的宏,让人不知所云。这里,将以helloworld为例,我们一步一步揭开它的神秘面纱。

1.helloworld:

typedef
struct
_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也要初始化。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: