BREW Extensions Demystified - Part III

Please read this post for context before moving on.

Creation of IMcbXML.c
The IMcbXML.c is the main source file for our extension, it is equivalent to AEEAppGen.c and AEEModGen.c in case of BREW Applets. This file implements instantiation of the extension, setting up of VTBL and reference counting.
We need to create a class structure to hold our instance specific information such as our reference count, shell and module pointer.

typedef struct McbXML{
  DECLARE_VTBL(IMcbXML)
  uint32 m_nRefs;
  IShell *m_pIShell;
  IModule *m_pIModule;
};
Lets create the entry point for our extension, the all important AEEClsCreateInstance function.
int AEEClsCreateInstance(AEECLSID ClsId,IShell * pIShell,IModule * po, void ** ppObj)
{
  *ppObj = NULL;
  if( ClsId == AEECLSID_MCBXML )
  {
    if( McbXML_New(sizeof(McbXML_t), pIShell, po, (IModule **)ppObj) == SUCCESS )
      return AEE_SUCCESS;
  }
  return EFAILED;
}
The AEEClsCreateInstance is the entry point for the extension.
The McbXML_New is the constructor function for our extension. It allocates the memory for the class structure and VTBL, sets up the VTBL with the function pointers and stores the IShell and IModule pointers.
int McbXML_New(int16 nSize, IShell *pIShell, IModule* pIModule, IModule ** ppMod)
{
  McbXML_t *pMe = NULL;
  VTBL(IMcbXML) * modFuncs;

  if( !ppMod !pIShell !pIModule )
    return EFAILED;

  *ppMod = NULL;
  // Allocate memory for the IMcbXML object
  if( nSize < sizeof(McbXML_t) )
    nSize += sizeof(McbXML_t);

  if( (pMe = (McbXML_t*)MALLOC(nSize + sizeof(IMcbXMLVtbl))) == NULL )
    return ENOMEMORY;

  // Allocate the vtbl and assign each function pointer to the correct
  // function address
  modFuncs = (IMcbXMLVtbl *)((byte *)pMe + nSize);

  modFuncs->AddRef = McbXML_AddRef;
  modFuncs->Release = McbXML_Release;
  modFuncs->ParseXML = McbXML_ParseXML;
  modFuncs->FindElement= McbXML_FindElement;
  modFuncs->DeleteRoot = McbXML_DeleteRoot;

  //initialize the vtable
  INIT_VTBL(pMe, IModule, *modFuncs);

  //We've got one reference since this class is allocated
  pMe->m_nRefs = 1;

  // initialize our internal member variables
  pMe->m_pIShell = pIShell;
  pMe->m_pIModule = pIModule;

  //Add References to the interfaces we're using
  ISHELL_AddRef(pIShell);
  IMODULE_AddRef(pIModule);
  *ppMod = (IModule*)pMe;
  return AEE_SUCCESS;
}
Now, to manage our references we need to create the AddRef and Release functions.
static uint32 McbXML_AddRef(IMcbXML * po)
{
  return (++((McbXML_t *)po)->m_nRefs);
}

static uint32 McbXML_Release(IMcbXML * po)
{
  McbXML_t *pMe = (McbXML_t *)po;
  //Decrease the number of references. If we still
  //have some references to this object, return
  //and do not free resources
  if(-pMe->m_nRefs != 0)
    return pMe->m_nRefs;

  // Release interfaces
  ISHELL_Release(pMe->m_pIShell);
  IMODULE_Release(pMe->m_pIModule);

  //Free the object
  FREE_VTBL(pMe, IModule);
  FREE(pMe);
  return 0;
}
As you can see the AddRef function increments the m_nRefs variable, the release function will Free up the memory when the reference count reaches zero. This reference counting mechanism prevents the release of an extension when it is still used by someone.

Now, we need to create the wrapper function to call the actuan McbXML API's.
static McbXMLElement* McbXML_ParseXML(IMcbXML *po, LPCTSTR lpszXML, McbXMLResults *pResults)
{
  return McbParseXML(lpszXML, pResults);
}

static McbXMLElement* McbXML_FindElement(IMcbXML *po, McbXMLElement *pHead, LPCTSTR lpszName)
{
  return McbFindElement(pHead, lpszName);
}

static void McbXML_DeleteRoot(IMcbXML *po, McbXMLElement * pElement)
{
  McbDeleteRoot(pElement);
}
In the next post we will create the supporting BID and MIF file and see how to use our extension.

0 Responses to "BREW Extensions Demystified - Part III"