Die Übergabe eines nicht dimensionierten Arrays an die Ubound-Funktion von VB6 führt zu einem Fehler. Ich möchte also überprüfen, ob das Array bereits dimensioniert wurde, bevor ich versuche, seine obere Grenze zu überprüfen. Wie kann ich dies tun?
Antworten
Zu viele Anzeigen?Nota: Der Code wurde aktualisiert, die Originalversion finden Sie in der Revisionsgeschichte (nicht dass es nützlich wäre, sie zu finden). Der aktualisierte Code hängt nicht von der undokumentierten
GetMem4
Funktion und richtig behandelt Arrays aller Typen.Hinweis für VBA-Benutzer: Dieser Code ist für VB6, das nie ein x64-Update erhalten hat. Wenn Sie beabsichtigen, diesen Code für VBA zu verwenden, siehe https://stackoverflow.com/a/32539884/11683 für die VBA-Version. Sie müssen nur die
CopyMemory
Erklärung und diepArrPtr
Funktion, der Rest bleibt.
Ich benutze dies:
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(ByRef Destination As Any, ByRef Source As Any, ByVal length As Long)
Private Const VT_BYREF As Long = &H4000&
' When declared in this way, the passed array is wrapped in a Variant/ByRef. It is not copied.
' Returns *SAFEARRAY, not **SAFEARRAY
Public Function pArrPtr(ByRef arr As Variant) As Long
'VarType lies to you, hiding important differences. Manual VarType here.
Dim vt As Integer
CopyMemory ByVal VarPtr(vt), ByVal VarPtr(arr), Len(vt)
If (vt And vbArray) <> vbArray Then
Err.Raise 5, , "Variant must contain an array"
End If
'see https://msdn.microsoft.com/en-us/library/windows/desktop/ms221627%28v=vs.85%29.aspx
If (vt And VT_BYREF) = VT_BYREF Then
'By-ref variant array. Contains **pparray at offset 8
CopyMemory ByVal VarPtr(pArrPtr), ByVal VarPtr(arr) + 8, Len(pArrPtr) 'pArrPtr = arr->pparray;
CopyMemory ByVal VarPtr(pArrPtr), ByVal pArrPtr, Len(pArrPtr) 'pArrPtr = *pArrPtr;
Else
'Non-by-ref variant array. Contains *parray at offset 8
CopyMemory ByVal VarPtr(pArrPtr), ByVal VarPtr(arr) + 8, Len(pArrPtr) 'pArrPtr = arr->parray;
End If
End Function
Public Function ArrayExists(ByRef arr As Variant) As Boolean
ArrayExists = pArrPtr(arr) <> 0
End Function
Verwendung:
? ArrayExists(someArray)
Ihr Code scheint das Gleiche zu tun (Prüfung auf SAFEARRAY** als NULL), aber auf eine Art und Weise, die ich für einen Compiler-Bug halten würde :)
Ich habe gerade an diesen hier gedacht. Einfach genug, keine API-Aufrufe erforderlich. Irgendwelche Probleme damit?
Public Function IsArrayInitialized(arr) As Boolean
Dim rv As Long
On Error Resume Next
rv = UBound(arr)
IsArrayInitialized = (Err.Number = 0)
End Function
Editar : Ich habe einen Fehler entdeckt, der mit dem Verhalten der Split-Funktion zusammenhängt (eigentlich würde ich es einen Fehler in der Split-Funktion nennen). Nehmen Sie dieses Beispiel:
Dim arr() As String
arr = Split(vbNullString, ",")
Debug.Print UBound(arr)
Wie hoch ist der Wert von Ubound(arr) an dieser Stelle? Er ist -1! Die Übergabe dieses Arrays an die Funktion IsArrayInitialized würde also true zurückgeben, aber der Versuch, auf arr(0) zuzugreifen, würde zu einem Fehler "Subscript out of range" führen.
Ich habe mich für das Folgende entschieden. Das ist ähnlich wie das von GSerg Antwort Sie verwendet jedoch die besser dokumentierte API-Funktion CopyMemory und ist völlig eigenständig (Sie können dieser Funktion einfach das Array anstelle von ArrPtr(array) übergeben). Sie verwendet die VarPtr-Funktion, die Microsoft warnt vor aber dies ist eine reine XP-Anwendung und sie funktioniert, also mache ich mir keine Sorgen.
Ja, ich weiß, dass diese Funktion alles akzeptiert, was man ihr hinwirft, aber ich lasse die Fehlerprüfung als Übung für den Leser.
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(pDst As Any, pSrc As Any, ByVal ByteLen As Long)
Public Function ArrayIsInitialized(arr) As Boolean
Dim memVal As Long
CopyMemory memVal, ByVal VarPtr(arr) + 8, ByVal 4 'get pointer to array
CopyMemory memVal, ByVal memVal, ByVal 4 'see if it points to an address...
ArrayIsInitialized = (memVal <> 0) '...if it does, array is intialized
End Function
Beide Methoden von GSerg und Raven sind undokumentierte Hacks, aber da Visual BASIC 6 nicht mehr entwickelt wird, ist das kein Problem. Das Beispiel von Raven funktioniert jedoch nicht auf allen Rechnern. Sie müssen wie folgt testen.
If (Not someArray) = -1 Then
Auf einigen Rechnern wird eine Null zurückgegeben, auf anderen eine große negative Zahl.
- See previous answers
- Weitere Antworten anzeigen