Object handles, as implemented in the RtdHandles.xpe
extension,
consist of a set of parts, separated by colons (or other separators),
which combine to form a handle.
The parts include:
{A6CBD52A-040D-4990-89EF-41A6721BADC6}
.
1280298484
.
Using the default handle format, a handle looks like this:
{A6CBD52A-040D-4990-89EF-41A6721BADC6}:1280298484
The developer can implement their own handle formatting class, and thereby take control of the appearance of the handle, by deriving a class from CHandleFormatter<T>.
For example, you can include the type, name and other details of the object being represented:
CustomThing:The name of the thing:{A6CBD52A-040D-4990-89EF-41A6721BADC6}:1280298484YieldCurve:USD:Govt:{A6CBD52A-040D-4990-89EF-41A6721BADC6}:1280298484
This makes for much more user-friendly handles; it becomes much easier to understand the structure of a spreadsheet that uses handles, and to track down problems.
If you do not specify a separator, then a colon is used. If you have handles that need to include colons, you can specify a different separator by passing it to the constructor of the base class, e.g.:
YieldCurve~USD:Govt~{A6CBD52A-040D-4990-89EF-41A6721BADC6}~1280298484YieldCurve/USD:Govt:Short/{A6CBD52A-040D-4990-89EF-41A6721BADC6}/1280298484
A class derived from CHandleFormatter<T> must implement the two conversion functions:
MakeHandle and
SplitHandle.
If the class has a destructor, it must be declared as virtual
.
The example code below can be found in the RtdHandleDemo sample. Here is the simple object which will be used with a custom handle formatter:
class CustomThing { public: CustomThing(const TCHAR* name_, int value_, double created_) : name(name_), value(value_), created(created_) { } std::tstring name; int value; double created; };
We will define a custom handle formatter class, which creates handles that include the target object's type and name, e.g.:
CustomThing/Gregory/{A6CBD52A-040D-4990-89EF-41A6721BADC6}/1280298484
The class implements the two required virtual methods, SplitHandle()
and MakeHandle().
The code is based on the implementations in the base class, which can be found
in include\XlRtdHandles\HandleFormatter.h
.
In addition, the constructor passes a forward slash to the base class constructor, to be used as a separator character.
class CustomThingHandleFormatter : public psl::rtd::CHandleFormatter<CustomThing> { public: // The constructor specifies a forward slash as the separator character CustomThingHandleFormatter() : psl::rtd::CHandleFormatter<CustomThing>(_T('/')) { } virtual bool SplitHandle(const TCHAR* pszHandle, std::tstring& strKey, long& lState) { // Extract the required parts: the guid key and the state // which are at positions 2 & 3 respectively. // The base class method ExtractKeyAndState() method does all the work. return ExtractKeyAndState(pszHandle, strKey, lState, 2, 3); } virtual std::tstring MakeHandle(const CustomThing* t, const TCHAR* pszKey, long lState) { // Create a handle: [Class]/[Name]/[GUID]/[State] // This code is based on that in the parent class, // with an additional 2 key parts inserted at the start // of the handle. std::vector<std::tstring> parts; // 1st, the class parts.push_back(_T("CustomThing")); // 2nd, the name. Note that the base class // method Escape() is used to remove any separator characters. parts.push_back(Escape(t->name)); // 3rd and fourth, the GUID and the state. // These two parts are required, but can be in any position. // We put them at the end of the handle, because they are not // interesting to the user, and we therefore do not care much // if they are not visible. parts.push_back(pszKey); parts.push_back(WriteState(lState)); // Join the parts together and return the concatenated string. return Join(parts); } };
Finally, in the OnXllOpen() event handler, we register the custom formatter with the single instance of HandleCache<CustomThing>:
BOOL CRtdHandleDemoApp::OnXllOpenEx() { // Install the custom handle formatter, for CustomThings. psl::HandleCache<CustomThing>::GetOrCreateInstance()->SetFormatter( new CustomThingHandleFormatter()); return TRUE; }