`
yanlijun250
  • 浏览: 752451 次
文章分类
社区版块
存档分类
最新评论

brew接口内存布局

 
阅读更多

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

#defineVTBL(iname)iname##Vtbl

#defineQINTERFACE(iname)
struct_##iname{
structVTBL(iname)*pvt;
}
;
typedef
structVTBL(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;
}
;
typedef
structIFileMgr_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)
}

typedef
struct_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;


}

如果你看懂上面的函数,说明你理解了接口了吧!

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics