This dub package allows D code to be called from Excel. It uses compile-time reflection to register the user's code in an XLL (a DLL loaded by Excel) so no boilerplate is necessary. Not even `DllMain`! It works like this:


import xlld;
mixin(wrapAll!(__MODULE__, "funcs"));


import xlld;

@Register(ArgumentText("Array to add"),
          HelpTopic("Adds all cells in an array"),
          FunctionHelp("Adds all cells in an array"),
          ArgumentHelp(["The array to add"]))
double FuncAddEverything(double[][] args) nothrow @nogc {
    import std.algorithm: fold;
    import std.math: isNaN;

    double ret = 0;
    foreach(row; args)
        ret += row.fold!((a, b) => b.isNaN ? 0.0 : a + b)(0.0);
    return ret;

This code, once compiled to an XLL (see the example in the repository) and loaded in Excel, will permit a user to write `=FuncAddEverything(B1:D6)` and have the cell populated with the sum of all arguments in that range.

There's a lot going on behind the scenes, and that's the point. For instance, the function above takes a 2d array of doubles and returns a double, but those aren't Excel types. The wrapper code writes out an Excel-compatible type signature at compile-time, does all the conversions, calls the user's code then converts back to types Excel can understand.

The user functions have to be `nothrow`. This is guaranteed at compile-time and the user gets a warning message about the function not being considered. `@nogc` is optional but won't work if returning a string due to allocations. The code is compatible with std.experimental.allocator internally but there's no way to specify an allocator currently for the registration.

I can make the registration mixin easier to use but haven't gotten around to it yet. I thought it was better to put the code out there as is than wait.

This is another one of those "only in D" packages due to the metaprogramming, which is always nice.


Reply via email to