Using Arrays

OLE 2 provides a special data type for arrays passed from Visual Basic to a DLL. This data type, called a SAFEARRAY, allows both Visual Basic and the DLL to allocate, free, and access array data in a controlled way.

Your DLL should always use OLE Automation functions to allocate and access SAFEARRAYs. These functions are described in Chapter 6 in Volume 2 of the OLE 2 Programmer's Reference. When OLE Automation passes a SAFEARRAY to your DLL, you receive a pointer to a pointer to the array itself. Like BSTR pointers, a SAFEARRAY pointer may point to a NULL array if the array has been declared but not yet dimensioned:

Dim a() as Integer

The pointer itself will never be NULL, however.

The following example determines the upper and lower bounds of an array and then loops through the array producing the sum of the elements in the array:

short WINAPI SumArray(
    LPSAFEARRAY *ppsa, long *plResult)
{
    short iElem;
    long lLb, lUb, l, lResult;

    if (*ppsa == NULL) // array has not been initialized
        return -4;

    if ((*ppsa)->cDims != 1)    // check number of dimensions
        return -5;

    // get the upper and lower bounds of the array

    if (FAILED(SafeArrayGetLBound(*ppsa, 1, &lLb)) ||
            FAILED(SafeArrayGetUBound(*ppsa, 1, &lUb)))
        return -1;
    
    // loop through the array and add the elements

    for (l = lLb, lResult = 0; l <= lUb; l++) 
    {
        if (FAILED(SafeArrayGetElement(*ppsa, &l, &iElem)))
            return -2;
        lResult += iElem;
    }

    *plResult = lResult;
    return 0;
}

Declared and called from Visual Basic:

Declare Function SumArray Lib "debug\ADVDLL.DLL" _
    (a() As Integer, r As Long) As Integer

Sub SumArrayTest()
    Dim n(5) As Integer
    Dim result As Long
    For i = 0 To 5
        n(i) = 2
    Next
    x = SumArray(n, result)
    MsgBox x & ":" & result
End Sub

Visual Basic does minimal type checking and enforcement on array element size. Because this function was declared as accepting only an array of integers, it is safe to use an integer element in the call to the SafeArrayGetElement function in the DLL. If the function was declared as accepting an array of any type, however, the Visual Basic code might pass an array of long values; in this case, the C-language function would produce incorrect results. If your DLL function must accept an array of any type, you should use an array of variants and check the variant type in the DLL.