如何从XLL UDF返回一个数组

我试图写一个Excel的数组构造函数作为使用C API的工作表函数。

目标: =array_cons(1, 2, 3) => {1, 2, 3}

但是,我没有正确初始化XLOPER12。 在Excel中,我的函数当前返回#NUM 。 我正在采取参数列表,并通过macros将其打包到vargs数组中,然后尝试返回提供的数组部分。

 #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; } 

我想到了。 有几件事要注意 –

您需要确保您的UDF注册使用正确的签名。 在我的情况下,我希望Excel引用给我他们各自的价值观,所以我注册function时使用Qtypes。 如果你不明白这一点,请查看http://msdn.microsoft.com/en-us/library/office/bb687869.aspx

为了返回一个数组,你必须dynamic分配新的内存给list.val.array.lparray成员,并迭代地填充它。

 __declspec(dllexport) LPXLOPER12 WINAPI array_cons(VARG_DEF_LIST(VARG_MAX)) { LPXLOPER12 vargs[] = GET_VARGS; int args_passed = 0; for(int i = 0; i < VARG_MAX; ++i, ++args_passed) { if (vargs[i]->xltype == xltypeMissing) { break; } } XLOPER12 list; list.xltype = xltypeMulti | xlbitDLLFree; list.val.array.lparray = new XLOPER12[args_passed]; list.val.array.rows = args_passed; list.val.array.columns = 1; for(int i = 0; i < args_passed; ++i) { list.val.array.lparray[i] = *vargs[i]; } return &list; } 

由于我们是dynamic分配内存,我们需要定义callback来释放它。

 __declspec(dllexport) void WINAPI xlAutoFree12(LPXLOPER12 p) { if (p->xltype == (xltypeMulti | xlbitDLLFree)) { delete [] p->val.array.lparray; } } 

您的解决scheme不完整。

你写

 XLOPER12 list; 

在function的身体。 这使得“list”成为在堆栈上创build的局部variables。 函数返回时,“list”超出范围。 您将返回一个指向不在范围内的variables的指针,并且当Excel尝试访问此指针时,行为是未定义的。 如果Excel在处理返回值之前碰巧调用另一个函数,那么你的列表variables将被破坏。

解决的办法是,你必须dynamic地为列表分配内存(然后确保它以后被释放),或者使列表成为静态或全局variables。

不知道为什么你认为xll库不会允许你开发一个开源插件。 IANAL,但是PL-PL似乎允许这样做。 你看过http://xllfunctional.codeplex.com/吗&#xFF1F; 它使用类似的不可移植的技巧,不会拖延到解决scheme。 WINAPI / __ stdcall就是这样。 如果你知道事情发生在硅片上,你可以利用这一点。