Optional Features Query API

This document details how to query a device for the presence of single features and multiple features using the Feature Registry.

Single feature queries

A single feature Query API is provided by class RFeatureRegistryNotify, declared in featreg.h, supplied by featreg.dll and linked through featreg.lib.

To inquire whether a single feature is supported on the device, use the following static function of class RFeatureRegistry:

static TInt QuerySupportS(TUid aFeatureUid);

This function returns a positive value if the feature is supported, zero if the feature is not supported, otherwise (in the exceptional case) a negative, system-wide error code if support cannot be determined.

You can choose to deal with the error returns locally. For example, by considering the feature not supported:

TBool haveUsb = RFeatureRegistry::QuerySupportS(NFeature::KUsb) > 0;

Alternatively you can choose to Leave on exceptional error returns:

TBool haveUsb =
              User::LeaveIfError(RFeatureRegistry::QuerySupportS(NFeature::KUsb)) > 0;

The Feature Registry maintains an additional 32-bit data word per feature, which can be obtained using an overload of the QuerySupportS function:

static TInt QuerySupportS(TUid aFeatureUid, TUint32& aInfo);

The contents of this extra word are reserved for future use.

Multiple feature queries

The most efficient way to find out if more than one function is supported is to open and query an instance of the RFeatureRegistry class using the following non-static methods of the RFeatureRegistry class:

inline RFeatureRegistry();
TInt Open();
TInt QuerySupport(TUid aFeatureUid);
TInt QuerySupport(TUid aFeatureUid, TUint32& aInfo);
void Close();

RFeatureRegistry also has an overload of non-static QuerySupport, which can return the extra word of data stored with each feature.

An important point about the above non-static APIs is that they only guarantee to return the state of features at the time Open() was called. To ensure that future run-time feature changes are detected, close the instance immediately after querying it, and re-open it next time queries are to be made. This also frees up resources held by the open instance.

Note: Querying features can have an impact on performance. Therefore, if you are querying frequently (for example, in a loop) it is recommended that you cache the query return. However, if the feature is seldom used (once or twice between switching the device on and off), caching is unnecessary.

Optional features query API example

The following code illustrates how to query several features in a non-leaving context (and treating exceptional results as if the feature is not supported).

TBool iHaveUsb;
TBool iHaveBluetooth;
...
RFeatureRegistry featReg;
const TBool opened = (featReg.Open() == KErrNone);
iHaveUsb = opened && (featReg.QuerySupport(NFeature::KUsb) > 0);
iHaveBluetooth = opened && (featReg.QuerySupport(NFeature::KBluetooth) > 0);
// can always call Close(), even if Open() failed:
featReg.Close();

Or if choosing to Leave on exceptional returns:

RFeatureRegistry featReg;
User::LeaveIfError(featReg.Open());
CleanupClosePushL(featReg);               // don’t forget this
iHaveUsb = User::LeaveIfError(featReg.QuerySupport(NFeature::KUsb)) > 0;
iHaveBluetooth =
    User::LeaveIfError(featReg.QuerySupport(NFeature::KBluetooth)) > 0;
CleanupStack::PopAndDestroy(&featReg);    // this calls Close()

Preconditions for Feature Queries

When deciding when and how often to query, you must plan carefully as feature queries will result in a performance overhead. It is recommended that you always query and cache the return value if it is to be used many times in quick succession, particularly in loops. However, if the feature is seldom used (once or twice between switching the device on and off), caching is unnecessary.

Your UI-provider or system integration team must ensure that the Feature Registry has a valid configuration file for the environment you are using, be it an emulator or a target device or reference board.

Where optional features are removed from a device, all effort is made to make the failure of any attempt to use the missing features as graceful as possible. Unless individual features are documented to give particular, safe responses when not supported by a device (through a stub DLL, for example), their use as a means to discover the feature cannot be considered safe unless expressly documented as such. In addition, optional features supplied as plug-ins may be more efficiently detected using the Feature Registry. Finally, even if it works now, there is no guarantee that attempts to use a removed feature in future will not have serious consequences including exceptions, leaves or panics.

Errors and Panics

If the error KErrNoMemory is returned, this means there is insufficient memory to complete the query. If more memory becomes available subsequent queries may succeed.

If the error KErrCorrupt is returned, this is serious. Your UI-provider or system integration team must ensure that the Feature Registry has a valid configuration file for the environment you are using, be it an emulator or a target device or reference board. Refer to the Single feature queries and Multiple feature queries sections for example code on how to allow client programs to continue under such circumstances.

In debug builds you may get panic “FeatReg 1” when you call RFeatureRegistry functions. In release builds, the error value KErrCorrupt is returned instead of a panic. “1” is the enumeration for EFeatRegBadConfig, declared in the exported header file featregpan.h. This issue only occurs within Symbian and licensee organisations, and does not apply to external developers.