You may have some standard code that you use in most or all of your add-in functions. You can transfer responsibility for writing the code to the XLL+ code generator by writing and registering a Function extension.
Typical uses of function extensions include:
When a function extension is registered, it appears in the XLL+ Function Wizard and in the Properties window, as an option that can be applied to any add-in function.
For example, if we register an extension named Trace, which writes to the debug console every time a function is used, we can see it in the function's Features list.
If we put a check against it, then additional lines will be injected into the generated code:
CXlOper* StringFn_Impl(CXlOper& xloResult, const CXlStringArg& Product_op) { TRACE(_T("Entering StringFn\n")); // Input buffers CString Product; // Validate and translate inputs XlReadScalarEx(Product_op, Product, psl::FixedLengthStringConverter(), CScalarConvertParams<CString>(L"Product", 0, 0, -1).SetIntParam(0, 4)); TRACE(_T("Validated StringFn\n")); // End of trace // End of generated code //}}XLP_SRC ... }
If at a later time you want to remove the extra code, you can use the Function Wizard or the Properties window to turn the extension off.
Extension code can be injected at various places in an add-in function.
Insertion point | Description |
---|---|
BeforeValidation | At the start of the common implementation function, before any validation code is called. |
AfterValidation | In the common implementation function, immediately after all validation code has been called. |
BeforeTryCatch | At the start of each wrapper function before the try-catch block that calls the common implementation function. |
AfterCatchException | In each wrapper function, after the try-catch block that calls the common implementation function. (This is a good place to catch exceptions that are not derived from CXlRuntimeException.) |
BeforeMacro | Outside any function definition, in a global context, just before the IMPLEMENT_XLLFN3 macro. |
AfterMacro | Outside any function definition, in a global context, just after the IMPLEMENT_XLLFN3 macro, and before the wrapper functions. |
In the example above, TRACE
statements were injected at
BeforeValidation
and AfterValidation
.
The full syntax of function extensions can be found in the reference here.
The critical part of the extension's definition is the code that is to be injected. You can use macros that will be substituted by the code generation engine, and allow you to generate data that is specific to the add-in function being extended.
For example, the Trace
extension above uses the
add-in function's name:
TRACE(_T("Entering $#ExportedName$\n"));
The generator will replace $#ExportedName$
with the value of
the add-in function's ExportedName property.
You can find a list of function properties in the reference.
See the Profiling sample for an example of a function extension in action.
For more examples of function extensions see the files in the
extensions
directory.