|
Option Explicit |
|
|
|
' 参考: [How Visual Basic 6 Stores Data | CodeGuru](https://www.codeguru.com/visual-basic/how-visual-basic-6-stores-data/) |
|
|
|
Private Declare PtrSafe Sub RtlMoveMemory Lib "Kernel32" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As LongPtr) |
|
|
|
Private Type ArrayBase |
|
cDim As Integer ' A count of the number of dimensions in the array. |
|
fFeature As Integer ' Flags |
|
cbElements As Long ' Size of each element in the array. |
|
cLocks As Long ' Used to lock the array. |
|
pvData As LongPtr ' A pointer to the first data element in the array. |
|
rgsabound As Variant ' Safe_Array_Bound array. ※cDim個のSafe_Array_Boundが一番右の次元→左の次元の順に並ぶ |
|
End Type |
|
|
|
Private Type Safe_Array_Bound |
|
cElements As Long ' The number of elements in the dimension. |
|
lLbound As Long ' The lower bound of the dimension. |
|
End Type |
|
|
|
Private Enum ArrayFeatureFlag |
|
FADF_AUTO = &H1& ' Array is allocated on the stack. |
|
FADF_STATIC = &H2& ' Array is statically allocated. |
|
FADF_EMBEDDED = &H4& ' Array is embedded in a structure. |
|
FADF_FIXEDSIZE = &H10& ' Array may not be resized or reallocated. |
|
FADF_BSTR = &H100& ' An array of BSTRs. |
|
FADF_UNKNOWN = &H200& ' An array of IUnknown*. |
|
FADF_DISPATCH = &H400& ' An array of IDispatch*. |
|
FADF_VARIANT = &H800& ' An array of VARIANTs. |
|
FADF_RESERVED = &HF0E8& ' Bits reserved for future use. |
|
End Enum |
|
|
|
Public Function RebaseArray(ByRef TargetArray As Variant, Optional ByVal Base As Long = 1, Optional ApplyToFixedArray As Boolean = False) As Long |
|
Const RET_OK As Long = 0 |
|
Const RET_NOT_ARRAY As Long = -1 |
|
Const RET_NOT_INITIALIZED As Long = -2 |
|
Const RET_FIXED_ARRAY As Long = -3 |
|
|
|
Const VT_ARRAY As Integer = vbArray ' &H2000 |
|
Const VT_BYREF As Integer = &H4000 |
|
Const PARRAY_OFFSET As LongPtr = 8 ' vt(VARTYPE:2 bytes)+(WORD:2 bytes)×3 |
|
|
|
Dim vt As Integer |
|
Dim pArray As LongPtr |
|
|
|
Call RtlMoveMemory(vt, TargetArray, LenB(vt)) |
|
If (vt And VT_ARRAY) = &H0 Then |
|
RebaseArray = RET_NOT_ARRAY |
|
Exit Function |
|
End If |
|
|
|
Call RtlMoveMemory(pArray, ByVal (VarPtr(TargetArray) + PARRAY_OFFSET), LenB(pArray)) |
|
If (vt And VT_BYREF) = VT_BYREF Then |
|
Call RtlMoveMemory(pArray, ByVal pArray, LenB(pArray)) |
|
End If |
|
If pArray = 0 Then |
|
RebaseArray = RET_NOT_INITIALIZED |
|
Exit Function |
|
End If |
|
|
|
Dim TargetArrayBase As ArrayBase |
|
Dim BoundArrayOffset As LongPtr: BoundArrayOffset = VarPtr(TargetArrayBase.rgsabound) - VarPtr(TargetArrayBase.cDim) |
|
|
|
Call RtlMoveMemory(TargetArrayBase, ByVal pArray, BoundArrayOffset) |
|
If Not ApplyToFixedArray Then |
|
' [TODO] 静的配列の場合でも書き換えは可能ではあるが、VBEのローカルウィンドウ等で見ると添字は変わらないように見えている |
|
If (TargetArrayBase.fFeature And FADF_FIXEDSIZE) = FADF_FIXEDSIZE Then |
|
RebaseArray = RET_FIXED_ARRAY |
|
Exit Function |
|
End If |
|
End If |
|
|
|
Dim BoundInfo As Safe_Array_Bound |
|
Dim BoundInfoSize As LongPtr: BoundInfoSize = LenB(BoundInfo) |
|
Dim Index As Long |
|
Dim pBound As LongPtr |
|
|
|
|
|
For Index = 0 To TargetArrayBase.cDim - 1 |
|
pBound = pArray + BoundArrayOffset + BoundInfoSize * CLngPtr(Index) |
|
Call RtlMoveMemory(BoundInfo, ByVal pBound, BoundInfoSize) |
|
BoundInfo.lLbound = Base |
|
Call RtlMoveMemory(ByVal pBound, BoundInfo, BoundInfoSize) |
|
Next |
|
|
|
RebaseArray = RET_OK |
|
End Function |