Let us take a moment to examine how the handle mechanism works.
For the implementation classes discussed below, refer to the header file
extensions\RtdHandles.h
.
Most of the work is done by the HandleCache<T>
class (where T
is the class of object being represented by
a handle). This object holds and "owns" all of the objects
of a particular type, and converts them to and from handles.
It is also responsible for releasing them during clean-up.
HandleToPtr() attempts to convert a handle
to a pointer to T
.
If the handle is valid, and refers to an item in the HandleCache,
then it is successfully converted.
This is the method invoked when converting a handle argument
received from Excel to a T*
pointer.
Conversely, CreateHandleInCache() converts a pointer to a handle, and adds the object to the HandleCache. This is the method invoked by functions that return handles.
HandleCache<T>
is a singleton (i.e. only one
instance may exist).
If no instance exists, then the XLL+ framework will create one at run-time.
The public methods of the class are thread-safe, protected by the
CXlLockable embedded in the cache.
This simple class connects an add-in function (that has been marked with the HandleCreator extension) to the handle cache for its particular handle type.
This is the converter class for the Handle extended type.
It is derived from CXlUserConverterBase<const T*, double>
,
meaning that it converts a numeric value to a const T*
pointer.
(See Extended types
and CXlUserConverterBase for more
on converter classes.)
The implementation method, ConvertFromExcel()
uses HandleCache::HandleToPtr()
to do all the work
of validation and conversion.
The error helper method GetTypeNameW()
returns the
name of the handle type, so that appropriate error messages can
be generated, e.g.:
#ERROR: Expected handle to Thingamajig for X
There are several global template functions, including CreateHandleInCache() which is used as follows:
// Add a Thing to the cache and return its handle Thing* thing = new Thing(Name, Value, CXlDate::Now()); xloResult = psl::CreateHandleInCache(thing); return xloResult.Ret();
For a function marked with the HandleCreator extension, one additional line of code is generated, e.g.:
psl::HandleCacheCreator<Thing> handleCache__Thing__Thing_Create(L"Thing", L"Thing.Create");
This constructs a global HandleCacheCreator<Thing>
object.
This object in turn causes a HandleCache<Thing>
to be created (if it does not already exist), and tags it with the
name of the add-in function.
The developer must simply write the code that adds the newly created
object to the HandleCache
, by calling the global template
function, psl::CreateHandleInCache(T*)
, e.g.:
Thing* thing = new Thing(Name, Value, CXlDate::Now());
xloResult = psl::CreateHandleInCache(thing);
The Handle extended type does all its work through its
converter class, HandleConverter
, discussed above.
No additional code needs to be supplied by the developer.