Friday, December 22

brew程序的入口点

一个brew程序的真正入口点在AEEModGen.c里面

#ifdef AEE_LOAD_DLL
__declspec(dllexport) int AEEMod_Load(IShell *pIShell, void *ph, IModule **ppMod)
#else
#if defined(BREW_MODULE) || defined(FLAT_BREW)
extern int module_main(IShell *pIShell, void *ph, IModule **ppMod);
int module_main(IShell *pIShell, void *ph, IModule **ppMod)
#else
int AEEMod_Load(IShell *pIShell, void *ph, IModule **ppMod)
#endif
#endif
{
// Invoke helper function to do the actual loading.
return AEEStaticMod_New(sizeof(AEEMod),pIShell,ph,ppMod,NULL,NULL);
}

可见模拟器通过DLL的公开函数AEEMod_Load进入初始化阶段

brew各个模块之间可以进行消息传递函数回调, 而每个模块都可以单独编译不需要连接lib, 是因为各个模块实际公开的都是函数指针, 类似于
#define ISHELL_SendEvent(p,cls,ec,wp,dw) GET_PVTBL(p,IShell)->SendEvent(p,0,cls,ec,wp, dw)

AEE环境给每一个module都传入IShell指针, 在程序里如果想调用其他模块, 需要首先通过ISHELL_CreateInstance创建一个新的实例。
ISHELL_CreateInstance没有代码可看, 可以猜测AEE通过给出classid, 到自己维护的classid表里找到需要dll(module), 调入内存, 执行公开函数AEEMod_Load做初始化

AEEMod_Load-> AEEStaticMod_New设置modFuncs->CreateInstance = AEEMod_CreateInstance
随后AEE调用这个指针,在AEEMod_CreateInstance里面完成调用AEEClsCreateInstance的任务, classid这时候作为参数传进来
在AEEModGen.h里面有AEEClsCreateInstance函数的声明, 这个函数的定义需要在自己的程序里面完成。
int AEEClsCreateInstance(AEECLSID ClsId, IShell *pIShell, IModule *pMod, void **ppobj);

如果一个module里面定义了多个class就需要判断classid的值,创建不同的实例。

在初始化代码里
if (NULL == (pme = (AEEApplet*)MALLOC(nSize + sizeof(IAppletVtbl))))
return FALSE; //分配空间,nSize代表CAPP的空间大小!!
appFuncs = (IAppletVtbl *)((byte *)pme + nSize);
这两句表明在applet的结构体后面就是IAppletVtbl

appFuncs->AddRef = AEEApplet_AddRef;
appFuncs->Release = AEEApplet_Release;
appFuncs->HandleEvent = AEEApplet_HandleEvent;

在AEEApplet_HandleEvent里面将IApplet指针转换成AEEApplet指针,然后调用AEEApplet的pAppHandleEvent
之所以可以这么转换是因为AEEApplet的第一个成员就是IApplet指针的地址。结构体的第一个成员的地址就是这个结构体的地址。

INIT_VTBL(pme, IApplet, *appFuncs);
这一句使的AEEApplet结构体的第一个成员指向applet结构体后面的IAppletVtbl

No comments: