Brew中的Module的实现方法:
我们从AEEModGen.c中提供的用于创建Module对象的对外接口入手,函数如下:
01int AEEStaticMod_New(int16 nSize, IShell *pIShell, void *ph, IModule **ppMod,
02 PFNMODCreateINST pfnMC,PFNFREEMODDATA pfnMF)
03{
04 AEEMod *pMe = NULL;
05 VTBL(IModule) *modFuncs;
……………省略第6到73行的代码…………………
74}
第4行申请AEEMod结构体类型的pMe指针,该结构体的定义如下:
01//Structure that implements the IModule interface
02typedef struct _AEEMod
03{
04 DECLARE_VTBL(IModule) // Virtual Table with pointers to IModule functions
05
06 uint32 m_nRefs; // Reference count for this module
07 IShell * m_pIShell; // Pointer to IShell
08
09 //Address of CreateInstance function of the module. This is needed for
10 // static modules
11 PFNMODCreateINST pfnModCrInst;
12
13 //Address of the function to free the module data. This is needed for static
14 // modules that define their own data.
15 PFNFREEMODDATA pfnModFreeData;
16
17} AEEMod;
在该结构体的第4行,声明了一个Virtual Table(虚拟表:专门用来来存放函数指针的结构体,不过此处是指向该结构体的指针),这个是重点,待会将展开来讲。第6行的m_nRefs是模仿COM中的计数器,第11行和第15行的两个函数指针成员,其中pfnModCrInst是用来存放创建Module本身的函数(地址),而pfnModFreeData是Module自身提供释放自身数据的函数指针。
下面我们将结构体中的第四行DECLARE_VTBL(IModule)展开:
先来看看DECLARE_VTBL的定义:
1// Use as first member of classes that override QINTERFACE()
2#define DECLARE_VTBL(iname) iname vt##iname;
所以DECLARE_VTBL(IModule)就是: IModule vtIModule;
IModule是一个结构体类型,定义如下:
1typedef struct _IModule IModule;
所以,我们需要了解_IModule的结构体是什么样子的。我们需要从下面的四行代码入手,不过下面主要是两个宏定义,需要展开才能够明白它们到底是什么东西。
1QINTERFACE(IModule)
2{
3 INHERIT_IModule(IModule);
4};
下面是所有相关的宏定义,先贴出来,然后再用这些定义将上面的4行慢慢展开:
01typedef struct _IModule IModule;
02#define INHERIT_IModule(iname) \
03 INHERIT_IBase(iname); \
04 int (*CreateInstance)(iname * po,IShell * pIShell,AEECLSID ClsId,void ** ppObj); \
05 void (*FreeResources)(iname * po, IHeap * ph, IFileMgr * pfm)
06
07QINTERFACE(IModule)
08{
09 INHERIT_IModule(IModule);
10};
11#define IMODULE_AddRef(p) GET_PVTBL(p,IModule)->AddRef(p)
12#define IMODULE_Release(p) GET_PVTBL(p,IModule)->Release(p)
13#define IMODULE_CreateInstance(p,ps,id,ppo) GET_PVTBL(p,IModule)->CreateInstance(p,ps,id,ppo)
14#define IMODULE_FreeResources(p,ph,pfm) GET_PVTBL(p,IModule)->FreeResources(p,ph,pfm)
15
16#define QINTERFACE(iname) struct _##iname {\
17 struct VTBL(iname) *pvt;\
18 };\
19 typedef struct VTBL(iname) VTBL(iname);\
20 struct VTBL(iname)
21
22#define VTBL(iname) iname##Vtbl
23
24#define INHERIT_IBase(iname) \
25 uint32 (*AddRef) (iname*);\
26 uint32 (*Release) (iname*)
先将QINTERFACE(IModule)展开,根据上面第16到20行的定义以及第22行VTBL的定义,得到:
1struct _IModule {
2 struct IModuleVtbl *pvt;
3 };
4 typedef struct IModuleVtbl IModuleVtbl;
5 struct IModuleVtbl
再将INHERIT_IModule(IModule);展开,根据上面第2到5行的定义以及第24到26行INHERIT_IBase的定义,得到:
1 uint32 (*AddRef) (IModule*);
2 uint32 (*Release) (IModule*);
3 int (*CreateInstance)(IModule * po,IShell * pIShell,AEECLSID ClsId,void ** ppObj);
4 void (*FreeResources)(IModule * po, IHeap * ph, IFileMgr * pfm);
将以上结果合并起来,就可以得到如下代码:
01struct _IModule
02{
03 struct IModuleVtbl *pvt;
04};
05typedef struct IModuleVtbl IModuleVtbl;
06struct IModuleVtbl
07{
08 uint32 (*AddRef) (IModule*);
09 uint32 (*Release) (IModule*);
10 int (*CreateInstance)(IModule * po,IShell * pIShell,AEECLSID ClsId,void ** ppObj);
11 void (*FreeResources)(IModule * po, IHeap * ph, IFileMgr * pfm);
12};
好,现在来总结一下:
前面已经说到DECLARE_VTBL(IModule)就是: IModule vtIModule;,它作为AEEMod结构体的第一个成员。IModule是_IModule的结构体类型,_IModule结构体只有一个成员,就是结构体IModuleVtbl的指针。而IModuleVtbl指向的是虚拟函数表的首地址,所以如果有一个IModule* p的指针,p->pvt就是IModuleVtbl*的类型,再用p->pvt->functionName找到对应的函数。为了方便,虚拟函数表中函数的调用是使用宏来定义的,从结构体IModuleVtbl中我们可以看到Module提供了四种方法,宏定义如下,其中还用到GET_PVTBL宏定义:
1#define IMODULE_AddRef(p) GET_PVTBL(p,IModule)->AddRef(p)
2#define IMODULE_Release(p) GET_PVTBL(p,IModule)->Release(p)
3#define IMODULE_CreateInstance(p,ps,id,ppo) GET_PVTBL(p,IModule)->CreateInstance(p,ps,id,ppo)
4#define IMODULE_FreeResources(p,ph,pfm) GET_PVTBL(p,IModule)->FreeResources(p,ph,pfm)
5#define GET_PVTBL(p,iname) ((iname*)p)->pvt
我们以AddRef函数为例,我们调用的时候会使用"IMODULE_AddRef(p);"语句,将其展开,其实就是:
((IModule*)p)->pvt->AddRef(p);
这样就实现了虚拟函数表中函数的调用了。
下面再回到用于创建Module对象的对外接口AEEStaticMod_New,具体代码如下:
01int AEEStaticMod_New
(int16 nSize
, IShell
*pIShell
, void *ph
, IModule
**ppMod
,02 PFNMODCreateINST pfnMC
,PFNFREEMODDATA pfnMF
)03{04 AEEMod
*pMe
= NULL
;05 VTBL
(IModule
) *modFuncs
; //将其展开就是 IModuleVtbl *modFuncs;
0607 if (!ppMod
|| !pIShell
) {08 return EFAILED
;09 }1011 if (nSize
< 0) {12 return EBADPARM
;13 }14 *ppMod
= NULL
;15 16#ifdef AEE_SIMULATOR
17 // IMPORTANT NOTE: g_pvtAEEStdLibEntry global variable is defined for
18 // SDK ONLY! This variable should NOT BE:
19 //
20 // (1) overwritten
21 // (2) USED DIRECTLY by BREW SDK users.
22 //
23 // g_pvtAEEStdLibEntry is used as an entry point to AEEStdLib,
24 // DO NOT REMOVE the next five lines.
25 if (!ph
) {26 return EFAILED
;27 } else {28 g_pvtAEEStdLibEntry
= (AEEHelperFuncs
*)ph
;29 }30#endif3132 //Allocate memory for the AEEMod object
3334 if (nSize
< sizeof(AEEMod
)) {35 nSize
+= sizeof(AEEMod
);36 }3738 if (NULL
== (pMe
= (AEEMod
*)MALLOC
(nSize
+ sizeof(IModuleVtbl
)))) {39 return ENOMEMORY
;40 }41 42 // Allocate the vtbl and initialize it. Note that the modules and apps
43 // must not have any static data. Hence, we need to allocate the vtbl as
44 // well.
4546 modFuncs
= (IModuleVtbl
*)((byte
*)pMe
+ nSize
);4748 // Initialize individual entries in the VTBL
49 modFuncs
->AddRef
= AEEMod_AddRef
;50 modFuncs
->Release
= AEEMod_Release
;51 modFuncs
->CreateInstance
= AEEMod_CreateInstance
;52 modFuncs
->FreeResources
= AEEMod_FreeResources
;535455 // initialize the vtable
56 INIT_VTBL
(pMe
, IModule
, *modFunc
已有 0 人发表留言,猛击->>这里<<-参与讨论
JavaEye推荐