(v13) RDR Example: API detection and redefinition
This page applies to Harlequin v13.1r0 and later; both Harlequin Core and Harlequin MultiRIP
It is possible to reveal APIs as RDRs. This allows a module controller to redefine an API implementation, but also allows multiple versions of an API to coexist without confusion.
For example, the sw_data_api
implementor could publish its code like this:
SwRegisterRDR(
RDR_CLASS_API, RDR_API_DATA, 20071111,
sw_data_api_virtual, sizeof(sw_data_api_virtual), SW_RDR_DEFAULT
) ;
Note that sizeof
() is not usually important unless the thing pointed to can be different lengths, such as an array or a subclassed (extended) structure. To be generally useful with multiple API versions, versioned API struct definitions are also required, so sw_data_api_20071111 and sw_data_api_20110502 can exist simultaneously.
Anything that requires the data API would find it like this:
sw_data_api_20071111 * data_api = NULL ; void * ptr ;
if (SwFindRDR(RDR_CLASS_API, RDR_API_DATA, 20071111,
&ptr, NULL) == SW_RDR_SUCCESS)
data_api = ptr ;
Obviously, multiple versions of an API can coexist simultaneously without requiring code that uses those APIs to be changed when a newer version is added, and the newer version does not necessarily need to be backwards compatible.
This also allows a module controller to temporarily override an API with its own implementation during its module's initialization. Significantly, if it subsequently becomes necessary to override some other API that module implementation may already be using, no change to the module or the API is required the module controller just overrides that API too. For example:
sw_data_api_20071111 my_data_api = { /* Our version of a standard API
*/
...
my_get_indexed, my_set_indexed,
...
my_open_blob
} ;
/* Override that API */
SwRegisterRDR(RDR_CLASS_API, RDR_API_DATA, 20071111,
my_data_api, sizeof(my_data_api), SW_RDR_OVERRIDE) ;
/* Initialise our module, during which time it may ask for this API */ initialise_my_module(...) ;
/* Deregister the API so nothing else gets our version */ SwDeregisterRDR(RDR_CLASS_API, RDR_API_DATA, 20071111,
my_data_api, sizeof(my_data_api)) ;
Note, therefore, that such a module must find its APIs during its initialization and store them for later use, rather than finding them later.
The OEM can extend or modify a supplied API by finding the original with SwFindRDR
, copying it, then registering a replacement with a higher priority. A cloned API's lifetime would have to match that of the module that may be using it.