前文提到我的FM收音机是通过com+app来实现的。这里的com是brew的组件,和微软的com组件是不一样的。在这里我不想讨论微软的com组件和brew的组件有什么不一样,而是想详细的分析一下brew的组件原理。(因为我对微软的com组件也不是很熟悉,之前做过windows mobile的开发,但是没做多久就换平台了。。。)就让我们拿来做为例子来深入的了解brew组件的原理和实现吧!
拿FM收音机的组件来说,头文件中定义如下(去掉了一些函数指针):
typedef struct IFMRadio IFMRadio;#define INHERIT_IFMRadio(iname) \
INHERIT_IQueryInterface(iname); \
int (*Start)(iname *po);\
int (*Stop)(iname *po)
AEEINTERFACE(IFMRadio)
{
INHERIT_IFMRadio(IFMRadio);
};
struct IFMRadio
{
const AEEVTBL(IFMRadio)* pvt;
void* pData;
};
#define IFMRadio_AddRef(pThis) \
(pThis)->pvt->AddRef((pThis))
#define IFMRadio_Release(pThis) \
(pThis)->pvt->Release((pThis))
#define IFMRadio_QueryInterface(pThis, ClsID, ppInterface) \
(pThis)->pvt->QueryInterface((pThis), (ClsID), (ppInterface))
#define IFMRadio_Start(pThis) \
(pThis)->pvt->Start((pThis))
#define IFMRadio_Stop(pThis) \
(pThis)->pvt->Stop((pThis))
我们首先看第一宏INHERIT_IQueryInterface,它在AEEQueryInterface.h中定义如下 #define INHERIT_IQueryInterface INHERIT_IQI 而INHERIT_IQI也是一个宏,它在AEEIQI.h中定义为:#define INHERIT_IQI(iname) \
uint32 (*AddRef)(iname*);\
uint32 (*Release)(iname*);\
int (*QueryInterface)(iname *, AEEIID, void **)
实际上它是三个函数指针,所以#define INHERIT_IFMRadio(iname) \
INHERIT_IQueryInterface(iname); \
int (*Start)(iname *po);\
int (*Stop)(iname *po)
进行宏替换后就成了
#define INHERIT_IFMRadio(iname) \
uint32 (*AddRef)(iname*);\
uint32 (*Release)(iname*);\int (*QueryInterface)(iname *, AEEIID, void **);\
int (*Start)(iname *po);\ int (*Stop)(iname *po)接下来看AEEINTERFACE的宏定义(它在AEEInterface.h文件中):
#define AEEINTERFACE(iname) \
typedef struct AEEVTBL(iname) AEEVTBL(iname); \
struct AEEVTBL(iname)
再对它进行宏替换,就成了如下形式:
typedef struct AEEVTBL(IFMRadio) AEEVTBL(IFMRadio); \struct AEEVTBL(IFMRadio)
{INHERIT_IFMRadio(IFMRadio);
};
对INHERIT_IFMRadio进行宏替换后:
typedef struct AEEVTBL(IFMRadio) AEEVTBL(IFMRadio); \
struct AEEVTBL(IFMRadio)
{
uint32 (*AddRef)(IFMRadio*);\
uint32 (*Release)(IFMRadio*);\
int (*QueryInterface)(IFMRadio *, AEEIID, void **);\
int (*Start)(IFMRadio *po);\
int (*Stop)(IFMRadio *po)
};
这里还有一个AEEVTBL宏,它也在AEEInterface.h中定义了:
#define AEEVTBL(iname) iname##Vtbl
于是对这个宏进行替换就成了下面的形式:typedef struct IFMRadioVtbl IFMRadioVtbl; \
struct IFMRadioVtbl
{
uint32 (*AddRef)(IFMRadio*);\
uint32 (*Release)(IFMRadio*);\
int (*QueryInterface)(IFMRadio *, AEEIID, void **);\
int (*Start)(IFMRadio *po);\
int (*Stop)(IFMRadio *po)
};
所以的宏替换之后,头文件变成了如下形式:
typedef struct IFMRadio IFMRadio;
typedef struct IFMRadioVtbl IFMRadioVtbl; \ struct IFMRadioVtbl {uint32 (*AddRef)(IFMRadio*);\
uint32 (*Release)(IFMRadio*);\
int (*QueryInterface)(IFMRadio *, AEEIID, void **);\
int (*Start)(IFMRadio *po);\
int (*Stop)(IFMRadio *po)
};
struct IFMRadio
{
const IFMRadioVtbl* pvt;
void* pData;};
结构体IFMRadio实际上是一个结构体指针IFMRadioVtbl*和一个空指针,而这个结构体IFMRadioVtbl是一些函数指针。 再来看FM收音机的源文件(略去了一些具体的代码):typedef struct
{
uint32 nRefs;
IShell* pIShell; IFMRadio myIFMRadio;} CFMRadio;
static const AEEVTBL(IFMRadio) gIFMRadioFuncs =
{
CFMRadio_IBase_AddRef,
CFMRadio_IBase_Release, CFMRadio_IBase_QueryInterface, CFMRadio_IFMRadio_Start, CFMRadio_IFMRadio_Stop,};
static int CFMRadio_IFMRadio_Start(IFMRadio *pIFMRadio)
{
int result = SUCCESS;
//实现的代码...
return result;
};
static int CFMRadio_IFMRadio_Stop(IFMRadio *pIFMRadio)
{
int result = SUCCESS;
//实现的代码...
return result;
}
static int CFMRadio_IBase_QueryInterface(IFMRadio* pIFMRadio, AEECLSID ClsID, void** ppInterface)
{
if (ClsID == AEECLSID_QUERYINTERFACE || ClsID == SYS_CLSID_IFMRADIO)
{
IBASE_COPY_IPTR(*ppInterface, pIFMRadio);
return SUCCESS;
}
return ECLASSNOTSUPPORT;
}
int CFMRadio_New(IShell* pIShell, AEECLSID ClsID, void** ppInterface)
{
int result = SUCCESS;
IFMRadio* pIFMRadio = NULL;
CFMRadio* pThis = NULL;
if (pIShell == NULL || ppInterface == NULL)
{
return EBADPARM;
}
if (ClsID != SYS_CLSID_IFMRADIO) {return EUNSUPPORTED;
} pThis = CFMRadio_Constructor(pIShell); if (pThis == NULL) { return ENOMEMORY; }pIFMRadio = &pThis->myIFMRadio;
result = IFMRadio_QueryInterface(pIFMRadio, SYS_CLSID_IFMRADIO, ppInterface); if (SYS_FAILURE(result)) {CFMRadio_Destructor(pThis);
}
return result;
}
static CFMRadio* CFMRadio_Constructor(IShell* pIShell)
{
CFMRadio* pThis = NULL;
pThis = (CFMRadio*)UMPAlloc(sizeof(CFMRadio));
if (pThis == NULL)
{
return NULL;
}
pThis->nRefs = 0;
IBASE_COPY_IPTR(pThis->pIShell, pIShell); pThis->myIFMRadio.pvt = &gIFMRadioFuncs; pThis->myIFMRadio.pData = (void*)pThis;if (SYS_FAILURE(CFMRadio_Initialise(pThis)))
{ CFMRadio_Destructor(pThis); pThis = NULL; } return pThis;}
我们要调用组件中的接口函数首先要调用ISHELL_CreateInstance创建这个组件的实例,创建成功后才能调用这个组件的接口函数,调用ISHELL_CreateInstance这个函数会传递一个classid,通过这个classid会调用对应的New函数(这个classid和相对应的New函数是通过一个静态类的数组关联起来的),CFMRadio_New函数会调用CFMRadio_Constructor函数,CFMRadio_Constructor函数首先为组件分配内存,接着是两个赋值语句: pThis->myIFMRadio.pvt = &gIFMRadioFuncs; pThis->myIFMRadio.pData = (void*)pThis; 通过前面我们可以看到gIFMRadioFuncs的定义,宏替换后就是下面的形式:static const IFMRadioVtbl gIFMRadioFuncs =
{
CFMRadio_IBase_AddRef, CFMRadio_IBase_Release, CFMRadio_IBase_QueryInterface, CFMRadio_IFMRadio_Start, CFMRadio_IFMRadio_Stop,};
它定义一个全局的结构体,并进行了初始化,于是IFMRadioVtbl中的函数指针就被初始化为这些函数名,uint32 (*AddRef)(IFMRadio*); 对应CFMRadio_IBase_AddRef,
uint32 (*Release)(IFMRadio*);对应CFMRadio_IBase_Release,
int (*QueryInterface)(IFMRadio *, AEEIID, void **);对应CFMRadio_IFMRadio_Start,
int (*Start)(IFMRadio *po);对应CFMRadio_IFMRadio_Start,
int (*Stop)(IFMRadio *po)对应CFMRadio_IFMRadio_Stop,
而下面一句则是把pThis赋给了结构体IFMRadio中的pData,接着我们来看它是app是如何进行调用的,app首先定义一个IFMRadio的指针*pFMRadio;接着调用ISHELL_CreateInstance创建这个组件的实例,并将第三个参数设置为(void**)&pFMRadio传递进去,这时会调用CFMRadio_New函数,它也接收(void**)&pFMRadio作为参数,它首先调用CFMRadio_Constructor函数对myIFMRadio结构体进行初始化,接着调用接口函数IFMRadio_QueryInterface接口函数,它实际上利用IBASE_COPY_IPTR(*ppInterface, pIFMRadio)对pIFMRadio指针进行初始化,实际上是将&pThis->myIFMRadio赋值给了pIFMRadio,如果我们调用IFMRadio_Start(pIFMRadio),通过前面的宏定义,#define IFMRadio_Start(pThis) \
(pThis)->pvt->Start((pThis))
实际上是(pIFMRadio)->pvt->Start(pIFMRadio),而pIFMRadio又被赋值为&pThis->myIFMRadio,所以调用变成了
(&pThis->myIFMRadio)->pvt->Start(&pThis->myIFMRadio)而在CFMRadio_Constructor中pThis->myIFMRadio.pvt又被初始化为&gIFMRadioFuncs,其中start函数指针被初始化为CFMRadio_IFMRadio_Start,所以最后IFMRadio_Start实际上调用的是CFMRadio_IFMRadio_Start函数。有的地方把这叫做类的扩展,而我们部门叫做组件。根据它的实现原理,我觉得叫做组件更确切一些(虽然它和微软的com组件不一样)。组件的实现有多种方式,实际上是大同小异的,一般会有一些宏不太一样,这些宏在AEE.h和AEEInterface.h等一些头文件都会有定义,进行宏替换后的结构基本上都是一样的。