XLL+ Class Library (7.0)

ArrayHandles Sample

Uses handles to represent vectors of numbers

Overview

This project demonstrates the use of handles to represent large data sets. Each handle represents a vector of numbers.

Object creation

Each vector is held in a NumericVector object; the NumericVector class is a thin wrapper around std::vector.

CopyC++
class NumericVector : public std::vector<double> {
public:
    NumericVector() { }
    NumericVector(const std::vector<double>& source)
    {
        assign(source.begin(), source.end());
    }
    NumericVector(size_t size)
    {
        resize(size);
    }
};

The add-in function CreateVector takes a vector of numbers as an argument, creates a NumericVector object, adds it to the object cache and returns a handle to the object.

CopyC++
CXlOper* CreateVector_Impl(CXlOper& xloResult, const CXlOper* numbers_op)
{
    // Input buffers 
    std::vector<double> numbers;
    // Validate and translate inputs
    XlReadVector(*numbers_op, numbers, L"numbers", XLA_TRUNC_ONEMPTY|
        XLA_TRUNC_ONBLANK);
    // End of generated code 
//}}XLP_SRC
    NumericVector* vec = new NumericVector(numbers);
    xloResult = psl::CreateHandleInCache(vec);
    return xloResult.Ret();
}

Using a handle

The add-in function UseVector1 takes a handle to a NumericVector as an argument, and returns the sum of the numbers in the vector. The XLL+ Function Wizard was used to declare the argument vec as of type Handle to NumericVector.

In the code below, note that the auto-generated code deals with all the work of converting the handle into a pointer to the cached NumericVector object. If the conversion fails, then an exception is thrown and the developer-defined code that uses vec is never reached.

CopyC++
CXlOper* UseVector1_Impl(CXlOper& xloResult, const CXlStringArg& vec_op)
{
    // Input buffers 
    const NumericVector* vec;
    // Validate and translate inputs
    XlReadScalarEx(vec_op, vec, psl::HandleConverter<NumericVector >(), 
        CScalarConvertParams<const NumericVector*>(L"vec", 0, 0, -1).
        SetStringParam(0, L"NumericVector"));
    // End of generated code 
//}}XLP_SRC
    xloResult = std::accumulate(vec->begin(), vec->end(), 0.0);
    return xloResult.Ret();
}

Variable type argument

The add-in function UseVector2 uses a variable type argument, which can be either:

  1. a handle to a NumericVector object; or
  2. a one-dimensional array of numbers.

This behavior is achieved by defining the argument as a Choice type, which can be either a Double[] or a Handle to NumericVector, as shown below:

CopyC++
CXlOper* UseVector2_Impl(CXlOper& xloResult, const CXlOper* HandleOrArray)
{
    // Input buffers 
    std::vector<double> numbers;
    const NumericVector* vec;
    // Validate and translate inputs 
    int HandleOrArray__index = -1;
    if (HandleOrArray__index < 0) {
        try {
            XlReadVector(*HandleOrArray, numbers, L"numbers", XLA_TRUNC_ONEMPTY|
                XLA_TRUNC_ONBLANK);
            HandleOrArray__index = 0;
        } catch(...) {}
    }
    if (HandleOrArray__index < 0) {
        try {
            XlReadScalarEx(*HandleOrArray, vec, psl::HandleConverter<
                NumericVector >(), CScalarConvertParams<const NumericVector*>(
                L"vec", 0, 0, -1).SetStringParam(0, L"NumericVector"));
            HandleOrArray__index = 1;
        } catch(...) {}
    }
    if (HandleOrArray__index < 0)
        throw CXlChoiceFailedException("HandleOrArray");
    // End of generated code 
//}}XLP_SRC 
    const std::vector<double>* input = (HandleOrArray__index == 0) 
            ? &numbers : (const std::vector<double>*)vec;
    xloResult = std::accumulate(input->begin(), input->end(), 0.0);
    return xloResult.Ret();
}

The auto-generated code shown above takes care of reading the argument into one of the variables numbers or vec. Note that the code sets the indicator variable HandleOrArray__index to either 0 or 1 to indicate which input variable was set. So the developer-provided code simply inspects HandleOrArray__index and uses the appropriate input variable:

CopyC++
const std::vector<double>* input = (HandleOrArray__index == 0) 
    ? &numbers : (const std::vector<double>*)vec;

Classes and functions used

psl::CreateHandleInCache

Sample project

Each sample project is located in a sub-directory of the Samples directory of the XLL+ installation. To use the sample project, open the solution file ArrayHandles.sln or the project file ArrayHandles.vcproj.

You can enable debugging under Excel by using the Setup Debugging command in the XLL+ ToolWindow.

When delivered, the help files are excluded from the build. You can enable the help build by selecting the files ArrayHandles.help.xml and ArrayHandles.chm in the Solution Explorer, and using the right-click menu to view Properties. Select the page "Configuration Properties/General" and set the "Excluded from build" property to "No". See Generating help in the User Guide for more information.

See Also

List of Sample Projects