Pergunta

I'm writing a C++ DLL to be accessed from Excel VBA (it is only completing mathematical equations and doesn't need to be accessed from the worksheet). The DLL is intended to replace current VBA code and I want to write it in C/C++ for performance.

Since I'm am using existing code and simply want to replace the current VBA function with the new DLL I have to use VBA Variants containing single vector arrays. The following is an abbreviated example of the VBA calling code:

Sub VBACaller()
    Dim InputR0(1 To 5) As Variant, vResult As Variant

    InputR0(1) = 26.8
    InputR0(2) = 27.8
    InputR0(3) = 28.8
    InputR0(4) = 29.8

    vResult = ReadArrayVBA(InputR0)
End Sub

I can pass this Variant array to my C++ function either ByVal or ByRef as a VARIANT data type and it appears to be received correctly. My problems occur when I try to read the contents of the array after converting it into a SAFEARRAY using SafeArrayAccessData. The SAFEARRAY conversion seems to work but the contents of the array aren't correct. The following is my C++ code:

VARIANT __stdcall ReadArrayByRef(VARIANT *input0)
{
//Variable to assign value from Array
double d_m = 0;

//Check if this is a variant type or not
if (V_VT(input0) & VT_ARRAY)
{
    SAFEARRAY* pSafeArrayInput0 = NULL;
    pSafeArrayInput0 = V_ARRAY(input0);

    double* pVals;

    HRESULT hr = SafeArrayAccessData(pSafeArrayInput0, (void **)&pVals); // direct access to SA memory
    if (SUCCEEDED(hr))
    {
        long lLBound = -1, lUBound = 1;  // get array bounds
        SafeArrayGetLBound(pSafeArrayInput0, 1, &lLBound);
        SafeArrayGetUBound(pSafeArrayInput0, 1, &lUBound);

        if (lLBound > -1 && lUBound > -1)
        {
            d_m =  pVals[1];
        }
        SafeArrayUnaccessData(pSafeArrayInput0);
    }
}

//Output
VARIANT v;
VariantInit(&v);
v.vt = VT_R8;
v.dblVal = d_m;

return v;
}    

The examples I've found seem to indicate that the .parray should hold the data, however inspection of input0 indicates that it is in .pparray. If I try to assign pSafeArrayInput0 = input0.pparray it gives an error. The value d_m returns is along the lines of 1.05319234616515E-307.

If I change the input to ByVal then I can access the elements of the array correctly using the following C++ code (the only difference being the address of input0 is being accessed by the SAFEARRAY.

VARIANT __stdcall ReadArrayByVal(VARIANT input0)
{
//Variable to assign value from Array
double d_m = 0;

//Check if this is a variant type or not
if (V_VT(&input0) & VT_ARRAY)
{
    SAFEARRAY* pSafeArrayInput0 = NULL;
    pSafeArrayInput0 = V_ARRAY(&input0);

    double* pVals;

    HRESULT hr = SafeArrayAccessData(pSafeArrayInput0, (void **)&pVals); // direct access to SA memory
    if (SUCCEEDED(hr))
    {
        long lLBound = -1, lUBound = 1;  // get array bounds
        SafeArrayGetLBound(pSafeArrayInput0, 1, &lLBound);
        SafeArrayGetUBound(pSafeArrayInput0, 1, &lUBound);

        if (lLBound > -1 && lUBound > -1)
        {
            d_m =  pVals[1];
        }
        SafeArrayUnaccessData(pSafeArrayInput0);
    }
}

VARIANT v; 
VariantInit(&v);
v.vt = VT_R8;
v.dblVal = d_m;

return v;
}

All the examples I've found indicate that passing the VARIANT input by a pointer should works per my ReadArrayByRef function (Ie http://support.microsoft.com/kb/167668 which is slightly different but the same at the points I'm after).

What am I doing wrong in my ByRef function?

Foi útil?

Solução

You should check the VT_BYREF flag, and if it is set, dereference the pointer to access the array like so:

pSafeArrayInput0 = *V_ARRAYREF(input0);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top