It uses a Variant for the input parameter so that you don't need to have a specific array type (Byte, Integer, etc) when putting the array into the parameter. It then uses API functions, rather than VB6 functions, for handling the SafeArray so as to be usable regardless of the data type of the array, regardless of the number of dimensions, and regardless of the lower bounds of the dimensions. It copies the entire content of the array (as long as it's a fairly normal type, not something with variable length entries like an array of strings or variants) to a byte array. This is very useful if you want to treat the array as a single chunk of data, such as for input to various functions that act on a single large piece of data. These might be checksum, CRC, or hash type functions, or even an encryption function. This should work with any arrays of any of the numeric data types (Byte, Integer, Long, Currency, Single, or Double).
Below is the code for this function, as well as the declare statements that you will need to make it work.
Here's some code to test it out. Make sure that your Form1 has the property AutoRedraw set to True.
The value printed on Form1 should be 63.
Here's why. There are 2 dimensions. The upper bounds are 3 and 1. The lower bounds are both 0. So this is a size of 4 in the first dimension, and 2 in the second dimension. This makes 8 elements. Since each element is of Currency type, which occupies 8 bytes, this gives 8*8=64 bytes. Since the byte array returned from the function has 0 as the lower bound, the upper bound is 63.
Below is the code for this function, as well as the declare statements that you will need to make it work.
Code:
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
Private Declare Sub SafeArrayAccessData Lib "oleaut32.dll" (ByVal psa As Long, ByRef ppvData As Any)
Private Declare Sub SafeArrayUnaccessData Lib "oleaut32.dll" (ByVal psa As Long)
Private Declare Function SafeArrayGetDim Lib "oleaut32.dll" (ByVal psa As Long) As Long
Private Declare Function SafeArrayGetElemsize Lib "oleaut32.dll" (ByVal psa As Long) As Long
Private Function AnyArrayToBytes(ByVal SafeArray As Variant) As Byte()
Dim SArrayPtr As Long
Dim ElemSize As Long
Dim DimCount As Long
Dim ElemsInDim As Long
Dim TotalElems As Long
Dim DataSize As Long
Dim DataPtr As Long
Dim Bytes() As Byte
Dim n As Long
CopyMemory SArrayPtr, ByVal VarPtr(SafeArray) + 8, 4
If SArrayPtr = 0 Then Exit Function
DimCount = SafeArrayGetDim(SArrayPtr)
ElemSize = SafeArrayGetElemsize(SArrayPtr)
TotalElems = 1
For n = 0 To DimCount - 1
CopyMemory ElemsInDim, ByVal SArrayPtr + 16 + n * 8, 4
TotalElems = TotalElems * ElemsInDim
Next n
DataSize = TotalElems * ElemSize
ReDim Bytes(DataSize - 1)
SafeArrayAccessData SArrayPtr, DataPtr
CopyMemory Bytes(0), ByVal DataPtr, DataSize
SafeArrayUnaccessData SArrayPtr
AnyArrayToBytes = Bytes()
End Function
Here's some code to test it out. Make sure that your Form1 has the property AutoRedraw set to True.
Code:
Private Sub Form_Load()
Dim a(3, 1) As Currency
Dim b() As Byte
b() = AnyArrayToBytes(a)
Print UBound(b)
End Sub
The value printed on Form1 should be 63.
Here's why. There are 2 dimensions. The upper bounds are 3 and 1. The lower bounds are both 0. So this is a size of 4 in the first dimension, and 2 in the second dimension. This makes 8 elements. Since each element is of Currency type, which occupies 8 bytes, this gives 8*8=64 bytes. Since the byte array returned from the function has 0 as the lower bound, the upper bound is 63.