Use the GetSafeArrayInfo function to rip the lid off a SAFEARRAY. It allows the caller to identify the number of dimensions and number of elements for each dimension (among other things). Element information for each dimension is stored in a one-based subarray of SAFEARRAYBOUND structures (rgsabound):
Public Type SAFEARRAYBOUND ' # of elements in the array dimension cElements As Long ' lower bounds of the array dimension lLbound As LongEnd TypePublic Type SAFEARRAY ' Count of dimensions in this array. cDims As Integer ' Flags used by the SafeArray ' routines documented below. fFeatures As Integer ' Size of an element of the array. ' Does not include size of ' pointed-to data. cbElements As Long ' Number of times the array has been ' locked without corresponding unlock. cLocks As Long ' Pointer to the data. ' Should be sized to cDims: pvData As Long ' One bound for each dimension. rgsabound() As SAFEARRAYBOUNDEnd TypePrivate Declare Sub CopyMemory Lib "kernel32" Alias _ "RtlMoveMemory" (ByVal lpDest As Long, ByVal _ lpSource As Long, ByVal nBytes As Long)Public Function GetSafeArrayInfo(TheArray As _ Variant, ArrayInfo As SAFEARRAY) As Boolean'===================================================' Fills a SAFEARRAY structure for the array.' TheArray: The array to get information on.' ArrayInfo: The output SAFEARRAY structure.' RETURNS: True if the array is instantiated.'=================================================== ' Pointer to the variants data item Dim lpData As Long ' the VARTYPE member of the VARIANT structure Dim VType As Integer Const VT_BYREF As Long = &H4000& ' Exit if no array supplied If Not IsArray(TheArray) Then Exit Function With ArrayInfo ' Get the VARTYPE value from the first 2 bytes ' of the VARIANT structure CopyMemory ByVal VarPtr(VType), ByVal _ VarPtr(TheArray), 2 ' Get the pointer to the array descriptor ' (SAFEARRAY structure) ' NOTE: A Variant's descriptor, padding & ' union take up 8 bytes. CopyMemory ByVal VarPtr(lpData), ByVal _ (VarPtr(TheArray) + 8), 4 ' Test if lpData is a pointer or a pointer to ' a pointer. If (VType And VT_BYREF) <> 0 Then ' Get real pointer to the array _descriptor ' (SAFEARRAY structure) CopyMemory ByVal VarPtr(lpData), _ByVal lpData, 4 ' This will be zero if array not ' dimensioned yet If lpData = 0 Then Exit Function End If ' Fill the SAFEARRAY structure with the array ' info ' NOTE: The fixed part of the SAFEARRAY ' structure is 16 bytes. CopyMemory ByVal VarPtr(ArrayInfo.cDims), _ ByVal lpData, 16 ' Ensure the array has been dimensioned before ' getting SAFEARRAYBOUND information If ArrayInfo.cDims > 0 Then ' Size the array to fit the # of _bounds ReDim .rgsabound(1 To .cDims) ' Fill the SAFEARRAYBOUND structure with ' the array info CopyMemory ByVal VarPtr(.rgsabound(1)), _ ByVal lpData + 16, _ ArrayInfo.cDims _* Len(.rgsabound(1)) ' So caller knows there is information ' available for the array in output ' SAFEARRAY GetSafeArrayInfo = True End If End WithEnd Function