在第一次接触brew时,我就在疑问:“brew中的接口是个什么概念啊!”,而且发现它里面就没有数据,只有一个指针。后来慢慢才熟悉和明白了brew的接口的实质和内存布局。
如果你要揪跟问底,那你可以跟踪到其定义的头文件中看看究竟。那我就以IFileMgr为例子来看看究竟!(别的都类似)
当我跟踪进去后,我发现头文件
#defineVTBL(iname)iname##Vtbl
#defineQINTERFACE(iname)
struct_##iname
{
structVTBL(iname)*pvt;
};
typedefstructVTBL(iname)VTBL(iname);
structVTBL(iname)

#defineINHERIT_IFileMgr(iname)
INHERIT_IBase(iname);
IFile*(*OpenFile)(iname*piname,constchar*pszFile,OpenFileModemode);
int(*GetInfo)(iname*piname,constchar*pszName,FileInfo*pInfo);
int(*Remove)(iname*piname,constchar*pszName);
int(*MkDir)(iname*piname,constchar*pszDir);
int(*RmDir)(iname*piname,constchar*pszDir);
int(*Test)(iname*piname,constchar*pszName);
uint32(*GetFreeSpace)(iname*piname,uint32*pdwTotal);
int(*GetLastError)(iname*piname);
int(*EnumInit)(iname*piname,constchar*pszDir,booleanbDirs);
boolean(*EnumNext)(iname*piname,FileInfo*pInfo);
int(*Rename)(iname*pfm,constchar*pszSrc,constchar*pszDest);
boolean(*EnumNextEx)(iname*pfm,AEEFileInfoEx*pInfo);
int(*SetDescription)(iname*pfm,constchar*pszName,AECHAR*pszDesc);
int(*GetInfoEx)(iname*pfm,constchar*pszName,AEEFileInfoEx*pi);
int(*Use)(iname*pfm,constchar*pszName,booleanbUse);
int(*GetFileUseInfo)(IFileMgr*pfm,AEEFileUseInfo*pfu)

QINTERFACE(IFileMgr)

{
INHERIT_IFileMgr(IFileMgr);
};
中都是一些宏定义,主要就是QINTERFACE(IFileMgr) 宏,我将其一层层展开:

struct_IFileMgr
{
structIFileMgr_Vtbl*pvt;
};
typedefstructIFileMgr_VtblIFileMgr_Vtbl;
structIFileMgr_Vtbl

{
INHERIT_IBase(IFileMgr);
IFile*(*OpenFile)(IFileMgr*piname,constchar*pszFile,OpenFileModemode);
int(*GetInfo)(IFileMgr*piname,constchar*pszName,FileInfo*pInfo);
int(*Remove)(IFileMgr*piname,constchar*pszName);
int(*MkDir)(IFileMgr*piname,constchar*pszDir);
int(*RmDir)(IFileMgr*piname,constchar*pszDir);
int(*Test)(IFileMgr*piname,constchar*pszName);
uint32(*GetFreeSpace)(IFileMgr*piname,uint32*pdwTotal);
int(*GetLastError)(IFileMgr*piname);
int(*EnumInit)(IFileMgr*piname,constchar*pszDir,booleanbDirs);
boolean(*EnumNext)(IFileMgr*piname,FileInfo*pInfo);
int(*Rename)(IFileMgr*pfm,constchar*pszSrc,constchar*pszDest);
boolean(*EnumNextEx)(IFileMgr*pfm,AEEFileInfoEx*pInfo);
int(*SetDescription)(IFileMgr*pfm,constchar*pszName,AECHAR*pszDesc);
int(*GetInfoEx)(IFileMgr*pfm,constchar*pszName,AEEFileInfoEx*pi);
int(*Use)(IFileMgr*pfm,constchar*pszName,booleanbUse);
int(*GetFileUseInfo)(IFileMgr*pfm,AEEFileUseInfo*pfu)
}
typedefstruct_IFileMgrIFileMgr
原来就是个IFileMgr就是个结构体,结构体中只有一项就是另一个结构体的指针,现在突然明白了,为什么原来sizeof(IFileMgr)
= 4呢?那么这个指针指向的结构体是什么东西啊,看看里面的定义都是一些函数指针,仔细分析会发现所有的函数指针都是这个接口提供的函数!
第一项是个宏:INHERIT_IBase(IFileMgr);
我不想多说了,这个其实就是IBase接口提供的引用记数功能,每个接口的第一项就是它。
现在有个疑问了,那么这个接口的数据在那里放着呢?废话啊,不在头文件中就在实现文件中。对,这点不容质疑。但是究竟这个数据是怎么和函数联系起来的呢?那我就要猜测了!(不猜测也不行,因为实现文件编译成二进制了)。高通对知识产权保护的真是到位啊(这是他一贯的作风)!怎么猜测呢?
我先看看怎么使用一个接口。大部分接口都是通过ISHELL_CreateInstance(IShell * pIShell, AEECLSID cls,
void** ppobj ) 创建的。然后就使用这个创建的pobj调用函数如OpenFile(IFileMgr * piname, const char
*pszFile, OpenFileMode
mode)。每个函数的第一个参数就是接口指针。正如前面分析的宏,这个函数也是个宏定义,变成调用虚表中相应的函数指针指向的函数。指向的函数就是真真正正实现的函数。
那么现在考虑2个问题:
1. 在写这些函数时如何得到数据的存储地址,你只是有一个虚表的地址,那我想这些
数据应该是紧放在虚表后面的空间中连续存放,否则函数无法得到数据。
2.函数指针应该初始化,以指向真实的实现函数,而且还要为数据和虚表分配空间。
我们可以肯定第1个问题是正确的。那么2个问题在那里做这些工作呢?我猜测的是ISHELL_CreateInstance中,因为ISHELL_CreateInstance返回时,接口已经建立好了,可以调用接口的函数了!如果不在ISHELL_CreateInstance中,那恐怕函数都调用不了啊!!
我尝试写了一个大概示意代码:

/**///////////////////////////////////////
//实现文件
/**///////////////////////////////////////
//接口数据定义
typedefstruct_IFileMgr_Data

{
charfileName[30];
intfile_pos;

}IFileMgr_Data;
//根据不同的AEECLSID调用具体接口的初始化函数
ISHELL_CreateInstance(IShell*pIShell,AEECLSIDcls,void**ppobj)

{

switch(cls)

{
caseAEECLSID_FILEMGR:
AllocFileMgr(ppobj);

}
}

intAllocFileMgr(IFileMgr**ppobj)

{
if(!ppobj)
return(FALSE);
*ppobj=NULL;
//分配内存
*ppobj=(IFileMgr*)malloc(sizof(IFileMgr)+sizeof(IFileMgr_Data));
//初始化虚表
(*ppobj)->pvt=(IFileMgr_Vtbl*)malloc(sizeof(IFileMgr_Vtbl));
//下面的open_fileandget_info是我假设的真实实现函数
(*ppobj)->pvt->OpenFile=open_file;
(*ppobj)->pvt->GetInfo=get_info;

//初始化数据
(IFileMgr_Data*)(*ppobj+sizof(IFileMgr))->file_pos=0;


}
如果你看懂上面的函数,说明你理解了接口了吧!
本文深入探讨了BREW环境中接口的概念,以IFileMgr为例详细解释了接口的内存布局及其实现原理,包括宏定义、虚表及接口创建过程。
128

被折叠的 条评论
为什么被折叠?



