xlladdins / xll

Excel add-in library
MIT License
104 stars 23 forks source link

Returning xll::OPER of dynamic size #15

Closed rmcrkd closed 2 years ago

rmcrkd commented 2 years ago

Consider the xll_test and XLL.TEST functions defined below.

In xll_test I declare static xll::OPER a(m, n) in accordance with the following (from README):

Since you are returning a pointer you must make sure the memory at which it points continues to exist after the function returns. Typically this is done by declaring a static xll::FPX in the function body.

But a consequence of a being static is that calls of XLL.TEST after the first call does not change the memory which was allocated for it during the first call. So e.g. calling XLL.TEST(3) after XLL.TEST(2) essentially has no effect.

What is the recommended way of dealing with this?

xll::OPER* WINAPI xll_test(xll::OPER o) {
#pragma XLLEXPORT
    int n = (int)o.val.num;
    static xll::OPER a(n, 1);
    for (int i = 0; i < n; i++) {
        a(i, 0) = i + 1;
    }
    return &a;
}

AddIn xai_test(
    Function(XLL_LPOPER, "xll_test", "XLL.TEST")
    .Arguments({
        Arg(XLL_LPOPER, "o", "Length"),
        })
    .Category("TEST")
);
rmcrkd commented 2 years ago

Same effect from XLL.TEST when replacing xll_test with

xll::OPER* WINAPI xll_test(xll::OPER o) {
#pragma XLLEXPORT
    int n = (int)o.val.num;
    static std::unique_ptr<xll::OPER> aPtr(new xll::OPER(n, 1));
    for (int i = 0; i < n; i++) {
        (*aPtr.get())(i, 0) = i + 1;
    }
    return aPtr.get();
}
keithalewis commented 2 years ago
LPOPER WINAPI xll_test(LPOPER po) { // LPOPER is OPER*. You must pass by pointer.
#pragma XLLEXPORT
    static OPER a;
    int n = (int)po->val.num; // ensure po->xltype == xltypeNum, or po->is_num()
    a.resize(n, 1);
    for (int i = 0; i < n; ++i) {
        a(i, 0) = i + 1;
    }

    return a.get();
}