Discussion:
xll to return an array
(too old to reply)
XLjedi
2010-02-10 18:05:01 UTC
Permalink
I would post an example, but I'm not even sure where to begin...

I need to be able to create an xll function that takes ranges as arguments
(XLOPER12) and then returns an array value result (presumably also as an
XLOPER12).

Basically I have two issues:

1) I know how to declare and load a 2D array in C++, I just don't know how
to properly return it in the form of an XLOPER12 result.

2) Then I need to be able to make the 2D array variable in size so it
matches the size of the range arguments.

I just need a basic template for an xll function that takes a 2D range as an
argument, creates a 2D array and populates it with the values +1, and then
returns the results in the form of an array result.
lab27
2010-02-12 21:32:50 UTC
Permalink
Inline.
Post by XLjedi
I would post an example, but I'm not even sure where to begin...
I need to be able to create an xll function that takes ranges as arguments
(XLOPER12) and then returns an array value result (presumably also as an
XLOPER12).
1)  I know how to declare and load a 2D array in C++, I just don't know how
to properly return it in the form of an XLOPER12 result.
Return an xloper(12) of type xlTypeMulti
Post by XLjedi
2)  Then I need to be able to make the 2D array variable in size so it
matches the size of the range arguments.
Val.array.parray should be dynamically allocated to width * depth *
sizeof xloper(12).
You can then just dump your data in there. (val.array.parray[0 ->
((width*depth)-1) ] )
Val.array.rows/columns should be set appropriately.

Remember to set bit xlDllFree on the return oper type field, and
implement xlAutoFree(12), because you'll need to free this memory when
excel calls you back, since it has no idea what heap you used to
allocate it.
Post by XLjedi
I just need a basic template for an xll function that takes a 2D range as an
argument, creates a 2D array and populates it with the values +1, and then
returns the results in the form of an array result.
You just need to xlCoerce the input into an xlTypeMulti, create an
output xlTypeMulti of the same size as above, and copy the data
across. Mind you, if your input data is definitely a double array,
you don't actually need to use xlopers at all, you can use type K.

Have a look here http://msdn.microsoft.com/en-us/library/aa730920.aspx
, also at Steve Dalton's book - it's a good introduction to XLL
development.

Rgds,

Lee.
XLjedi
2010-02-15 18:29:03 UTC
Permalink
I've already been to the MSDN URL and I have Dalton's book on order. I may
just have to wait and see how he does it.

All I need to return is an array so a K-data type will probably be fine. I
just haven't been able to find good examples of how to accept an XLoper or
Array data type and create/return one of matching size.

Everytime I try to create a variable-sized array it fails to compile. I
haven't been able to do anything like: double MyArray[r][c]
lab27
2010-02-15 22:17:39 UTC
Permalink
I've already been to the MSDN URL and I have Dalton's book on order.  I may
just have to wait and see how he does it.
There's really nothing to it other than what I said above. Example
below with xloper.
All I need to return is an array so a K-data type will  probably be fine.  I
just haven't been able to find good examples of how to accept an XLoper or
Array data type and create/return one of matching size.  
Everytime I try to create a variable-sized array it fails to compile.  I
haven't been able to do anything like:  double MyArray[r][c]
Do you know how heap memory works in C/C++?
For the sake of argument / keeping it in C, I'll use malloc. (and not
add much error checking).
There's no reason you have to use malloc, as long as your xlAutoFree
function corresponds.

Lee.

// Expects framewrk.h/c from excel SDK for TempInt
extern "C" LPXLOPER __declspec(dllexport) rangeadd(LPXLOPER px)
{
// Not threadsafe.
static XLOPER xlo;

switch (px->xltype)
{
case xltypeMulti:
case xltypeRef:
case xltypeSRef:
// Coerce it to the values.
{
XLOPER xMulti;
LPXLOPER pxiterin, pxiterout;
unsigned int arrsz;
unsigned int x;

if (xlretSuccess != Excel(xlCoerce, &xMulti, 2,
(LPXLOPER) px, TempInt(xltypeMulti))) {
return 0; // uncalced inputs, call me when you've got something.
}
pxiterin = xMulti.val.array.lparray;
arrsz = xMulti.val.array.rows * xMulti.val.array.columns;

// Note I'm using malloc here to keep it pure C.
xlo.val.array.lparray = pxiterout = (LPXLOPER)malloc(arrsz *
sizeof(XLOPER));
xlo.val.array.rows = xMulti.val.array.rows;
xlo.val.array.columns = xMulti.val.array.columns;
// I'm returning an array, and I'd like to be called so I can free
the memory.
// Therefore need to implement xlAutoFree.
xlo.xltype = xltypeMulti|xlbitDLLFree;

for (x=0;x<arrsz;++x, ++pxiterin, ++pxiterout)
{
switch (pxiterin->xltype)
{
case xltypeNum:
pxiterout->xltype = xltypeNum;
pxiterout->val.num = pxiterin->val.num + 1;
break;
default:
pxiterout->xltype = xltypeErr;
pxiterout->val.err = xlerrValue;
break;
}
}
// Free the temp xlTypeMulti.
Excel(xlFree, 0, 1, &xMulti);
}
break;
default:
// Note that I'm not handling any value cases.
xlo.xltype = xltypeErr;
xlo.val.err = xlerrNA;
break;
}

return &xlo;
}

Of course, you need to supply a callback to free the memory. If you
were to do it properly, it would free any heap memory inside the
xlopers of any array it was called back with.

extern "C" __declspec(dllexport) void xlAutoFree(LPXLOPER xParam) {
if (!xParam) return;
if (0 != (xParam->xltype & xlbitDLLFree)) {
switch (xParam->xltype & ~xlbitDLLFree) {
case xltypeMulti:
// Here I should iterate over the array, if there's a possibility
there
// is any other heap (eg strings) in it, etc.
free(xParam->val.array.lparray);
break;
default: // should handle strings etc.
break;
}
}
}
XLjedi
2010-02-16 16:29:01 UTC
Permalink
Thank you for the detailed code example.

I know very little c/c++ at the moment and am trying to learn. Your
commented code will be very helpful, thanks for taking the time to post it.
Loading...