See the xll library for an earlier version.
There is a reason why many companies still use the ancient Microsoft Excel C Software Development Kit, It provides the highest possible performance for integrating C, C++, and even Fortran into Excel. VBA, C#, and JavaScript require data to be copied into their world and then copied back to native Excel. Microsoft's Python in Excel actually calls over the network to do every calculation, as if Python isn't slow enough already.
There is a reason why many companies don't use the ancient Microsoft Excel C SDK. The example code and documentation are difficult to understand and use. This library makes it easy and performant to call native code from Excel.
One reason for Python's popularity is that people who know how to call C, C++, and even Fortran, from Python have written packages to do that. The xll library allows you to do that directly from the most popular language in the world, Excel.
The xll library requires 64-bit Excel on Windows and Visual Studio 2026.
Go to xll_template,
click on Use this template/Create a new repository.
Fill in your repository and the name you want for the new project, then
Create new repository, Click Code/Open with Visual Studo.
Locate the Solution Explorer tab and double click xll_template.sln.
Pressing F5 should build the solution and start the add-in in Excel.
An xll add-in is a dynamic link library, or DLL,
that exports well-known functions.
When an xll is opened in Excel it
dynamically loads
the xll,
looks for
xlAutoOpen, then
and calls it. There are 7
xlAutoXXX functions
that Excel calls to manage the lifetime of the xll. The xll library implements those for you.
To add a function to be called when Excel calls xlAutoXXX create an
object of type Auto<XXX> and specify a macro to be called.
Macros are functions that take no arguments and returns 1 to indicate success or 0 for failure.
See auto.h for the list of possible values for XXX.
Everything Excel has to offer is available through the Excel function.
The first argument is a function number defined in the C SDK header file
XLCALL.H
specifying the Excel function or macro to call.
Arguments for function numbers are documented in
Excel4Macros.
Function numbers for functions begin with xlf and for macros with xlc.
Functions have no side effects. They return a value based only on their arguments.
Macros take no arguments and only have side effects.
They can do anything a user can do and return 1 on success or 0 on failure.
There are exceptions to this. The primary one is
xlfRegister.
It has the side effect of registering a function or macro with Excel.
There is no need to call xlfRegister directly.
The AddIn class is used to register functions and macros with Excel.
An Excel function returns a result that depends only on its arguments
and has no side effects.
To call a C or C++ function from Excel use
the AddIn class to instantiate an object
that specifies the information Excel needs.
Here is how to register xll_hypot as STD.HYPOT in Excel.
It returns a double and takes two double arguments.
AddIn xai_hypot(
Function(XLL_DOUBLE, "xll_hypot", "STD.HYPOT")
.Arguments({
Arg(XLL_DOUBLE, "x", "is a number."),
Arg(XLL_DOUBLE, "y", "is a number."),
})
.Category("STD")
.FunctionHelp("Return the length of the hypotenuse of a right triangle with sides x and y.")
.HelpTopic("https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/hypot-hypotf-hypotl-hypot-hypotf-hypotl?view=msvc-170")
);The Function class uses the
named parameter idiom.
The member functions Category, FunctionHelp, and HelpTopic are optional but people using your
handiwork will appreciate it if you supply them.
You can specify a URL in HelpTopic that will be opened when
Help on this function
is clicked in the in the
Insert Function
dialog. If you don't then it defaults to https://google.com/search?q=xll_hypot.
Implement xll_hypot by calling std::hypot
from the C++ standard library.
double WINAPI xll_hypot(double x, double y)
{
#pragma XLLEXPORT
return std::hypot(x,y);
}Every function registered with Excel must be declared WINAPI
and exported with #pragma XLLEXPORT in its body.
The first version of Excel was written in Pascal
and the WINAPI calling convention
is a historical artifact of that. Unlike Unix, Windows does not make functions
visible outside of a shared library unless they are explicitly exported.
The pragma does that for you.
Keep the Excel WINAPI function implementations simple.
Grab the arguments you told Excel to provide,
call your platform independent function, and return the result.
Provide a platform independent header file and library for your C and C++ code
so it can be used on any computer with a C++ compiler
to get the same results displayed in Excel.
An Excel macro only has side effects and can do anything a user can do. It takes no arguments and returns 1 on success or 0 on failure.
To register a macro specify the name of the C++ function and the name Excel will use to call it.
AddIn xai_macro(
Macro("xll_macro", "XLL.MACRO")
);Then implement it.
int WINAPI xll_macro(void)
{
#pragma XLLEXPORT
Excel(xlcAlert, "你好 мир"); // UTF-8 string
return 1;
}
The AddIn class is constructed from Args.
All functions and macros must be registered with Excel, and
unregistered when the xll is unloaded.
The Args struct is used to
register
the arguments to a macro or function.
The structs Macro and Function inherit from Args to
to populate the Args struct.
Macros only require the the name of the native function and the name Excel will use to call it.
Functions require the signature of the native function and
and allow you to provide information Excel can display to users
in the Insert Function
dialog.
The Function struct uses the named parameter
idiom to specify optional arguments.
The XlfRegister function is used to register macros and functions
with Excel.
AddIn objects are created when the add-in is loaded,
but there are some things that can only be done after Excel calls xlAutoOpen.
The Args::prepare function arranages the data specified in the Args object
into a format that is necessary to call xlfRegister.
The ADDIN.INFO(name) function returns information about an add-in
given its name.
Functions and macros can report errors, warnings, and information to the user.
The XLL.ALERT.LEVEL function take a mask indicating what type of alerts
to report. The mask is a sum of any of the following values:
XLL_ALERT_ERROR(), XLL_ALERT_WARNING(), and XLL_ALERT_INFORMATION().
To force cell to be calculated after ref, use =DEPENDS(cell, ref).
Selecting characters in the formula in bar then pressing F9 evaluates
the character string. The function EVAL(cell) function does the same thing.
The \RANGE(range) function returns a handle to a range of cells.
The function RANGE(handle) returns the range corresponding to the handle.
After typing = and the name of a function then pressing Ctrl-Shift-A
will produce the names of the arguments of the function.
I don't have access to the source code of Excel, but there is a
simple way to extend this functionality. Instead of pressing
Ctrl-Shift-A you can press <Backspace> to remove the
trailing left parenthesis and then press <Enter>.
You will see the register id
Excel uses to keep track of user defined functions.
With your cursor in the cell containing the register id, pressing Ctrl-Shift-B will
replace the arguments you see from Ctrl-Shift-A with their
default values.
Pressing Ctrl-Shift-C will enter the default values below the cell
and provide the function corresponding to the register id to call those.
You can change the values below the cell to provide new arguments.
Pressing Ctrl-Shift-D will define the names you see from Ctrl-Shift-A
below the cell and provide the function corresponding to the register id
with those names as arguments. The function has the Output style
applied and the arguments have the Input style applied.
If the function text starts with a backslash (\) then the
function returns a handle to a C++ object. The handle is a
64-bit IEEE double
having the same bits as the pointer to the underlying C++ object.
The \RANGE(cells) function returns a handle to a range of cells.
The RANGE(handle) function returns the range corresponding to the handle.
Two row OPERs correspond to JSON objects.
The first row are the string keys and the second row are the corresponding values.
JSON objects can be nested, and so can OPERs.
However, Excel only displays two dimensional ranges.
We address this by providing a handle to a range if it is nested.
Use the RANGE function to get the range corresponding to the handle.
Handle multiple add-ins being loaded. Perhaps define hidden named ranges with the data? Only exists per Excel session.