The xll library makes it simple to call C, C++, or even Fortran code from Excel. It is much easier to use than the Microsoft Excel Software Development Kit. There are newer technologies available using C# and JavaScript that are appropriate for certain problems, but if you need the highest possible numerical performance from Excel this library is for you.
Plug your code, or a third party library, into Excel by
writing a thin wrapper that gathers arguments from Excel, call any function, and return the result.
Use the full power of Excel to explore and perfect your code.
Anyone can use your handiwork by opening the self-contained .xll
file you produce.
The xll library can also generate documentation integrated into Excel's help system. People using your code can use the Function Wizard and click on Help with this function. to see how you documented the code you wrote.
The major usability enhancement for developers in the latest version is that all strings are now UTF-8. They are a L"ot" nicer to use than wide character strings. The library still provides high performance access to numeric arrays and lets you easily create handles for embedding C++ objects. This lets you use Excel to orchestrate code operating on memory up to machine limits that runs at native speed. You can also use single inheritance to make your software more convenient to use.
Windows 10 or Windows 11
The Excel SDK is not supported on MacOS. You will have to install
a Windows virtual machine
on your Mac. I've had success with VirtualBox.
Visual Studio
Use the Community Edition and install the Desktop development with C++
and
GitHub Extension for Visual Studio
workload.
Microsoft Excel
Install the 64-bit version of Office Microsoft 365 for the best experience.
Use this template to generate a new repository.
Open in Visual Studio and double click on the solution (.sln
).
Press F5
to build the add-in and start Excel with it loaded in the debugger.
If your add-in does not load you should check your security settings.
From the File
tab select Options
, then Trust Center
. Click on the Trust Center Settings...
button.
Select Macro Settings
and choose Enable VBA Macros
. Do not open add-ins you do not trust.
If you download an xll from the web you may have to right click on it, Properties
and choose
Unblock
at the bottom of the dialog.
The xll::AddIn
class is used to register Excel functions and macros.
AddIn
objects should be defined at the
global scope
so they will be
constructed
when the xll is loaded. The constructors store information Excel needs when
xlAutoOpen
is called.
The xll library
implements
this for you.
To register a new C++ add-in function that can be called from Excel create
an AddIn
object with a Function
argument that has information Excel needs to register your
function: the return type, the C++ function name, the Excel name, and
a list of arguments with their type, name, and short description.
You can optionally specify function help for the Function Wizard and
the category Excel should use.
If you have documentation available at a URL then
provide a link to a help topic.
This library uses UTF-8 instead of multibyte character sets and Unicode (UTF-16, UCS-2). The Unicode wars are over, the dust has settled, and UTF-8 is the clear winner. Joel can get you up to speed.
#include <cmath>
// Uncomment to build for versions of Excel prior to 2007.
// #define XLL_VERSION 4
#include "xll/xll.h"
using namespace xll;
AddIn xai_tgamma(
Function(XLL_DOUBLE, "xll_tgamma", "TGAMMA")
.Arguments({
Arg(XLL_DOUBLE, "x", "is the value for which you want to calculate Gamma.")
})
.FunctionHelp("Return the Gamma function value.")
.Category("CMATH")
.HelpTopic("https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/tgamma-tgammaf-tgammal")
);
double WINAPI xll_tgamma(double x)
{
#pragma XLLEXPORT
return tgamma(x);
}
The add-in registers the function TGAMMA
with Excel to call the C++ function
xll_tgamma
that returns a double
. It has one argument that
is also a double
and will show up in the Excel function wizard under the
CMATH
category with the specified function help. When
Help on this function
is clicked it will open the help topic for the Microsoft C runtime library reference for tgamma
.
Compare this to
the built-in Excel functon
GAMMA
.
All functions called from Excel must be declared WINAPI
which is defined to be
__stdcall
.
This is an artifact of the original versions of Excel being written in Pascal.
The line #pragma XLLEXPORT
causes the function to be exported
from the dll so it will be visible to Excel.
No need for old-fashioned .DEF
files.
The function xll_tgamma
calls the tgamma
function declared in the <cmath>
library.
Recall the Gamma function is Γ(x)
= ∫0∞ tx - 1 e-t dt,
x > 0.
It satisfies Γ(x + 1) = x Γ(x) for x > 0.
Since Γ(1) = 1 we have Γ(x + 1) = x! if x is a non-negative integer.
For applications you may want to use the
lgamma
function that returns the natual logarithm of Γ. For x ≥ 171.62,
Γ(x) is greater than the largest IEEE 64-bit double value.
To register a new add-in macro call AddIn
with a Macro
argument. It takes
two string arguments: the name of the C++ function to be called and the name for Excel to use.
Macro functions take no arguments and return an int
that is non-zero if it succeeds or zero if it fails.
Don't forget WINAPI
in the function definition
and #pragma XLLEXPORT
in the function body so Excel can load it.
AddIn xai_macro(Macro("xll_macro", "XLL.MACRO"));
int WINAPI xll_macro(void)
{
#pragma XLLEXPORT
Excel(xlcAlert,
Excel(xlfConcatenate,
OPER("XLL.MACRO 召唤 with активный cell: "), // use utf-8!
Excel(xlfReftext,
Excel(xlfActiveCell),
OPER(true) // A1 style instead of R1C1
)
),
OPER(2), // general information
OPER("https://xlladdins.github.io/Excel4Macros/alert.html")
);
return TRUE;
}
The Help
button in the alert dialog will take you to documentation for the
ALERT
macro.
The name of the AddIn
object is arbitrary. I use xai_
as a prefix for all
Excel add-in objects as a convention.
The Excel SDK has two versions of most data types, ones for pre 2007 Excel and ones for 2007 Excel and later.
The new verions allow for large grids and wide character Unicode strings. The new data types
have names with the suffix 12
. This library makes it possible to
write add-ins that work with all version of Excel. It uses a technique similar to the Windows
TCHAR
technique.
That uses the suffix A
for char (ANSI) functions and the W
suffix for wide character (Unicode) functions.
When the suffix is omitted the appropriate function will be called based on macros set before including <tchar.h>
.
The major difference is that the generic functions always take UTF-8 strings.
The xll library converts these to the appropriate string types for Excel.
The xll library controls this by the macro XLL_VERSION
.
Define it to be
4
for pre 2007 Excel and
12
for Excel 2007 and later before including xll/xll.h
.
By default it is defined to be 12
.
The file
traits.h
uses the traits pattern
to parameterize by these two types.
The SDK uses Excel4
(or Excel4v
) and Excel12
(or Excel12v
) to
call Excel functions
from your add-in. If you need to know the Excel
version at runtime call
XLCallVer
.
It returns 0x500
(oddly enough) for version 4 and 0x0c00
for version 12 (hexidecimal C
).
Note the original SDK used Excel4
and Excel4v
but not XLOPER4
. Obviously.
You can get finer grained information by calling the
GET.WORKSPACE
function with argument 2
. The return value is a string, for example "5.0"
, with the exact version of Excel.
Using the SDK the call would be Excel4(xlfGetWorkspace, &version, 1, &two)
where version
and two
are XLOPER
s with two = {.val = {.int = 2}, .xltype = xltypeInt}
. You must call
Excel4(xlFree, 0, 1, &version)
to release the memory Excel allocated for the version string.
Using the xll add-in library the call would be OPER version = Excel(xlfWorkspace, OPER(2))
.
The destructor for version
will release the memory when it goes out of scope.
At the C SDK level the fundamental data types are the XLOPER
and XLOPER12
structs for pre and post Excel 2007 respectively.
Each is a discriminated union where the .xltype
member determines the type.
/*
** XLOPER12 structure
**
** Excel 12's fundamental data type: can hold data
** of any type. Use "U" as the argument type in the
** REGISTER function.
**/
typedef struct xloper12
{
union
{
double num; /* xltypeNum */
XCHAR *str; /* xltypeStr */
BOOL xbool; /* xltypeBool */
int err; /* xltypeErr */
int w;
struct
{
WORD count; /* always = 1 */
XLREF12 ref;
} sref; /* xltypeSRef */
struct
{
XLMREF12 *lpmref;
IDSHEET idSheet;
} mref; /* xltypeRef */
struct
{
struct xloper12 *lparray;
RW rows;
COL columns;
} array; /* xltypeMulti */
struct
{
union
{
int level; /* xlflowRestart */
int tbctrl; /* xlflowPause */
IDSHEET idSheet; /* xlflowGoto */
} valflow;
RW rw; /* xlflowGoto */
COL col; /* xlflowGoto */
BYTE xlflow;
} flow; /* xltypeFlow */
struct
{
union
{
BYTE *lpbData; /* data passed to XL */
HANDLE hdata; /* data returned from XL */
} h;
long cbData;
} bigdata; /* xltypeBigData */
} val;
DWORD xltype;
} XLOPER12, *LPXLOPER12;
The burden is on you to set the appropriate .val
members for each .xltype
.
The xll
library provides the C++ class OPER
to help you with this.
Although C++ is strongly typed the OPER
class is designed
to behave much like a cell in a spreadsheet. E.g., OPER o = 1.23
results in o.xltype == xltypeNum
and o.val.num == 1.23
. Assigning a string o = "foo"
results in a counted string with
o.xltype == xltypeStr
and o.val.str == "\03foo" (== {3, 'f', 'o', 'o')})
. The C++ class for
OPER
takes care of all memory managment so it acts like a built-in type. If it doesn't
'do the right thing' when you use it let me know because that would be a design flaw on my part.
A cell (or a 2-dimensional row-major range of cells) corresponds to the OPER
type
defined in the xll
namespace. It is a variant
type that can be a number, string, boolean, reference, error, multi (if it is a range), missing,
nil, simple reference, multiple reference or integer. The xltype
member indicates the type and can be one of
xltypeNum
, xltypeStr
, xltypeBool
, xltypeRef
, xltypeErr
, xltypeMulti
, xltypeMissing
,
xltypeNil
, xltypeSRef
, xltypeRef
, or xltypeInt
.
Excel cells can be floating point doubles or various integer types. These are indicated by, XLL_DOUBLE
,
XLL_WORD
, ..., XLL_LONG
. The corresponding arguments in C functions can be declared as DOUBLE
, WORD
,
..., LONG
but you can use double
, unsigned
, and int
if you prefer. Integer and long types are both 32-bit.
Excel has two flavors of strings: counted Pascal strings and null terminate C strings.
Early versions of Excel involved Pascal which uses counted strings where the first character
is the length of the string. Excel 2007 introduced wide character strings having 16-bit characters.
The old limit was 255 characters to a string. The post Excel 2007 limit is 65535 characters.
You can tell Excel to give you a counted or null terminated char*
string by specifying the
XLL_PSTRING4
of XLL_CSTRING4
data type in the AddIn
constructor.
Use XLL_PSTRING12
or XLL_CSTRING12
to tell Excel to give you a wchar_t*
.
For maximum portability use XLL_PSTRINGX
or XLL_CSTRINGX
with corresponding argument TCHAR*
.
OPER
s are specializations of the XOPER
class which publicly inherits from the XLOPERX
struct defined the header file
XLCALL.H
. More precisely,
OPER4
inherits from XLOPER
and OPER12
inherits from XLOPER12
. These are shorthand for
XOPER<XLOPER>
and XOPER<XLOPER12>
.
This permits anOPER
to be used anywhere a const XLOPERX&
can be used.
The Excel SDK structs know nothing about memory management so the OPER
constructors make
a copy of the data from a XLOPERX
.
It is permissable to have multis that contain other multis and can be nested to any depth.
Multis having two columns with the first column containg strings are quite similar to
JSON objects.
You can use the Excel built-in function
DGET
to access values via DGET(multi, 2, key)
to obtain the value (in columns 2) of the multi
corresponding
to key
.
The default constructer of OPER
creates an object of type xltypeNil
.
Do not confuse this with the "#NULL!"
error type that indicates an empty intersection of two ranges.
The OPER
Nil
is predefined.
Use Nil4
for the XLOPER
version and Nil12
for a XLOPER12
.
All standard error types are predefined with names corresponding to the error.
For example, ErrNull
is the OPER
with xltype = xltypeErr
and val.err == xltypeNull
.
Both ErrNull4
and ErrNull12
are also predefined.
The missing type is used only for function arguments.
It indicates no argument was provided by the calling Excel function.
This is predefined as Missing
,Missing4
and Missing12
.
It is an error to return this type from a function.
A feature of the Excel C SDK is that it allows you to specify more argument types than the .xltype
field allows. You can use this to your advantage
to have Excel check argument types before calling your function.
If someone using your code calls a function with an invalid argument type then Excel returns
#VALUE!
.
On the other hand, it does not allow you to check the argument type and display a
more informative error message. If you want to do this, specify the argument as XLL_LPXLOPER
to get a pointer to the fundamental XLOPER
Excel data type.
Another feature is that you can tell Excel you do not want it to hand you reference types.
If you specify the argument type as XLL_LPOPER
then Excel will coerce the reference
and hand you the value it refers to. If the reference is a 2-dimensional range
you will get an xltypeMulti
. If the reference is a single cell then you will get
an OPER
with xltype
corresponding to the cell value.
You can also use this to provide pointers to internal Excel data structures that can be passed to C++ functions and avoid copying data.
The C SDK uses a character string
to indicate function signatures. The xll
library defines XLL_
type character
strings to make these easier to use.
The xll::FPX
data type is a two dimensional array of floating point numbers.
It is the fastest way of interacting with numerical data in Excel.
All other APIs require the data to be copied out of Excel then back again.
See potrf.cpp
for an example of how to use this.
It calls the FORTRAN function DPOTRF
from the
LAPACK
library to perform a Cholesky decomposition.(Yes, you can easily call FORTRAN, and C of course, from C++).
A 1000 x 1000 matrix takes about 0.3 seconds on my old Surface Pro 4 1GHz laptop.
There are structs defined in XLCALL.H
for versions of Excel prior to 2007 as struct _FP
and struct _FP12
for later versions.
These are typedef'd as FP
and FP12
and reside in the global namespace.
The classes xll::FP4
and xll::FP12
make these into well-behaved
C++ value types.
Use _FPX
(or _FP4
/_FP12
) to get the appropriate C Excel type in the global
namespace to use for arguments and
return types. Excel doesn't know about anything in the xll
namespace.
Since FPX
does not inherit from the C structs you must use
the FPX::get()
member function to get a pointer to the underlying struct.
This is used to return arrays to Excel where the return type is
XLL_FPX
. Since you are returning a pointer you must make sure the memory
it points to exist after the function returns. Typically
this is done by declaring a static xll::FPX
in the function body.
Use xll::FPX a(2,3)
to create a 2 by 3 array of doubles and a(1,0)
to access
the second row, first column (indexing is 0-based) of a
. The same element
can be accessed using one-dimesional indexing via a[3]
since data are
stored in row-major order. Use the member function resize
to resize the array.
The FPX
data type also has member functions for rows
, columns
, and size
.
To be STL friendly the member functions begin
and end
are provided for
both const
and non-const iterators over array elements.
The xll
library uses only UTF-8 strings but Excel (post 2007) uses either 8-bit ASCII unsigned char*
or
16-bit wide character unsigned short*
strings.
The easiest way of getting strings in and out of Excel is to use an OPER
of type xltypeStr
. Use OPER::is_str()
to detect if it is a string.
The library will take care of encoding and decoding strings for you.
To get strings directly from Excel specify the argument as XLL_PSTRING
, XLL_CSTRING
, XLL_PSTRING12
, or XLL_PSTRING12
.
The P
indicates the string is counted with the first character being its length. The C
indicates the string will be null terminated
as is the custom in C. You can return strings directly to Excel by specifying the appropriate return type in Function
.
When returning a pointer to an OPER
that is a string you must indicate to Excel how the memory was allocated. If the OPER
was
allocated on the call stack then you must set the xlbitDLLFree
bit using o.xltype |= xlbitDLLFree
. If Excel
allocated the string then you must set the xlbitXLFree
bit. An OPER
returned from a call to Excel
has this
bit set already. The easiest method is to declare the OPER
as static
so the memory will stick around
after the function returns, however this is not thread safe.
The xltypeMulti
type is a two dimensional array of OPER
s. Specify the type as XLL_LPOPER
as the AddIn
argument type.
It has a val.array.lparray
pointer to a row major array of OPER
s having dimension val.array.row
by val.array.columns
.
The constructor takes two integers indicating the number of rows and columns. It can be indexed linearly with
OPER::operator[](int i)
or OPER::operator()(int row, int column)
for two dimensional arrays.
If the argument type is specified to be XLL_LPXLOPER
and the argument is a reference then Excel with provide you
with a single reference type, xltypeSRef
, or a multiple reference type, xltypeRef
. If you specify
XLL_LPOPER
and the argument is a reference then Excel calls xlCoerce
on the reference to get its value
before handing it to you.
When returning a pointer to an OPER
that is a multi you must indicate to Excel how the memory was allocated. If the OPER
was
allocated on the call stack then you must set the xlbitDLLFree
bit using o.xltype |= xlbitDLLFree
. If Excel
allocated the multi then you must set the xlbitXLFree
bit. An OPER
returned from a call to Excel
has this
bit set already. The easiest method is to declare the OPER
as static
so the memory will stick around
after the function returns, however this is not thread safe.
Handles are used to embed C++ objects in Excel.
Call xll::handle<T>(T*)
using new
to create an object of type T
.
The call xll::handle<T> h(new T(...))
creates a handle h
to
an object of type T
using any constructor for T
.
If the cell a function is being called from contains a handle returned by
a previous call, then the corresponding C++ object is delete
d
and the new handle is returned to the cell.
Use h.ptr()
to get the underlying C++ pointer and h.get()
to get
the handle to be returned to Excel. The latter has type HANDLEX
and
is specified in add-in arguments as XLL_HANDLEX
.
To access a handle that has been created use xll::handle<T>(HANDLEX);
to converts a handle to a pointer. If the pointer was not created by
a call to handle<T>(T*)
then it is set to nullptr
and the value of h.get()
is the
double 0.
The xll::handle
class has a member function operator->()
so
h->member(...)
works as if h
were a T*
.
For example if we have the class
class base {
OPER x;
public:
base(const OPER& x) : x(x) { }
OPER& get() { return x; }
};
then we can embed base
objects in Excel using
AddIn xai_base(
Function(XLL_HANDLEX, "xll_base", "XLL.BASE")
.Arguments({
Arg(XLL_LPOPER, "x", "is a cell or range of cells")
})
.FunctionHelp("Return a handle to a base object.")
.Uncalced() // Required for functions creating handles!!!
);
HANDLEX WINAPI xll_base(LPOPERX px)
{
#pragma XLLEXPORT
xll::handle<base> h(new base(*px));
return h.get();
}
and access them with
AddIn xai_base_get(
Function(XLL_LPOPER, "xll_base_get", "XLL.BASE.GET")
.Arguments({
Arg(XLL_HANDLEX, "handle", "is a handle returned by XLL.BASE")
})
.FunctionHelp("Return the value stored in base.")
);
LPOPERX WINAPI xll_base_get(HANDLEX _h)
{
#pragma XLLEXPORT
static OPER result; // must be static since we are returning its address
xll::handle<base> h(_h);
if (h) {
result = h->get();
}
else {
result = ErrNA;
}
return &result;
}
For a production quality version of this example see
handle.cpp.
That file also has examples illustrating how single inheritance can be used in Excel
using dynamic_cast
. The handle
class has a member template<class U> U* as()
to do this for you and ensure U
is derived from T
.
When a spreadsheet containing handles is reopened you must 'refresh' the handles using Ctrl-Alt-F9
.
The old handles that were previously saved are stale.
Add-ins can call any Excel function using xll::Excel
and the appropriate function number.
The function numbers are defined in
XLCALL.H
and correspond to Excel built-in functions or macros (command equivalents).
To determine the approriate arguments for a function number see the
Excel 4 Macro documentaton
Function numbers starting with xlf
are functions and can be called from add-in functions.
Function numbers starting with xlc
are macros and can only be called from add-in macros.
Functions are not allowed to have side-effects, they must be purely functional. Macros can only
have side-effects, they take no arguments and return TRUE
if they run successfully and
FALSE
if not.
Some
function numbers are special to the C API.
For example, xlUDF
can be used to call User-Defined Functions.
The program that the debugger starts and the arguments to use are specified in project properties.
Right click on a project and select Properties
(Alt-Enter
) at the bottom of the popup menu.
Navigate to Debugging
in Configuration Properties
.
The Command
$(registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\excel.exe)
looks in the registry for the full path of the Excel executable.
The Command Arguments
"$(TargetPath)" /p "$(ProjectDir)"
are passed to
Excel when the debugger starts. The variable $(TargetPath)
is the
full path to the xll that was built and is opened by Excel.
The /p
flag to Excel sets the
default directory so Ctrl-O
opens to the project directory.
You can automatically generate documentation for your add-in by calling Documentation("NAME", "Description...)
anywhere
in your add-in. This creates an index.html
file with links to all the functions and macros that
have a .Documentation()
argument. The files are created in the directory the add-in is run from
and only works when compiled in debug mode. There is an experimental macro called DOC
that
will create a workbook with one sheet per add-in function and provide an index page.
Math is rendered using KaTeX. Inline formulas use \(...\)
and displayed formulas
use \[...]\
. I like to use
raw string literals
to keep the documentation next to the code. For example
AddIn xai_foo(
Function(...)
.Arguments({...})
...
.Documentation(R"xyzyx(
This is documentation with inline math like this: \(e^{\pi i} + 1 = 0\).
It also has a displayed equation
\[
\exp(x) = \sum_{n = 0}^\infty \frac{x^n}{n!}.
\]
<p>
You can use any valid HTML in your documentation.
</p>
<aside><p>Any unique string of characters can be used with a raw string literal instead of `xyzyx`.</p></aside>
)xyzyx")) // ← last parentheses closes `.Documentation()`
);
Things you should be aware of but don't need to know to use the xll library.
At the end of the day computer programs come down to bits. Everything is a collection of bits, it is just a matter of how to interpret them. The Windows 10 operating system comes in two flavors: 32-bit and 64-bit. The abstract data model, how the bits are interpreted, are nearly the same: all basic data types are 32-bit, only the pointer types differ. You may have difficulty locating a 32-bit version of Window 10, which is good. All new developent is happening in the 64-bit world so you should prefer that.
Excel also comes in 32-bit and 64-bit flavors. You can run either (but not both) on 64-bit Windows. You can only run 32-bit Excel on 32-bit Windows. Visual Studio can build both 32-bit and 64-bit add-ins. You should build for the flavor of Excel you have installed. Install 64-bit Excel if you have that option.
Microsoft Office has several flavors. The latest version is Microsoft Office 2019 and only runs on Windows 10 or Mac OS X Sierra and later. There is a free web based version that runs in all modern browsers.
There is also Office 365,
now called Microsoft 365, which should not be confused with Office 2019.
It has features not available in Office 2019, in particular
dynamic arrays.
No need for Ctrl-Shift-Enter
and trying to guess the size of ranges returned by functions.
The entire range gets plopped into the spreadsheet and you will see a
#SPILL!
error if that would clobber existing cells.
Xll add-ins are not supported on Macs or the web based version. You can write custom functions using JavaScript (or, even better, TypeScript) for Office on Windows, Mac, and online versions.
When you build in debug mode the add-in library will check for memory leaks after you run the add-in.
It uses the functions in
<crtdbg.h>
to turn on memory debugging.
After you run your add-in the Output
window will have information about the location of memory leaks.
It will also have a lot of other things such as all the dlls that were loaded and unloaded, and a list
of exceptions that were thrown. You can ignore those.
Use Ctrl-F
and search for the strings matching leak
to find the output
from the memory debugging routines. Those will tell you the values to set for _crtBreakAlloc
so the next time you run the add-in the debugger will stop where the bad allocation was detected.
Use the call stack to zero in on the offending allocation.
The cool kids use AddressSanitizer these days.
Handles are handled by the xll::handle<T>
class parameterized by the handle type T
.
They are similar to std::unique_ptr<T>
.
A handle is a double
used
to represent a pointer.
Excel doesn't know about pointers so we use a double to hold a pointer to a C++ object.
Use HANDLEX
instead of double
to make clear when a double is representing a pointer.
If you are worried that the 64-bits in a pointer might represent a double
that is
a NaN or denormalized value, you should be. Neither of those survive a round
trip to Excel and back. Returning a NaN to Excel results in the error type #NUM!
.
On 64-bit Windows the first 16-bits of a pointer are zero so all we need are the remaining 48-bits.
Doubles can exactly represent integers up to 253
so we have plenty of room to spare.
Converting between HANDLEX
and void*
is just a
cast, so no lookup is involved.
The handle<T>(T *)
constructor takes a pointer returned by new
and behaves like
a std::unique_ptr
. The member function handle<T>::ptr()
returns the T*
pointer.
The member function handle<T>::operator->()
provides syntactic sugar for this.
Use handle<T>::get()
to return the corresponding HANDLEX
to Excel.
When the HANDLEX
is passed back from Excel as an add-in function argument the
handle<T>(HANDLEX)
constructor converts the HANDLEX
back to a T*
pointer.
By default it checks to see if this has been constructed by a call to handle<T>(T*)
,
but this can be turned off. If the check fails a nullptr
is returned.
If any arguments to a function call a function that creates a handle, then the handle
gets deleted after the outer function returns. To avoid repeated calls to new
and delete
put handles in their own cell and pass a reference to that as an argument.
If you don't like seeing raw pointer values as doubles then roll your own encoder/decoder to display whatever tickles your fancy.
Functions that are declared .Uncalced()
have a limited ability to call command equivalents/macros.
You must specify this when writing an add-in that creates a handle.
In general, add-in functions cannot have side-effects.
They can only call Excel
with function numbers starting with xlf
(functions) and are
forbidden to call Excel
with function numbers starting with xlc
(command equivalents,
also known as macros).
Functions that are declared .Volatile()
are called on every recalculation.
For example, the built-in RAND()
function is volatile.
It is always recalculated even though it has no dependencies.
In Excel F9
(xlcCalculateNow
) recalculates all 'dirty' cells.
Use Shift-F9
(xlcCalculateDocument
) to recalculate only the dirty cells in the active worksheet.
There is no command equivalent in the C API for Ctrl-Alt-F9
.
Use this when you want Excel to recalculate everything, really, no kidding, just do it.
You should be aware of the 'replace equal by equal' idiom.
The key sequence is Ctrl-H, =, <tab>, =, a
.
This replaces all occurences of the =
character in every formula by =
and causes each formula to be recalculated without changing the formula.