如何从一个XLL UDF返回数组(How to return an array from an XL

2019-08-06 16:35发布

我试着写为Excel数组构造函数使用C API工作表函数。

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

不过,我没有正确初始化XLOPER12。 在Excel中,我的功能目前返回#NUM 。 这是我在参数列表,并将其包装成一个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;
}

Answer 1:

我想到了。 几件事情要注意在这里 -

你需要确保你的UDF注册使用正确的签名。 就我而言,我想引用的Excel给我各自的价值,所以我用Q注册功能时类型。 如果你不明白这一点,看看http://msdn.microsoft.com/en-us/library/office/bb687869.aspx

为了返回一个数组,你必须动态地分配新的内存到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;
}

由于我们是动态分配的内存,我们需要定义回调以释放它。

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


Answer 2:

您的解决方案是不完整的。

你写

XLOPER12 list;

在函数体。 这使得“名单”是在栈上创建了一个局部变量。 当函数返回时,“列表”超出范围。 你返回一个指针变量不再范围,当Excel试图访问该指针,该行为是不确定的。 如果Excel处理发生的返回值之前调用另一个函数,您的列表变量将得到重挫。

解决的办法是,你要么必须动态地分配内存列表(并确保它被释放后),或使列表静态或全局变量。



Answer 3:

不知道为什么你认为XLL库不会让你开发一个开源插件。 IANAL,但MS-PL似乎允许的。 你看http://xllfunctional.codeplex.com/ ? 它使用的是不给解决拖升压类似的非便携的技巧。 该WINAPI / __ STDCALL是它是什么。 如果你知道事情是如何发生倒在硅你可以利用这一点。



文章来源: How to return an array from an XLL UDF
标签: c++ excel xll