Basic APIs

Accessing APIs and basic functions in kernel-side programs.

Device drivers, like user-side programs, need to use APIs for basic tasks such as managing buffers and arrays. However, the EKA2 architecture does not allow kernel-side programs such as drivers to link and use the User Library (euser.dll) that provides these APIs to user-side programs. This means kernel side code cannot use the majority of classes and functions that are available to user side code.

However, some classes are available for use on both the user side and the kernel side. The first section of this document, Available EUSER functionality, explains what these are. In other cases, there are alternative Kernel-specific APIs or techniques that you can use. The second section, Coding techniques to replace EUSER functionality, describes these.

The detailed contents are given below:

Contents

Available EUSER functionality

This is a list of USER side classes, types and APIs that can still be used on the kernel side. However, a subset of the class member functions may not be available.

8-bit descriptors

The following classes, defined in e32des8.h, can be used on the kernel side.

For some classes, the kernel side can use the same member functions that are available to the user side. However, for other classes, the kernel side is restricted to using a subset of functions; where this is the case, the functions are listed

Classes available

Public member functions that are available to kernel side code

TDesC8

TInt operator<(const TDesC8 &aDes) const;

TInt operator<=(const TDesC8 &aDes) const;

TInt operator>(const TDesC8 &aDes) const;

TInt operator>=(const TDesC8 &aDes) const;

TInt operator==(const TDesC8 &aDes) const;

TInt operator!=(const TDesC8 &aDes) const;

const TUint8 &operator[](TInt anIndex) const;

TInt Length() const;

TInt Size() const;

const TUint8 *Ptr() const;

TInt Compare(const TDesC8 &aDes) const;

TInt Match(const TDesC8 &aDes) const;

TInt MatchF(const TDesC8 &aDes) const;

TInt MatchC(const TDesC8 &aDes) const;

TInt Locate(TChar aChar) const;

TInt LocateReverse(TChar aChar) const;

TInt Find(const TDesC8 &aDes) const;

TInt Find(const TUint8 *pS,TInt aLenS) const;

TPtrC8 Left(TInt aLength) const;

TPtrC8 Right(TInt aLength) const;

TPtrC8 Mid(TInt aPos) const;

TPtrC8 Mid(TInt aPos,TInt aLength) const;

TInt CompareF(const TDesC8 &aDes) const;

TDes8

TDes8& operator=(const TUint8 *aString);

TDes8& operator=(const TDesC8 &aDes);

TDes8& operator=(const TDes8 &aDes);

TInt MaxLength() const;

TInt MaxSize() const;

const TUint8 &operator[](TInt anIndex) const;

TUint8 &operator[](TInt anIndex);

TDes8 &operator+=(const TDesC8 &aDes);

void Zero();

void SetLength(TInt aLength);

void SetMax();

void Copy(const TDesC8 &aDes);

void Copy(const TUint8 *aBuf,TInt aLength);

void Copy(const TUint8 *aString);

void Copy(const TDesC16 &aDes);

void Append(TChar aChar);

void Append(const TDesC8 &aDes);

void Append(const TDesC16 &aDes);

void Append(const TUint8 *aBuf,TInt aLength);

void Fill(TChar aChar);

void Fill(TChar aChar,TInt aLength);

void FillZ();

void FillZ(TInt aLength);

void Num(TInt64 aVal);

void Num(TUint64 aVal, TRadix aRadix);

void NumFixedWidth(TUint aVal,TRadix aRadix,TInt aWidth);

void AppendNum(TInt64 aVal);

void AppendNum(TUint64 aVal, TRadix aRadix);

void AppendNumFixedWidth(TUint aVal,TRadix aRadix,TInt aWidth);

TPtrC8

Same as for user side code.

TPtr8

Same as for user side code.

TBufC8

Same as for user side code.

TBuf8

Same as for user side code.

TDes8Overflow

Same as for user side code.

TLitC8

Same as for user side code.

Arrays

The following classes, defined in e32cmn.h, can be used on the kernel side.

For some classes, the kernel side can use the same member functions that are available to the user side. However, for other classes, the kernel side is restricted to using a subset of functions; where this is the case, the functions are listed

Classes available

Public member functions that are available to kernel side code

RArray <class T>

RArray();

RArray(TInt aGranularity);

RArray(TInt aGranularity, TInt aKeyOffset);

RArray(TInt aMinGrowBy, TInt aKeyOffset, TInt aFactor);

void Close(); inline TInt Count() const;

const T& operator[](TInt anIndex) const;

T& operator[](TInt anIndex);

TInt Append(const T& anEntry);

TInt Insert(const T& anEntry, TInt aPos);

void Remove(TInt anIndex);

void Compress();

void Reset();

TInt Find(const T& anEntry) const;

TInt Find(const T& anEntry, TIdentityRelation<T> anIdentity) const;

TInt FindInSignedKeyOrder(const T& anEntry) const;

TInt FindInUnsignedKeyOrder(const T& anEntry) const;

TInt FindInOrder(const T& anEntry, TLinearOrder<T> anOrder) const;

TInt FindInSignedKeyOrder(const T& anEntry, TInt& anIndex) const;

TInt FindInUnsignedKeyOrder(const T& anEntry, TInt& anIndex) const;

TInt FindInOrder(const T& anEntry, TInt& anIndex, TLinearOrder<T> anOrder) const;

TInt SpecificFindInSignedKeyOrder(const T& anEntry, TInt aMode) const;

TInt SpecificFindInUnsignedKeyOrder(const T& anEntry, TInt aMode) const;

TInt SpecificFindInOrder(const T& anEntry, TLinearOrder<T> anOrder, TInt aMode) const;

TInt SpecificFindInSignedKeyOrder(const T& anEntry, TInt& anIndex, TInt aMode) const;

TInt SpecificFindInUnsignedKeyOrder(const T& anEntry, TInt& anIndex, TInt aMode) const;

TInt SpecificFindInOrder(const T& anEntry, TInt& anIndex, TLinearOrder<T> anOrder, TInt aMode) const;

TInt InsertInSignedKeyOrder(const T& anEntry);

TInt InsertInUnsignedKeyOrder(const T& anEntry);

TInt InsertInOrder(const T& anEntry, TLinearOrder<T> anOrder);

TInt InsertInSignedKeyOrderAllowRepeats(const T& anEntry);

TInt InsertInUnsignedKeyOrderAllowRepeats(const T& anEntry);

TInt InsertInOrderAllowRepeats(const T& anEntry, TLinearOrder<T> anOrder);

RArray <TInt>

RArray();

RArray(TInt aGranularity);

RArray(TInt aMinGrowBy, TInt aFactor);

void Close();

TInt Count() const;

const TInt& operator[](TInt anIndex) const;

TInt& operator[](TInt anIndex);

TInt Append(TInt anEntry);

TInt Insert(TInt anEntry, TInt aPos);

void Remove(TInt anIndex);

void Compress();

void Reset();

TInt Find(TInt anEntry) const;

TInt FindInOrder(TInt anEntry) const;

TInt FindInOrder(TInt anEntry, TInt& anIndex) const;

TInt SpecificFindInOrder(TInt anEntry, TInt aMode) const;

TInt SpecificFindInOrder(TInt anEntry, TInt& anIndex, TInt aMode) const;

TInt InsertInOrder(TInt anEntry);

TInt InsertInOrderAllowRepeats(TInt anEntry);

RArray <TUint>

RArray();

RArray(TInt aGranularity);

RArray(TInt aMinGrowBy, TInt aFactor);

void Close();

TInt Count() const;

const TUint& operator[](TInt anIndex) const;

TUint& operator[](TInt anIndex);

TInt Append(TUint anEntry);

TInt Insert(TUint anEntry, TInt aPos);

void Remove(TInt anIndex);

void Compress();

void Reset();

TInt Find(TUint anEntry) const;

TInt FindInOrder(TUint anEntry) const;

TInt FindInOrder(TUint anEntry, TInt& anIndex) const;

TInt SpecificFindInOrder(TUint anEntry, TInt aMode) const;

TInt SpecificFindInOrder(TUint anEntry, TInt& anIndex, TInt aMode) const;

TInt InsertInOrder(TUint anEntry);

TInt InsertInOrderAllowRepeats(TUint anEntry);

RPointerArray <class T>

RPointerArray();

RPointerArray(TInt aGranularity);

RPointerArray(TInt aMinGrowBy, TInt aFactor);

void Close();

TInt Count() const;

T* const& operator[](TInt anIndex) const;

T*& operator[](TInt anIndex);

TInt Append(const T* anEntry);

TInt Insert(const T* anEntry, TInt aPos);

void Remove(TInt anIndex);

void Compress();

void Reset();

void ResetAndDestroy();

TInt Find(const T* anEntry) const;

TInt Find(const T* anEntry, TIdentityRelation<T> anIdentity) const;

TInt FindInAddressOrder(const T* anEntry) const;

TInt FindInOrder(const T* anEntry, TLinearOrder<T> anOrder) const;

TInt FindInAddressOrder(const T* anEntry, TInt& anIndex) const;

TInt FindInOrder(const T* anEntry, TInt& anIndex, TLinearOrder<T> anOrder) const;

TInt SpecificFindInAddressOrder(const T* anEntry, TInt aMode) const;);

TInt SpecificFindInOrder(const T* anEntry, TLinearOrder<T> anOrder, TInt aMode) const;

TInt SpecificFindInAddressOrder(const T* anEntry, TInt& anIndex, TInt aMode) const;

TInt SpecificFindInOrder(const T* anEntry, TInt& anIndex, TLinearOrder<T> anOrder, TInt aMode) const;

TInt InsertInAddressOrder(const T* anEntry);

TInt InsertInOrder(const T* anEntry, TLinearOrder<T> anOrder);

TInt InsertInAddressOrderAllowRepeats(const T* anEntry);

TInt InsertInOrderAllowRepeats(const T* anEntry, TLinearOrder<T> anOrder);

TIdentityRelation <class T>

Same as for user side code.

TLinearOrder <class T>

Same as for user side code.

Character representation

The following class, defined in e32cmn.h, can be used on the kernel side.

For some classes, the kernel side can use the same member functions that are available to the user side. However, for other classes, the kernel side is restricted to using a subset of functions; where this is the case, the functions are listed

Classes available

Public member functions that are available to kernel side code

TChar

TChar();

TChar(TUint aChar);

TChar& operator-=(TUint aChar);

TChar& operator+=(TUint aChar);

TChar operator-(TUint aChar);

TChar operator+(TUint aChar);

operator TUint() const;

Basic utility functions and classes

The following global utility functions and classes, defined in e32cmn.h, can be used on the kernel side.

TRefByValue

TInt Lim(TInt aVal,TUint aLimit);

TInt LimX(TInt aVal,TUint aLimit);

template <class T> T Min(T aLeft,T aRight);

template <class T> T Min(T aLeft,TUint aRight);

template <class T> T Max(T aLeft,T aRight);

template <class T> T Max(T aLeft,TUint aRight);

template <class T> T Abs(T aVal);

template <class T> TBool Rng(T aMin,T aVal,T aMax);

template <class T,class S> T* PtrAdd(T* aPtr,S aVal);

template <class T,class S> T* PtrSub(T* aPtr,S aVal);

template <class T> T Align2(T aValue);

template <class T> T Align4(T aValue);

The Package Buffers API

The package buffers API, represented by classes defined in e32cmn.h, can be used on the kernel side.

The UID manipulation APIs

The UID manipulation APIs, represented by classes defined in e32cmn.h can be used on the kernel side. However, only a subset of functions are available. See the detailed notes in the following table.

TUid

Only the two inline functions can be used:

TUidType

None of the member functions can be used; however, the iUid data member is declared as public on the kernel side.

TUidName

This will only ever be an 8-bit type descriptor.

Version handling API

The version handling API, represented by the TVersion class defined in e32cmn.h can be used on the kernel side.

TRequestStatus

The TRequestStatus class representing the completion status of an asynchronous request, and defined in e32cmn.h can be used on the kernel side.

TIpcArgs

The TIpcArgs class, which is part of the Version2 client/server APIs, and defined in e32cmn.h, can be used on the kernel side. However, the Set() and Type() member functions that take 16-bit descriptors are not available.

Basic graphic classes

The basic graphic classes TPoint and TSize are defined on the kernel side. However, only the public data members are defined - the member functions are not defined, and are not available for use.

Coding techniques to replace EUSER functionality

Buffers: replacing HBufC8 with HBuf

In EKA2, the heap descriptor buffer, HBufC8 is not available. However, the kernel side defines and implements an equivalent (kernel) heap descriptor buffer: HBuf8. HBuf8 is behaves in a similar way to HBufC8, so nearly all of your code can be reused, but note the following points:

  • If your code uses the typedef HBufC, then you need to change it to HBuf.

  • On the kernel side, there is no explicit support for 16-bit buffers, which means that there is no class called HBuf16. In practice, this means that, HBuf is always the same as HBuf8.

  • Unlike HBufC8, HBuf8 is a modifiable type descriptor. It has TDes8 in its derivation hierarchy, and this means that you can manipulate the descriptor's data (using the TDes8 member functions).

  • The number of functions available to create an HBuf8 object is more limited than for HBufC8 - there are only three variants - although in practice this is not a problem:

    • HBuf8::New(TInt aMaxLength) to allocate a heap descriptor buffer (on the kernel heap) and set its length to zero; this behaves the same as the user side HBufC8::New(TInt aMaxLength)

    • HBuf8::New(const TDesC8& aDes) to allocate a heap descriptor buffer (on the kernel heap) and initialise it by copying an existing descriptor's data into it.

    • HBuf8::ReAlloc(TInt aNewMax) to re-allocate (i.e. to resize) a heap descriptor buffer (on the kernel heap); this behaves the same as the user side HBufC8::New(TInt aMaxLength)

  • There are no "leaving" variants of these functions - if you have NewL(), NewLC(), and other "leaving" variants, then you will need to change your code to explicitly check the return code to make sure that the creation, or the reallocation of the heap descriptor buffer has worked.

  • As the descriptor is modifiable, there is no need for, and there is no equivalent of the function HBufC8::Des(); you just use the base class TDes8 functions.

  • If your code uses the assignment operators (i.e. the = operator), you don't need to change your code; the compiler will use the operators implemented in the TDes8 base class, which will do the right thing.

  • The descriptor function TDesC8::Alloc() is no longer available on the kernel side, so you cannot create a heap descriptor buffer from a general descriptor.

The following code fragments show code that is approximately equivalent between EKA1 and EKA2. The fragments are a little artificial, and make assumptions that would not necessarily be made in real code, but nevertheless still show the essential differences.

EKA1

EKA2

This is a function that allocates a heap descriptor buffer (HBufC8), puts data into it, changes its size, replaces the data, deletes a part of the data, and then deletes it.

_LIT8(KTxSmall,"abcdef");
_LIT8(KTxBig,"ghijklmnopqrstuvwxyz");

void X::FunctionL()
    {
    // Create a buffer big enough to contain
    // the text "abcdef".
    // This uses the "leaving" variant, and leaves
    // if there is insufficient memory.
    HBufC8* pBuf = HBufC8::NewL(KTxSmall().Length());

    // Copy the text "abcdedf" into it
    *pBUf = KTxSmall;
        
    // Make the buffer bigger...
    // ... and check that it worked OK
    // Note that we are using the non-leaving version.
    // We could use the leaving version, but we would
    // need to handle the cleanup of pBuf 
    HBuf8* pNewBuf = pBuf->ReAlloc(KTxBig().Length());;

    if (pNewBuf)
        {
        pBuf = pNewBuf;
        }
     else
        {
        delete pBuf;
        User::Leave(KErrNoMemory);
        }

    // Replace content of the descriptor with 
    // the text "ghijkl......"
    *pBuf = KTxBig;

    // Need to use the Des() function to create 
    // a modifiable descriptor before we can make
    // changes to the text in the descriptor.
    TPtr8 pDesPtr;
    pDesPtr = pBuf->Des();

    // Delete the 1st two characters.
    PDesPtr.Delete(0,2)
     
    delete pBUf;

    return;
    }

A similar function, but it uses HBuf8 instead.

_LIT8(KTxSmall,"abcdef");
_LIT8(KTxBig,"ghijklmnopqrstuvwxyz");

TInt X::Function()
    {
    // Create a buffer big enough to contain
    // the text "abcdef", and copy the text
    // from its source into the buffer.
    //
    // You need to check explicitly that this
    // has worked.
    HBuf8* pBuf = HBuf8::New(KTxSmall);
    if (!pBuf)
        {
        return KErrNoMemory;
        }
        
    // Make the buffer bigger...
    // .. and check that it worked OK
    HBuf8* pNewBuf = pBuf->ReAlloc(KTxBig().Length());

    if (pNewBuf)
        {
        pBuf = pNewBuf;
        }
     else
        {
        delete pBuf;
        return KErrNoMemory;
        }

    // You can still use the =operator to replace 
    // the content of the heap descriptor !
    // Replace content with 
    // the text "ghijkl......"
    *pBuf = KTxBig;


    // Can now use use the TDes8 functions
    // directly.
    // This deletes the 1st two characters.
    pBuf->Delete(0,2);

    // delete the heap descriptor
    delete pBUf;

    return KErrNone;
    }

A small code fragment that uses TDesC8::Alloc() to create an HBufC8 heap descriptor buffer from an existing descriptor.

HBufC8* X::Function(const TDesC8& aDes)
    {
    // Returns NULL if creation
    // of the heap descriptor buffer fails.

    return aDes.Alloc();
    }

or possibly:

HBufC8* X::FunctionL(const TDesC8& aDes)
    {
    // Leaves if creation of the heap
    // descriptor buffer fails, otherwise it 
    // returns a valid pointer.

    return(aDes.AllocL());
    }

An equivalent code fragment that creates an HBuf8 heap descriptor buffer.

HBuf8* X::Function(const TDesC8& aDes)
    {
    // Returns NULL if creation
    // of the heap descriptor buffer fails.
   
    return (HBuf8::New(aDes));
    }

Buffers: replacing HBufC8 with C style pointers

Instead of replacing HBufC8 with HBuf, it may be more suitable to replace your heap descriptor buffers with C style pointers - effectively managing your buffers in open code or as part of the implementation of your own purpose written classes.

You allocate memory from the kernel heap using Kern::Alloc() or Kern::AllocZ() and track the pointers to that memory. The following code fragments show how the use of HBufC8 translates to the direct use of these functions.

Although the EKA2 code here uses memcpy(), and memmove(), you will also find the functions memclr(), memset(), wordmove() and memcompare() useful in your code.

EKA1

EKA2

This is a function that allocates a heap descriptor buffer (HBufC8), puts data into it, changes its size, replaces the data, deletes a part of the data, and then deletes the whole buffer.

_LIT8(KTxSmall,"abcdef");
_LIT8(KTxBig,"ghijklmnopqrstuvwxyz");

void X::FunctionL()
    {
    // Create a buffer big enough to contain
    // the text "abcdef".
    // This uses the "leaving" variant, and leaves
    // if there is insufficient memory.
    HBufC8* pBuf = HBufC8::NewL(KTxSmall().Length());

    // Copy the text "abcdedf" into it
    *pBUf = KTxSmall;
        
    // Make the buffer bigger...
    // ... and check that it worked OK
    // Note that we are using the non-leaving version.
    // We could use the leaving version, but we would
    // need to handle the cleanup of pBuf 
    HBuf8* pNewBuf = pBuf->ReAlloc(KTxBig().Length());;

    if (pNewBuf)
        {
        pBuf = pNewBuf;
        }
     else
        {
        delete pBuf;
        User::Leave(KErrNoMemory);
        }

    // Replace content of the descriptor with 
    // the text "ghijkl......"
    *pBuf = KTxBig;

    // Need to use the Des() function to create 
    // a modifiable descriptor before we can make
    // changes to the text in the descriptor.
    TPtr8 pDesPtr;
    pDesPtr = pBuf->Des();

    // Delete the 1st two characters.
    PDesPtr.Delete(0,2)
     
    delete pBUf;

    return;
    }

A similar function, but allocates memory on the kernel heap explicitly, and manages its own pointers instead. Note the use of the nanokernel utility function: memcpy(), and memmove()

_LIT8(KTxSmall,"abcdef");
_LIT8(KTxBig,"ghijklmnopqrstuvwxyz");

TInt X::Function()
    {
    // Create a buffer big enough to contain
    // the text "abcdef", and copy the text
    // from its source into the buffer.
    //
    // Steps.
    // 1. work out the size of buffer needed
    // 2. Get the buffer.
    // 3. Copy the source.

    TInt lengthInBuffer = 0;
     
    // 1.
    TInt Smallsize;
    SmallSize = KTxSmall().Length();
    lengthInBuffer = SmallSize;

    // 2.
    TUint8* pBuf;
    pBuf = Kern::Alloc(SmallSize);
    if (!pBuf)
        {
        return KErrNoMemory;
        }

    // 3.
    memcpy(pBuf,KTxSmall().Ptr(),SmallSize));


    // Make the buffer bigger.
    // If it works ok, then copy the data
    // to the new buffer, delete the old buffer
    TInt BiggerSize;
    TUint8* pNewBuf;

    BiggerSize = KTxBig().Length();
    pNewBuf = Kern::Alloc(BiggerSize);
    if (pNewBuf)
        {
        memcpy(pNewBuf, pBuf, SmallSize);
        Kern::Free(pBuf);
        pBuf = pNewBuf;       
        }
     else
        {
        Kern::Free(pBuf);
        return KErrNoMemory;
        }
     lengthInBuffer = BiggerSize;

    // Replace content with 
    // the text "ghijkl......"
    memcpy(pNewBuf, KTxBig().Ptr(), BiggerSize);
   

    // Delete 1st two characters 
    memmove(pNewBuf, pNewBuf+2, lengthInBuffer;
    lengthInBuffer -= 2;
   
    Kern::Free(pBuf);

    return KErrNone;
    }

Handling 16-bit data items

If you need to handle 16-bit items on the kernel side, then you can still use 8-bit heap descriptor buffers. You just need to be aware that the data is 16 bit and cast accordingly. The following code fragments are simplistic, but show you the basic idea.

EKA1

EKA2

This is a function which is passed a 16-bit descriptor containing 16-bit wide characters.

void X::FunctionL(const TDes16& aDes)
    {
    HBuf16* pBuf = aDes.AllocL();

    TInt     noOfCharacters;
    TUint16* pointerToData;

    noOfCharacters = pBuf->Length();
    pointerToData  = pBuf->Ptr();

    ...
    }

This is a similar function which is also passed 16-bit wide characters. The function needs slight changes as it can only receive data through an 8-bit descriptor.

TInt X::Function(const TDes8& aDes)
    {
    HBuf8* pBuf = HBuf8::New(aDes);
    if (!pBuf)
       {
       return KErrNoMemory;
       }

    TInt     noOfCharacters;
    TUint16* pointerToData;
     
    noOfCharacters = ((pBuf->Length()) >> 1);
    pointerToData  = (TUint16*)(pBuf->Ptr());

    ...

    return KErrNone;
    }

Replacing CBase with DBase

The DBase class is the kernel-side equivalent of the user-side CBase class. It provides zero-filling of memory prior to object construction and a virtual destructor in a similar way to CBase.

If you have a class derived from CBase, then all you need to do is:

  • change your class definition so that it is derived from DBase.

  • Remember to include the klib.h header file.

you should not need to do anything else.

One additional feature provided by DBase that is not available in CBase is the function DBase::AsyncDelete(). This allows you to delete an instance of a DBase derived class asynchronously, and is useful if you need to delete a DBase derived object in time-critical code.

Internally, asynchronous deletion works by placing the object to be deleted onto a queue, and then triggering a DFC, which runs in the context of the supervisor thread. This means that only a small amount of code is executed by your (the calling) thread, and the actual deletion is done by the supervisor thread.

Its use is straightforward.

class DMyObject : public DBase
    {
    ...
    }
DMyObject pPtr;
    ...
    pPtr = new DMyObject;
    ...
    pPtr->AsyncDelete();
    ...

Replacing User::QueryVersionSupported() with Kern::QueryVersionSupported()

User::QueryVersionSupported() is replaced by Kern::QueryVersionSupported() on the kernel side.

The parameters passed to these functions are the same, both in type and meaning. The behaviour of both functions is also the same. This means that all you need to do is replace User:: with Kern:: in your code.