I’m trying to write an array constructor for Excel as a worksheet function using the C API.
Goal: =array_cons(1, 2, 3) => {1, 2, 3}
However, I am not initializing the XLOPER12 correctly. In Excel, my function currently returns #NUM. I am taking the argument list and packing it into a vargs array via macros then trying to return the part of the array that was supplied.
#include <windows.h>
#include <xlcall.h>
#include <framewrk.h>
#include <boost/preprocessor.hpp>
#define VARG_COUNT 250
#define VARG_FORMAT(Z, A, B) B##A,
#define VARG_DEF_LIST(N) BOOST_PP_REPEAT(N, VARG_FORMAT, LPXLOPER12 varg) \
LPXLOPER12 varg##N
#define VARG_ARRAY(N) { BOOST_PP_REPEAT(N, VARG_FORMAT, varg) varg##N }
#define GET_VARGS VARG_ARRAY(VARG_COUNT)
__declspec(dllexport) LPXLOPER12 WINAPI array_cons(VARG_DEF_LIST(VARG_COUNT))
{
LPXLOPER12 vargs[] = GET_VARGS;
int args_passed = 0;
for(int i = 0; i < VARG_COUNT; ++i, ++args_passed)
{
if (vargs[i]->xltype == xltypeMissing)
{
break;
}
}
if (args_passed == 0)
{
XLOPER12 err;
err.xltype = xltypeErr;
err.val.err = xlerrValue;
return (LPXLOPER12)&err;
}
XLOPER12 list;
list.xltype = xltypeMulti;
list.val.array.lparray = (XLOPER12*)vargs;
list.val.array.rows = args_passed;
list.val.array.columns = 1;
return (LPXLOPER12)&list;
}
I figured it out. A couple of things to note here –
You need to make sure that your UDF registration is using the right signature. In my case, I wanted Excel references to give me their respective values, so I used the
Qtype when registering the function. If you don’t understand this, check out http://msdn.microsoft.com/en-us/library/office/bb687869.aspxIn order to return an array, you have to dynamically allocate new memory to the
list.val.array.lparraymember and iteratively populate it.Since we are dynamically allocating memory, we need to define the callback to free it.