Using Extended Interfaces

Framework developers define and publish extension interfaces to the existing interfaces used in the framework. Once an interface extension is published by the framework developer, plug-in developers implement the extension if required.


  1. Identify the published instantiation and extended interface UIDs and header files of the framework.

  2. Create a new project file (.mmp) with targettype variable set as PLUGIN3. Allocate UIDs for the the plug-in implementations and plug-in DLL (UID3) as shown in the code snippet below.
    TARGET         cimplementationclass.dll
    TARGETTYPE     PLUGIN3
    CAPABILITY    All -TCB
    
    // PLUGIN3 recognition UID followed by the UID for this dll
    UID 0x10009D93 0x10009E37
    VENDORID 0x70000001
    
    SOURCEPATH    ../src
    SOURCE        cimplementationclass.cpp 
    
    USERINCLUDE    ../src
    SYSTEMINCLUDE     /epoc32/include
    
    START RESOURCE    cimplementationclass.rss
    TARGET cimplementationclass.rsc
    END
    
    LIBRARY     euser.lib
    LIBRARY     ecom.lib
    

  3. Create a new resource file (.rss) of format version 3.
    CImplementationClass.rss
    #include <ecom/registryinfov3.rh>
    
    RESOURCE REGISTRY_INFO theInfo
        {
        resource_format_version = RESOURCE_FORMAT_VERSION_3;
        dll_uid = 0x10009E37;
        interfaces = 
        {
        INTERFACE_INFO
            {
            instantiation_interface_uid = 0x10009DBB;
            implementations = 
            {
            IMPLEMENTATION_INFO
                {
                info_format = IMPLEMENTATION_INFO_RECORD_TYPE1; 
                implementation_uid = 0x10009E38;
                version_no = 1;
                display_name = "Extended Interface Example";
                default_data = {"Extended Interface Example||up to 255 chars", "Max. two strings allowed"};
                opaque_data = {"up to 255 chars", “max. 2 strings allowed”};
                extended_interfaces = {0x10009E44, 0x10009E45};
                flags = FLAG_ROM_ONLY;                    
                }    
            };
            }
        };
        }
    

  4. Implement the interfaces in the plug-in implementation source files. Implementing an interface extension in a plug-in implementation can be done in either of the two ways:

    1. Inheritance: The instantiation interface object is also of the type of the extended interface object. When a user wants to instantiate the extended interface object, the implementation simply returns a re-cast of the instantiation interface object. The example below shows implementing an interface extension using inheritance.
      //Implementing an interface extension using multiple inheritance
      class CImplementationClass : public CExampleInterface, public MExampleInterfaceExtended
      {
      
      public:
          static CImplementationClass* NewL();
          static TAny* GetExtendedInterfaceL(TAny* aInstantiationInterface,const TUid& aExtendedInterfaceUid,TUint32& aBitFlags,TAny*& aReleaseObject);
          static void ReleaseExtendedInterface(TAny* aExtendedInterface, const TUid& aExtendedInterfaceUid);
      
          ~ CImplementationClass() {}
          virtual void DoMethodL(); // from original interface
          virtual void DoMethodExtended();  //from MExampleInterfaceExtended
      private:
          CImplementationClass() {}
      };
      
      

    2. Realizing the extended interface as separate class and objects. When users fetch the extended interface object, the implementation allocates a new object. The example below shows implementing an interface extension using realisation.
      // Implementing an interface extension using realization
      
      class CImplementationClassExtended : public CBase, public MExampleInterfaceExtended2
      {
      public:
          static CImplementationClassExtended* NewL();
          ~ CImplementationClassExtended() {}
          virtual void DoMethodExtended2();  //from MExampleInterfaceExtended2
      private:
          CImplementationClassExtended() {}
      };
      

  5. Implement REComSession::CreateImplementationL(),REComSession::GetExtendedInterfaceL(),REComSession::ManuallyReleaseExtendedInterfaceL() functions of the instantiation interface.
    TAny* CImplementationClass::GetExtendedInterfaceL(TAny* aInstantiationInterface,
    const TUid& aExtendedInterfaceUid,
    TUint32& aBitFlags,
    TAny*& aReleaseObject)
        {
        TAny* ret = NULL;
        aBitFlags &= ~KReleaseRequiredMask; // clear release flag
        switch (aExtendedInterfaceUid.iUid)
        {
        case 0x10009E44: 
            {
                // release not required, so do not modify aBitFlags.
             // re-cast Instantiation object as Extended Interface object
            ret = static_cast<MExampleInterfaceExtended *> (static_cast<CImplementationClass *>(aObject));
            break;
            }    
        case 0x10009E45: 
            {
              CImplementationClassExtended *classExt = CImplementationClassExtended::NewL();
            aReleaseObject = classExt;
            aBitFlags |= KReleaseRequiredMask; // Indicate release is required
            // Multiple inheritance involved – Cbase and the M class. Must use
                // either dynamic_cast or static_cast to add offset to the base pointer       
            ret = static_cast<MExampleInterfaceExtended2*>(classExt);
            break;
               }                
        }
        return ret;
        }
    
    The plug-in framework releases the extended interface object when the user destroys the instantiation interface object. Alternatively, if the framework wants to release the extended interface earlier, they can call the REComSession::ManuallyReleaseExtendedInterfaceL()
    void CImplementationClass::ReleaseExtendedInterface(TAny* aExtendedInterface, const TUid& aExtendedInterfaceUid)
        {
        switch (aExtendedInterfaceUid.iUid)
        {
        case 0x10009E45:
            {
                // this Extended Interface object require release.
            CImplementationClassExtended* classExt = static_cast<CImplementationClassExtended*>(aReleaseObject);
            delete classExt;
            break;
            }                
        }
        }    
    
    The aInstanceKey parameter is returned by REComSession::CreateImplementationL(). It identifies the instantiation interface object instance. The aExtendedInterfaceUid parameter identifies the extended interface required.

  6. Export the instantiation functions into a TImplementationProxy3 table.
    const TImplementationProxy3 KImplementationTable[] =
        {
        IMPLEMENTATION_PROXY_ENTRY3(0x10009E38, CImplementationClass::NewL, CImplementationClass::GetExtendedInterfaceL,CImplementationClass::ReleaseExtenedInterface)
        };
    
    EXPORT_C const TImplementationProxy3* ImplementationGroupProxy(TInt& aTableCount)
        {
        aTableCount = sizeof(KImplementationTable) / sizeof(TImplementationProxy3);
        return KImplementationTable;
        }
    
    

  7. Export the release functions into a TImplementationProxy3 table.
    void CImplementationClass::ReleaseExtendedInterface(TAny* aExtendedInterface, const TUid& aExtendedInterfaceUid)
        {
        switch (aExtendedInterfaceUid.iUid)
        {
        case 0x10009E45:
            {
                // this Extended Interface object require release.
            CImplementationClassExtended* classExt = static_cast<CImplementationClassExtended*>(aReleaseObject);
            delete classExt;
            break;
            }                
        }
        }    
    
    

To instantiate and use an extended interface, the plug-in user must:

  • Identify plug-ins that support the desired interface extensions using REComSession::ListImplementationsL().

    IMPORT_C static void ListImplementationsL(TUid aInterfaceUid, 
    RExtendedInterfacesArray& aExtendedInterfaces,
        const TEComResolverParams& aResolutionParameters,
        RImplInfoPtrArray& aImplInfoArray);
    

    The “aInterfaceUid” parameter specifies the instantiation interface. All of the implementations returned in “aImplInfoArray” support all the extensions listed in the “aExtendedInterfaces” parameter.

  • Select one from the array and create an instantiation interface object.

  • Call REComSession::GetExtendedInterfaceL() API to get an extended interface object.

    IMPORT_C static TAny* GetExtenedInterfaceL(const TUid& aInstanceKey, 
    const TUid& aExtendedInterfaceUid);
    

    The aInstanceKey parameter identifies the instantiation interface object returned by REComSession::CreateImplementationL().

The example code depicts the above steps:


const TUid KExampleInterfaceUid = {0x10009DBB}; // the Instantiation Interface
const TUid KExtendedInterfaceUid1 = {0x10009E44};
const TUid KExtendedInterfaceUid2 = {0x10009E45};

// Set up extended interfaces UID list which form part of the resolution criteria.
RArray<TUid> extendedInterfaces;
CleanupClosePushL(extendedInterfaces);
extendedInterfaces.AppendL(KExtendedInterfaceUid1);
extendedInterfaces.AppendL(KExtendedInterfaceUid2);

// set up resolve parameter
_LIT8(KExampleImplementationData,"Extended Interface Example");
TEComResolverParams ResolverParams;
ResolverParams.SetDataType(KExampleImplementationData());
ResolverParams.SetGenericMatch(ETrue);

TUid instanceKey;
CExampleInterface* instantiateIf = static_cast<CExampleInterface*>(
    REComSession::CreateImplementationL(KExampleInterfaceUid,
                                       extendedInterfaces,
                                       instanceKey,
                                       ResolverParams) );
CleanupStack::PopAndDestroy(&extendedInterfaces);

CleanupStack::PushL(instantiateIf);
// May want to TRAP here if KErrNotSupported is handled, i.e. extension optional
MExampleInterfaceExtended2* ext2 = static_cast<MExampleInterfaceExtended2*>(
  REComSession::GetExtendedInterfaceL(instanceKey, KExtendedInterfaceUid2));

instantiateIf->DoMethodL();  // access old interface function
ext2->DoMethodExtended2();   // access extension function

// Calling ManuallyReleaseExtendedInterface is optional. Do this
// if want to release extended object early.
REComSession::ManuallyReleaseExtendedInterface(instanceKey,KExtendedInterfaceUid2);

REComSession::DestroyedImplementation(instanceKey);
CleanupStack::PopAndDestroy(instantiateIf);