XLL+ Class Library (6.3)

How handles work

Let us take a moment to examine how the handle mechanism works.

Implementation classes

For the implementation classes discussed below, refer to the header file extensions\RtdHandles.h.

HandleCache

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.

HandleCacheCreator

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.

HandleConverter

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

Global functions

There are several global template functions, including CreateHandleInCache() which is used as follows:

CopyC++
// 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();

Code supplied by the developer

Creating handles

For a function marked with the HandleCreator extension, one additional line of code is generated, e.g.:

CopyC++
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.:

CopyC++
Thing* thing = new Thing(Name, Value, CXlDate::Now());
xloResult = psl::CreateHandleInCache(thing);

Using handles

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.

Next: Requirements and deployment >>