Brew中的Module的实现方法:
【原创作者:shosh,
http://www.yuleyx.com/shosh】
我们从AEEModGen.c中提供的用于创建Module对象的对外接口入手,函数如下:
01 int 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 }
01 int 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
02 typedef 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 ;
01 //Structure that implements the IModule interface
02 typedef 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 ;
1 // Use as first member of classes that override QINTERFACE()
2 #define DECLARE_VTBL (iname ) iname vt##iname ;
所以DECLARE_VTBL
(IModule
)就是:
IModule vtIModule;
IModule是一个结构体类型,定义如下:
1 typedef struct _IModule IModule ;
1 typedef struct _IModule IModule ;
所以,我们需要了解_IModule的结构体是什么样子的。我们需要从下面的四行代码入手,不过下面主要是两个宏定义,需要展开才能够明白它们到底是什么东西。
1QINTERFACE (IModule )
2 {
3 INHERIT_IModule (IModule ) ;
4 } ;
1QINTERFACE (IModule )
2 {
3 INHERIT_IModule (IModule ) ;
4 } ;
下面是所有相关的宏定义,先贴出来,然后再用这些定义将上面的4行慢慢展开:
01 typedef 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 * )
01 typedef 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的定义,得到:
1 struct _IModule {
2 struct IModuleVtbl *pvt ;
3 } ;
4 typedef struct IModuleVtbl IModuleVtbl ;
5 struct IModuleVtbl
1 struct _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 ) ;
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 ) ;
将以上结果合并起来,就可以得到如下代码:
01 struct _IModule
02 {
03 struct IModuleVtbl *pvt ;
04 } ;
05 typedef struct IModuleVtbl IModuleVtbl ;
06 struct 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 } ;
01 struct _IModule
02 {
03 struct IModuleVtbl *pvt ;
04 } ;
05 typedef struct IModuleVtbl IModuleVtbl ;
06 struct 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
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,具体代码如下:
01
int 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;
06
07 if ( !ppMod | | !pIShell ) {
08 return EFAILED ;
09 }
10
11 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 #endif
31
32 //Allocate memory for the AEEMod object
33
34 if (nSize < sizeof (AEEMod ) ) {
35 nSize + = sizeof (AEEMod ) ;
36 }
37
38 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.
45
46 modFuncs = (IModuleVtbl * ) ( (byte * )pMe + nSize ) ;
47
48 // 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 ;
53
54
55 // initialize the vtable
56 INIT_VTBL (pMe , IModule , *modFunc
02 PFNMODCreateINST pfnMC ,PFNFREEMODDATA pfnMF )
03 {
04 AEEMod *pMe = NULL ;
05 VTBL (IModule ) *modFuncs ; //将其展开就是 IModuleVtbl *modFuncs;
06
07 if ( !ppMod | | !pIShell ) {
08 return EFAILED ;
09 }
10
11 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 #endif
31
32 //Allocate memory for the AEEMod object
33
34 if (nSize < sizeof (AEEMod ) ) {
35 nSize + = sizeof (AEEMod ) ;
36 }
37
38 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.
45
46 modFuncs = (IModuleVtbl * ) ( (byte * )pMe + nSize ) ;
47
48 // 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 ;
53
54
55 // initialize the vtable
56 INIT_VTBL (pMe , IModule , *modFunc