深入BREW接口机制

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

1helloworld

typedef struct _helloworld {

       AEEApplet      a ;           //第一个成分必须是 AEEApplet

    AEEDeviceInfo  DeviceInfo; // 设备信息

    IDisplay      *pIDisplay// 显示

    IShell        *pIShell;    //指向Shell

    //加入自己的变量

} helloworld;

 

2AEEApplet

看看, 什么是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

       ……  //其它的变量定义

};

3IApplet

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++中的子类与父类的继承关系。

4AEEApplet_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地址

下面就要对Iappletpvt进行符值,让它指向这一块vtbl啦。

   INIT_VTBL(pme, IApplet, *appFuncs); 

宏展开再看看:

   ((IApplet *)pme)->pvt = (IAppletVtbl *)appFuncs;

5.结论:

由此我们可以看到,在brew中,所谓的接口,不过是一个指针,不同类型的接口的指针指向了不同的的函数指针表,可以理解为C++中的Vtbl

对于某一接口的的实例,它的第一个变量就是指向Vtbl的指针,一般来讲,它的Vtbl表是存在这个类实例的尾端的。在这个类初始化时,必须同时对它的vtbl也要初始化。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值