Le passage d'un tableau non dimensionné à la fonction Ubound du VB6 provoquera une erreur. Je souhaite donc vérifier s'il a déjà été dimensionné avant de tenter de vérifier sa limite supérieure. Comment puis-je faire cela?
Réponses
Trop de publicités?J'utilise ceci:
Public Declare Function GetMem4 Lib "msvbvm60" (ByVal pSrc As Long, ByVal pDst As Long) As Long
Public Declare Function ArrPtr Lib "msvbvm60" Alias "VarPtr" (arr() As Any) As Long
Public Function StrArrPtr(arr() As String, Optional ByVal IgnoreMe As Long = 0) As Long
GetMem4 VarPtr(IgnoreMe) - 4, VarPtr(StrArrPtr)
End Function
Public Function UDTArrPtr(ByRef arr As Variant) As Long
If VarType(arr) Or vbArray Then
GetMem4 VarPtr(arr) + 8, VarPtr(UDTArrPtr)
Else
Err.Raise 5, , "Variant must contain array of user defined type"
End If
End Function
Public Function ArrayExists(ByVal ppArray As Long) As Long
GetMem4 ppArray, VarPtr(ArrayExists)
End Function
Usage:
? ArrayExists(ArrPtr(someArray))
? ArrayExists(StrArrPtr(someArrayOfStrings))
? ArrayExists(UDTArrPtr(someArrayOfUDTs))
Votre code semble faire la même chose (tester SAFEARRAY ** étant NULL), mais d'une manière que je considérerais comme un bogue du compilateur :)
J'ai juste pensé de celui-ci. Assez Simple, pas d'appels de l'API nécessaires. Pas de problèmes avec elle?
Public Function IsArrayInitialized(arr) As Boolean
Dim rv As Long
On Error Resume Next
rv = UBound(arr)
IsArrayInitialized = (Err.Number = 0)
End Function
Edit: j'ai fait découvrir une faille avec ce lié au comportement de la fonction de répartition (en fait je l'appellerais une faille dans la fonction de répartition). Prenez cet exemple:
Dim arr() As String
arr = Split(vbNullString, ",")
Debug.Print UBound(arr)
Quelle est la valeur de Ubound(arr) à ce point? C'est -1! Ainsi, le passage de cette matrice à cette IsArrayInitialized la fonction renvoie true, mais tenter d'accéder à des arr(0) provoquerait un indice en dehors de la plage d'erreur.
Voici ce que je suis allé avec. Ceci est similaire à GSerg de la réponse, mais utilise les mieux documentés CopyMemory la fonction de l'API et est entièrement autonome (il vous suffit de passer le tableau plutôt que de ArrPtr(array) pour cette fonction). Il utilise la fonction VarPtr, Microsoft met en garde contre l', mais c'est un XP-seule application, et ça marche, donc je ne suis pas concerné.
Oui, je sais que cette fonction accepte tout ce que vous jetez à lui, mais je vais laisser la vérification des erreurs comme exercice pour le lecteur.
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
GSerg et Raven sont des méthodes non documentées, mais comme Visual BASIC 6 n'est plus en développement, ce n'est pas un problème. Cependant, l'exemple de Raven ne fonctionne pas sur toutes les machines. Vous devez tester comme ça.
Si (pas un tableau) = -1 alors
Sur certaines machines, il retournera un zéro sur d'autres, un nombre négatif élevé.