jeudi 28 mars 2019

C++ Reduce Redundancy

I have many C++ functions in a DLL that I made specifically for Excel to call.

I frequently pass to these functions as parameters OLE VARIANTs that contain SafeArrays.

I wrote a function to act as a guard to ensure that a passed VARIANT actually contains a SafeArray and that the array is of the proper type for the occasion, both in terms of datatype and number of dimensions.

If those three criteria are satisfied the function returns a pointer to the first element and also has two out parameters to return the number of elements in each dimension (note: I only care about 1d and 2d SafeArrays).

Here is the function:

PVOID SafeArrayDataPointer(VARIANT &v, const long &ArrayType, const long &ArrayDims, long &Elems1D, long &Elems2D) {

    SAFEARRAY* pSafeArray = NULL;

    if ( V_VT(&v) & VT_ARRAY ) {

        if ( ArrayType != (V_VT(&v) & VT_TYPEMASK) ) return NULL;

        pSafeArray = V_ARRAY(&v);
        if ( ArrayDims != pSafeArray->cDims ) NULL;

        switch (ArrayDims) {
        case 2:
            Elems1D = (pSafeArray->rgsabound)[1].cElements;
            Elems2D = (pSafeArray->rgsabound)[0].cElements;
            break;
        case 1:
            Elems1D = (pSafeArray->rgsabound)[0].cElements;
            Elems2D = 0;
            break;
        default: 
            Elems1D = 0;
            Elems2D = 0;
            break;
        }

        return pSafeArray->pvData;

    } else return NULL;

}

This function works well and allows me to conveniently grab the data pointer and to get the number of elements in each dimension by calling like this (assuming vData is a VARIANT passed from Excel:

pDataArray = (VARIANT*) SafeArrayDataPointer(vData, VT_VARIANT, 2, Elems1D, Elems2D); if (pDataArray == NULL) goto error1;

However, there are two things that I do not like about this:

1.) Since the function returns a PVOID I have to cast to the relevant pointer type... but this is redundant as I've already specfied in the second argument what type of array must be contained in the VARIANT. For example in a different situation I may need to make sure that the array is of long values:

pDataArray = (long*) SafeArrayDataPointer(vData, VT_I4, 1, Elems1D, Junk); if (pDataArray == NULL) goto error1;

Again, this works fine, but it is redundant. I would much prefer some mechanism that allows the function to return the correct type of pointer. And I'm hoping this can be done without templates.

2.) I can't figure out how to NOT have the Junk parameter in the second example where I specify that the array must be 1d. Obviously, in such a case, there are no elements in the second dimension.

Aucun commentaire:

Enregistrer un commentaire