If I have an array with n-dimensions, where n is an unknown number until runtime, how do I index into that array?
ReDim indices(1 to n) As Long = array(1,2,3)
data(1,2,3) 'n = 3
data(*indices) 'I want this
(we can work out n using this https://github.com/cristianbuse/VBA-ArrayTools/blob/c23cc6ba550e7ebaed1f26808501ea3afedf1a3b/src/LibArrayTools.bas#L730-L741)
Public Function GetArrayDimsCount(ByRef arr As Variant) As Long Const MAX_DIMENSION As Long = 60 'VB limit Dim dimension As Long Dim tempBound As Long ' On Error GoTo FinalDimension For dimension = 1 To MAX_DIMENSION tempBound = LBound(arr, dimension) Next dimension FinalDimension: GetArrayDimsCount = dimension - 1 End Function
The following does what I want I think but I was wondering is there an obvious way to do this in VBA (*pv void looks like a headache)
HRESULT SafeArrayGetElement(
[in] SAFEARRAY *psa,
[in] LONG *rgIndices,
[out] void *pv
);
With a bit of memory trickery you can look at your multidimensional array as a one dimensional array. You will need LibMemory:
Quick test:
Edit #1
This is a response to a series of interesting questions asked by the OP in the comments section. Not only the response is too long but it should definitely be part of the answer.
When copying the SAFEARRAY structure, we also copy the
pvDatapointer pointing to the actual data. The fake array is pointing to the same data in memory so we're fooling the array handling code to read that data directly (not ByRef). But, we need to set the ByRef flag on thevaluesVariant to avoid releasing the same memory twice which would cause a crash. But nothing so far is ByRef - just 2 array variables pointing to the same data.If the original data is having ByRef members (paramarray of VARIANTARGS) that could only happen if we use something like the
CloneParamArraymethod because otherwise VB doesn't allow to pass the param array around, at least not natively. In this case, accessing the ByRef members via the fake array can only be done correctly via an utility function that can receive such a member ByRef.Example:
If one uses
CloneParamArrayon purpose then one should be aware anyway that the ByRef individual Variant members can only be accesed/changed via utility methods likePrintVarandLetByRefor any other method expecting a ByRef Variant as an argument.Because we don't know what the array type is (e.g.
Long()orVariant()) then we obviously must wrap in a Variant when we pass to theArrayToFakeArraymethod. Passing the wrapped arrayByValdoes make a copy and we can see that by runing the below:So, we need to pass the wrapped array
ByRefso thatArrPtrreturns the correct address of the SAFEARRAY structure.