The recommendation in the Splitting the UI and the Engine section to cleanly separate GUI and engine code is founded on good design principles. This section takes the issue of code separation and reusability, which are the pillars of those principles, one step further. It suggests that engines, and other kinds of software components , could be reused with the greatest of ease if there were some kind of framework to allow them to dynamically plug-in, so that they essentially become an extension of the OS. ECom is exactly this ”it stands for Epoc Component Object Model , and it provides a means of taking new software components that may be widely beneficial and placing them within a delivery framework that is managed by the OS. ECom is a recent development and is available only from Series 60 2.x. Although it is not uniformly available, it is extremely useful and deserves coverage here, in the spirit of maximum code reuse and minimum redundancy.

The ECom framework is a Client/Server architecture that provides a service to instantiate, resolve, and destroy plug-in instances. Essentially it means you can encapsulate common functionality in a DLL that can be accessed by multiple clients through an interface class. The interface is client-side while the server manages the implementation. The framework takes care of the instantiation, as shown in Figure 4-7.

Figure 4-7. Representation of the ECom architecture.

The ECom framework is a new addition to Series 60 and is available only from Series 60 2.x.

Prior to ECom, the polymorphic DLL was the standard Symbian OS convention for delivering additional functionality at runtime. This convention meant that:

  • Modification of the DLL did not enforce recompilation of applications that used it (as opposed to statically linked libraries).

  • The loading of the DLL did not have to occur at application startup ”it could be loaded as the need arose, thereby preventing applications from needlessly using up memory.

ECom retains all of these runtime advantages. But at the same time, it significantly improves the ease of access to additional functionality. Whereas accessing objects in polymorphic DLLs requires knowledge of the DLL's location, ECom abstracts all such physicalities from developers wishing to use ECom plug-ins.

This section first provides a conceptual overview of the ECom convention, discussing what it does and the advantages it provides. Then it delves into the mechanisms of ECom and exemplifies the work required to design and deploy an ECom plug-in DLL. To illustrate this, the EComExample example application has been provided.

ECom Conceptual Overview

Each ECom object has one interface , contained within a standard header file. This interface is all that an ECom user requires ”the interface definition not only specifies how to interact with the object, but it also provides one or more static methods to instantiate the object.

One key feature of the ECom convention is that an object interface can have more than one implementation. To clarify the benefit of this, consider the example application EComExample ”the engine offers to draw both circles and rectangles, but each of these classes is derived from CShape . In the ECom paradigm, CShape would be the interface, and CCircle and CRectangle would be the implementations of that shape. Therefore, different functionality can be provided through a common interface. This feature is also useful, for example, to provide different versions of an object through the same interface.

ECom interfaces are typically very similar to those exposed in polymorphic DLLs, in that they are usually pure abstract class definitions, and this abstraction is what allows an interface to have more than one implementation.

ECom implementations each have a repository of descriptive information about the object. This includes the object's name , version, description and so on. This information is very useful, because it provides a couple of different ways to get access to a particular implementation ”they can be requested either by their unique ID or via a text-based cue. The latter request makes use of an ECom resolver, which searches through all the meta-information for each implementation and then returns the one that best matches the cue. Figure 4-8 broadly demonstrates the ECom convention. The user requests an object via the provided interface definition. It is ECom, however, that actually instantiates the requested object.

Figure 4-8. Basic ECom architecture.

ECom Interface

ECom uses Symbian OS Client/Server architecture. The interface resides client-side, whereas the implementations are managed by the server. The following code, taken from EComExample , shows an ECom object interface.

 class CShape : public CBase    {    public:       static CShape* NewL();       static CShape* NewL(const TDesC8& aMatch);       virtual ~CShape();       virtual void Draw(CWindowGc& aGraphicsContext) const = 0;    private:       TUid iDestructorIDKey;    }; 

The ECom-specific aspect of this interface resides in the overloaded NewL() functions and the destructor ”these use the REComSession API, through which actual implementations are requested and delivered. The two overloaded NewL() functions demonstrate the two ways in which implementations can be requested: The first NewL() , taking no parameters, simply requests the implementation by its known implementation UID ( KCCircleInterfaceUid ), so if this method is invoked, a CCircle object will be instantiated :

 inline CShape* CShape::NewL()    {    const TUid KCCircleInterfaceUid = { 0x101FDA61 };    TAny* interface = REComSession::CreateImplementationL(KCCircleInterfaceUid, _FOFF(CShape, iDestructorIDKey));    return reinterpret_cast<CShape*>(interface);    } 

The second version, shown below, requests the implementation based upon a free-form text query:

[View full width]
[View full width]
inline CShape* CShape::NewL(const TDesC8& aMatch) { const TUid KCShapeInterfaceUid = { 0x101FDA5D }; const TUid KCShapeResolverUid = { 0x101FDA5F }; TEComResolverParams resolverParams; resolverParams.SetDataType(aMatch); resolverParams.SetWildcardMatch(ETrue); TAny* interface = REComSession::CreateImplementationL(KCShapeInterfaceUid, _FOFF(CShape , iDestructorIDKey), resolverParams, KCShapeResolverUid); return reinterpret_cast<CShape*>(interface); }

To use this version of the NewL() function, the client would need to pass through a string that indicates the shape they require. The particular string text necessary for instantiating each type of object is defined in a resource file, 101FDA60.rss . So if you wanted a CRectangle object:

 _LIT8(KRectangleText, "Rectangle"); CShape* shape = CShape::NewL(KRectangleText) 

Apart from instantiation, the interface interacts with REComSession in order to destroy the object. Each object is allocated a unique key, and this key is passed back to ECom so that it can destroy the correct object.

 inline CShape::~CShape()    {    REComSession::DestroyedImplementation(iDestructorIDKey);    } 

Therefore, designing an ECom interface requires you to:

  • Provide a class definition for the object that will be returned from the ECom Server.

  • Provide static NewL() function(s) for implementing the object.

  • Implement the NewL() function, using REComSession to request the object.

  • Implement a virtual destructor which will, through REComSession , request to destroy the object.


The previous subsection described the requirements of an ECom interface. This subsection details the work required to add an ECom plug-in into the framework.

An ECom implementation is simply a collection of one or more implementations for one or more interfaces. Physically, it is made up of a pair of files. The first is the all-important DLL, which contains the actual code. The second is a compiled resource file, which is a map linking user interfaces to their implementations. It also provides descriptive information for each implementation. These two files are associated with one another by their names ”the unique UID of the DLL is typically used as the name for both files, as it is unique and relates the files to their implementation.

The resource files are what the ECom Server browses through in order to find the correct implementation for an interface. The following excerpt shows the format of the resource file 101FDA60.rss:

 RESOURCE REGISTRY_INFO r_theinfo    {    // UID for the DLL    dll_uid = 0x101FDA60;    // Declare array of interface info    interfaces =       {       INTERFACE_INFO          {          // UID of interface that is implemented          interface_uid = 0x101FDA5D;          implementations =             {             // Info for CCircle             IMPLEMENTATION_INFO                {                implementation_uid = 0x101FDA61;                version_no          = 1;                display_name        = "Circle shape";                default_data        = "CIRCLE";                opaque_data         = "";                },             // Info for CSquare             IMPLEMENTATION_INFO                {                implementation_uid = 0x101FDA62;                version_no          = 1;                display_name        = "Rectangle shape";                default_data        = "RECTANGLE";                opaque_data         = "";                }             };          }       };    } 

This demonstrates visibly how the information links together. The implementation DLL UID is defined first. Next, each interface that the implementation DLL contains is defined by the INTERFACE_INFO structure. Each of these contains one or more IMPLEMENTATION_INFO structures, exposing each implementation UID and accompanying descriptive information. Resource files and structures are covered in more detail in Chapter 5.

The resource file clearly provides the required information to:

  • Associate an interface with a particular implementation DLL.

  • Associate an interface with its various interface implementations.

  • Allow the user to request an implementation either by its unique UID, or by a text description of it.

The final requirement is for ECom to be able to locate a particular implementation within the DLL. In order to achieve this, every ECom DLL implements a table that maps each implementation in the DLL to its memory address, and a single function is exported that gives access to this table:

 const TImplementationProxy ImplementationTable[] =    {       { { 0x101FDA61 },   CCircle::NewL },       { { 0x101FDA62 },   CRectangle::NewL }    }; EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)    {    aTableCount = sizeof(ImplementationTable) / sizeof(TimplementationProxy);    return ImplementationTable;    } 

ECom DLLs must possess a UID that identifies them as such. The DLLs, along with the compiled .rsc files, must then be placed within the \system\libs\plugins\ directory in order for them to become registered.

The following example .mmp file should clarify any final informational requirements:

 TARGET ecomexample.dll TARGETTYPE ECOMIIC // ECom Dll recognition UID followed by the unique UID for this dll UID 0x10009D8D 0x101FDA60 SOURCEPATH    . SOURCE main.cpp SOURCE proxy.cpp SOURCE circle.cpp SOURCE rectangle.cpp USERINCLUDE  . SYSTEMINCLUDE       \epoc32\include SYSTEMINCLUDE       \epoc32\include\ecom RESOURCE     101FDA60.RSS LIBRARY euser.lib ECom.lib 

Developing Series 60 Applications. A Guide for Symbian OS C++ Developers
Developing Series 60 Applications: A Guide for Symbian OS C++ Developers: A Guide for Symbian OS C++ Developers
ISBN: 0321227220
EAN: 2147483647
Year: 2003
Pages: 139 © 2008-2017.
If you may any questions please contact us: