Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Symbian OS Explained - Effective C++ Programming For Smartphones (2005) [eng].pdf
Скачиваний:
60
Добавлен:
16.08.2013
Размер:
2.62 Mб
Скачать

FACTORY METHODS

237

virtual void DecryptL(TDesC8& aCiphertext, TDesC8& aKey, TDes8& aPlaintext, CryptoInterface::TAlgorithm) = 0;

private:

TUid iDtor_ID_Key; // Identification on cleanup };

This example interface derives directly from CBase, but it is not mandatory for an ECOM interface definition to do so. Interfaces may, for example, equally well derive from another C class such as CActive, which, of course, itself derives from CBase. Although the interface is defined as a C class, you’ll notice that a couple of the usual characteristics of a C class are missing. Firstly, the class has no explicitly declared constructor because it is an abstract base class and will not itself be constructed.2 In addition, although the class defines a static NewL() factory function, it does not define a ConstructL() method for second-phase construction. This is because the NewL() factory method of CCryptoInterface does not use standard twophase construction, but instead calls ECOM to instantiate a suitable implementation object.

An ECOM interface has the following characteristics:

It is an abstract class with a set of one or more pure virtual functions.

It must provide one or more factory functions to allow clients to instantiate an interface implementation object.

It must provide a means for its clients to release it, such as a destructor or a method such as Release() or Close().

It has a TUid data member, used internally to identify an implementation instance for cleanup purposes.

14.3Factory Methods

Let’s look at the implementation of the two static factory methods in more detail. The overload of NewL() that takes no parameters creates an object of the default implementation of CCryptoInterface. In the example

2 The compiler generates an implicit default constructor when instances of classes deriving from CCryptoInterface are created, in order to construct the virtual function table for the class.

238

ECOM

code below, the method hard-codes a specific implementation (CSoftwareCrypto) by passing ECOM its UID.3 This method of specifying a particular class assumes that the UID of at least one implementation class is known when the factory function for the interface is compiled.

An alternative, more loosely-coupled, technique for instantiating a default implementation uses the ECOM resolver. The resolver can be passed a cue to enable it to instantiate, for example, the first concrete class it discovers which implements that interface. I’ll illustrate how to do this later, when I discuss how to customize the ECOM resolver.

EXPORT_C CCryptoInterface* CCryptoInterface::NewL()

{

// Hard-coded to use CSoftwareCrypto by default const TUid KSWCryptoUid = { 0x10008EE5 };

TAny* defaultCrypto =REComSession::CreateImplementationL(KSWCryptoUid, _FOFF(CCryptoInterface, iDtor_ID_Key));

return (reinterpret_cast<CCryptoInterface*>(defaultCrypto));

}

REComSession::CreateImplementationL() is passed the UID of the required implementation and the offset4 of the iDtor_ID_Key member of the interface class. Don’t worry too much about this ECOMinternal housekeeping, which initializes iDtor_ID_Key so ECOM can later identify the object for cleanup. CreateImplementationL() returns a TAny* which must be re-cast to the interface pointer before returning it to the caller. There are a number of other overloads of

REComSession::CreateImplementationL(), which you’ll find documented in detail in your preferred SDK (from Symbian OS v7.0 onwards).

The second NewL() factory method takes a cue parameter, which it passes to the default ECOM resolver. The resolver uses it to determine the concrete instance of the implementation to be instantiated, by matching the cue against the default_data attributes for registered implementations of that interface. I’ll discuss the role of the default resolver and ECOM resource files in more detail later.

// interface_uid for CCryptoInterface

const TUid KCCryptoInterfaceUid = {0x10008EE0};

3 Implementations are identified by their implementation_uid attribute, which is declared in the resource file associated with the plug-in DLL, as I’ll discuss later in the chapter.

4 The _FOFF macro is defined as follows in e32def.h:

#define _FOFF(c,f) ((TInt)(&((c *)0)->f))

It returns the offset in bytes of a member variable f of class c

FACTORY METHODS

239

EXPORT_C CCryptoInterface* CCryptoInterface::NewL(const TDesC8& aCue) {// Resolution using the default ECOM resolver TEComResolverParams resolverParams; resolverParams.SetDataType(aCue);

// Allows wildcards in the string match resolverParams.SetWildcardMatch(ETrue);

TAny* cryptoInterface = REComSession::CreateImplementationL(KCCryptoInterfaceUid, _FOFF(CCryptoInterface, iDtor_ID_Key), NULL, resolverParams));

return (reinterpret_cast<CCryptoInterface*>(cryptoInterface));

}

Besides the TEComResolverParams object, which encapsulates the resolver cue, other parameters passed to REComSession::CreateImplementationL() include the UID of the requested interface and the offset of iDtor_ID_Key as discussed previously. The third parameter, NULL in the example above, can be used to pass data to the initialization method of the concrete class. If CreateImplementationL() cannot find an appropriate interface implementation for the cue given, it leaves with KErrNotFound.

By calling NewL(), an interface client instantiates an object which implements that interface. The implementation type is either determined by the cue passed into NewL() or is the default type. Because the caller uses the interface to perform instantiation, it does not need information about the class that actually implements that interface. However, REComSession does provide a function, ListImplementationsL(), which returns information about all the implementations of a given interface in an object of type RImplInfoPtrArray. This can be used to provide interface clients with a list of every implementation class available. I’ll illustrate how a client might use this function at the end of this chapter.

EXPORT_C void CCryptoInterface::ListImplementationsL(RImplInfoPtrArray&

aImplInfoArray)

{

REComSession::ListImplementationsL(KCCryptoInterfaceUid,

aImplInfoArray);

}

The CCryptoInterface class also defines a virtual destructor, which calls the ECOM framework, passing iDtor_ID_Key to identify the object. This enables ECOM to perform reference counting and cleanup as necessary. Subclasses will inherit this destructor code, which C++ calls after the destructor of the derived class.

240

ECOM

EXPORT_C CCryptoInterface:: CCryptoInterface()

{// Notify ECOM that this object is being deleted

REComSession::DestroyedImplementation(iDtor_ID_Key);

}

14.4Implementing an ECOM Interface

Having discussed CCryptoInterface, let’s move on to consider how it is implemented. Concrete classes must be defined in an ECOM plugin DLL, which is built with targettype ECOMIIC (which stands for ”ECOM Interface Implementation Collection”). Here’s the .mmp file for the example plug-in DLL:

// ECryptoExample.mmp

TARGET ECryptoExample.dll

TARGETTYPE ECOMIIC

// UID2 = ECOM plug-in DLL recognition, UID3 = unique UID for this DLL UID 0x10009D8D 0x10009EE1

SOURCEPATH .

SOURCE // ... Omitted for clarity

USERINCLUDE // ... Omitted for clarity

SYSTEMINCLUDE \epoc32\include \epoc32\include\ecom

RESOURCE 10009EE1.RSS // The resource file for this implementation

LIBRARY ECOM.lib

//

ECOM plug-in DLLs must link against ECOM.lib

LIBRARY ...

//

Other libraries as required

The plug-in is a polymorphic Symbian OS DLL and must define a standard DLL entry point as follows:

TBool E32Dll()

{

return (ETrue);

}

Within a plug-in DLL, an ECOM interface collection may contain one or more implementations of one or more ECOM interfaces and/or multiple implementations of the same interface. The sample code implements two subclasses of CCryptoInterface.

// implementation_uid = 0x10008EE5 (discussed later)

class CSoftwareCrypto : public CCryptoInterface

{

IMPLEMENTING AN ECOM INTERFACE

241

public:

static CSoftwareCrypto* NewL();

CSoftwareCrypto();

// Implementation using a software cryptography library virtual void EncryptL(TDesC8& aPlaintext, TDesC8& aKey,

TDes8& aCiphertext);

virtual void DecryptL(TDesC8& aCiphertext, TDesC8& aKey, TDes8& aPlaintext);

private:

CSoftwareCrypto(); void ConstructL();

private:

... // Omitted for clarity };

// implementation_uid = 0x10008EE4 (discussed later)

class CHardwareCrypto : public CCryptoInterface

{

public:

static CHardwareCrypto* NewL();

CHardwareCrypto();

// Implementation using hardware & device drivers virtual void EncryptL(TDesC8& aPlaintext, TDesC8& aKey,

TDes8& aCiphertext);

virtual void DecryptL(TDesC8& aCiphertext, TDesC8& aKey, TDes8& aPlaintext);

private:

CHardwareCrypto(); void ConstructL();

private:

... // Omitted for clarity };

Besides the interface functions, every implementation must have an instantiation function which it ”registers” with ECOM. The classes above each define a static NewL() factory function, which uses two-phase construction as described in Chapter 4.

ECOM calls the NewL() factory function of a class when a call to

REComSession::CreateImplementationL() specifies that class directly or a given cue resolves to that implementation.

A plug-in DLL ”registers” these instantiation functions with ECOM by exporting a standard function (ImplementationGroupProxy()) which returns a pointer to an array of TImplementationProxy objects. This is the only function that a polymorphic ECOM plug-in DLL exports. Each TImplementationProxy object represents a single implementation class and contains the TUid which identifies the implementation (this should match the implementation_uid value for the class in its registration resource file) and a pointer to its instantiation method.

#include <ImplementationProxy.h>

// ECOM header file

#include "CHardwareCrypto.h"

// Class definition for CHardwareCrypto

#include "CSoftwareCrypto.h"

// Class definition for CSoftwareCrypto