brew组件实现原理

  前文提到我的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等一些头文件都会有定义,进行宏替换后的结构基本上都是一样的。

转载于:https://www.cnblogs.com/rager/archive/2010/08/15/1800235.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值