Test for Empty Array

  • Thread starter Thread starter Terry
  • Start date Start date
T

Terry

How can I test if array() as variant has not been dim/redim'd, eg 'empty'

I've tried a few things but not found an answer yet.

Regards
 
You can use the following function:

Public Function IsInitialized(ByVal testArray As Variant)
As Boolean
Dim result As Boolean
On Error Resume Next
result = UBound(testArray) > -1
IsInitialized = result
End Function

HTH
 
Hi,
The easiest way is to use UBound and trap the error you'll get if it
hasen't been dimensioned.

Alternatively, I found this code and did a quick test with access 97 and immediately
got a page fault. I'll post it though and you can troubleshoot it if you like: (watch out for line wrap)

This will go in a standard module:

Option Compare Database
Option Explicit

Type SAFEARRAYBOUND
cElements As Long ' # of elements in the array dimension
lLbound As Long ' lower bounds of the array dimension
End Type

Public Type SAFEARRAY
cDims As Integer ' // Count of dimensions in this array.
fFeatures As Integer ' // Flags used by the SafeArray
' // routines documented below.
cbElements As Long ' // Size of an element of the array.
' // Does not include size of
' // pointed-to data.
cLocks As Long ' // Number of times the array has been
' // locked without corresponding unlock.
pvData As Long ' // Pointer to the data.
' Should be sized to cDims:
rgsabound() As SAFEARRAYBOUND ' // One bound for each dimension.
End Type
Const VT_BYREF = &H4000&

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpDest As Any, lpSource As Any, ByVal cBytes As Long)

Public Function GetArrayInfo(TheArray As Variant, ArrayInfo As SAFEARRAY) As Boolean
Dim lp As Long, VType As Integer
If Not IsArray(TheArray) Then Exit Function
With ArrayInfo
' Get the VARTYPE value from the first 2 bytes of the VARIANT structure
CopyMemory ByVal VarPtr(VType), ByVal VarPtr(TheArray), 2
' Get the pointer to the array descriptor (SAFEARRAY structure)
' NOTE: A Variant's descriptor, padding & union take up 8 bytes.
CopyMemory ByVal VarPtr(lp), ByVal (VarPtr(TheArray) + 8), 4
' Test if lp is a pointer or a pointer to a pointer.
If (VType And VT_BYREF) <> 0 Then
' Get real pointer to the array descriptor (SAFEARRAY structure)
CopyMemory ByVal VarPtr(lp), ByVal lp, 4
End If
' Fill the SAFEARRAY structure with the array info
' NOTE: The fixed part of the SAFEARRAY structure is 16 bytes.
CopyMemory ByVal VarPtr(ArrayInfo.cDims), ByVal lp, 16
' Ensure the array has been dimensioned before getting SAFEARRAYBOUND information
If ArrayInfo.cDims > 0 Then
' Size the array to fit the # of bounds
ReDim .rgsabound(1 To .cDims)
' Fill the SAFEARRAYBOUND structure with the array info
CopyMemory ByVal VarPtr(.rgsabound(1)), ByVal lp + 16, ArrayInfo.cDims * Len(.rgsabound(1))
' So caller knows there is information available for the array in output SAFEARRAY
GetArrayInfo = True
End If
End With
End Function

And this could go in your form:
Private Sub cmdArray_Click()
Dim sa As SAFEARRAY
Dim myArr() As Variant
If GetArrayInfo(arr, sa) Then
MsgBox "Array have " & sa.cDims & " dimensions."
Else
MsgBox "Array not dimensioned yet"
End If

End Sub

Good luck!
 
Hi Sergey,
Thanks for the help.
Regards

Sergey Poberezovskiy said:
You can use the following function:

Public Function IsInitialized(ByVal testArray As Variant)
As Boolean
Dim result As Boolean
On Error Resume Next
result = UBound(testArray) > -1
IsInitialized = result
End Function

HTH
 
Hi Dan,
I'll give it a whirl, thanks.
Regards

Dan Artuso said:
Hi,
The easiest way is to use UBound and trap the error you'll get if it
hasen't been dimensioned.

Alternatively, I found this code and did a quick test with access 97 and immediately
got a page fault. I'll post it though and you can troubleshoot it if you
like: (watch out for line wrap)
This will go in a standard module:

Option Compare Database
Option Explicit

Type SAFEARRAYBOUND
cElements As Long ' # of elements in the array dimension
lLbound As Long ' lower bounds of the array dimension
End Type

Public Type SAFEARRAY
cDims As Integer ' // Count of dimensions in this array.
fFeatures As Integer ' // Flags used by the SafeArray
' // routines documented below.
cbElements As Long ' // Size of an element of the array.
' // Does not include size of
' // pointed-to data.
cLocks As Long ' // Number of times the array has been
' // locked without corresponding unlock.
pvData As Long ' // Pointer to the data.
' Should be sized to cDims:
rgsabound() As SAFEARRAYBOUND ' // One bound for each dimension.
End Type
Const VT_BYREF = &H4000&

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory"
(lpDest As Any, lpSource As Any, ByVal cBytes As Long)
Public Function GetArrayInfo(TheArray As Variant, ArrayInfo As SAFEARRAY) As Boolean
Dim lp As Long, VType As Integer
If Not IsArray(TheArray) Then Exit Function
With ArrayInfo
' Get the VARTYPE value from the first 2 bytes of the VARIANT structure
CopyMemory ByVal VarPtr(VType), ByVal VarPtr(TheArray), 2
' Get the pointer to the array descriptor (SAFEARRAY structure)
' NOTE: A Variant's descriptor, padding & union take up 8 bytes.
CopyMemory ByVal VarPtr(lp), ByVal (VarPtr(TheArray) + 8), 4
' Test if lp is a pointer or a pointer to a pointer.
If (VType And VT_BYREF) <> 0 Then
' Get real pointer to the array descriptor (SAFEARRAY structure)
CopyMemory ByVal VarPtr(lp), ByVal lp, 4
End If
' Fill the SAFEARRAY structure with the array info
' NOTE: The fixed part of the SAFEARRAY structure is 16 bytes.
CopyMemory ByVal VarPtr(ArrayInfo.cDims), ByVal lp, 16
' Ensure the array has been dimensioned before getting SAFEARRAYBOUND information
If ArrayInfo.cDims > 0 Then
' Size the array to fit the # of bounds
ReDim .rgsabound(1 To .cDims)
' Fill the SAFEARRAYBOUND structure with the array info
CopyMemory ByVal VarPtr(.rgsabound(1)), ByVal lp + 16,
ArrayInfo.cDims * Len(.rgsabound(1))
 
Hi Dan,
Trapping error 9 does the job, thanks.
regards

Dan Artuso said:
Hi,
The easiest way is to use UBound and trap the error you'll get if it
hasen't been dimensioned.

Alternatively, I found this code and did a quick test with access 97 and immediately
got a page fault. I'll post it though and you can troubleshoot it if you
like: (watch out for line wrap)
This will go in a standard module:

Option Compare Database
Option Explicit

Type SAFEARRAYBOUND
cElements As Long ' # of elements in the array dimension
lLbound As Long ' lower bounds of the array dimension
End Type

Public Type SAFEARRAY
cDims As Integer ' // Count of dimensions in this array.
fFeatures As Integer ' // Flags used by the SafeArray
' // routines documented below.
cbElements As Long ' // Size of an element of the array.
' // Does not include size of
' // pointed-to data.
cLocks As Long ' // Number of times the array has been
' // locked without corresponding unlock.
pvData As Long ' // Pointer to the data.
' Should be sized to cDims:
rgsabound() As SAFEARRAYBOUND ' // One bound for each dimension.
End Type
Const VT_BYREF = &H4000&

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory"
(lpDest As Any, lpSource As Any, ByVal cBytes As Long)
Public Function GetArrayInfo(TheArray As Variant, ArrayInfo As SAFEARRAY) As Boolean
Dim lp As Long, VType As Integer
If Not IsArray(TheArray) Then Exit Function
With ArrayInfo
' Get the VARTYPE value from the first 2 bytes of the VARIANT structure
CopyMemory ByVal VarPtr(VType), ByVal VarPtr(TheArray), 2
' Get the pointer to the array descriptor (SAFEARRAY structure)
' NOTE: A Variant's descriptor, padding & union take up 8 bytes.
CopyMemory ByVal VarPtr(lp), ByVal (VarPtr(TheArray) + 8), 4
' Test if lp is a pointer or a pointer to a pointer.
If (VType And VT_BYREF) <> 0 Then
' Get real pointer to the array descriptor (SAFEARRAY structure)
CopyMemory ByVal VarPtr(lp), ByVal lp, 4
End If
' Fill the SAFEARRAY structure with the array info
' NOTE: The fixed part of the SAFEARRAY structure is 16 bytes.
CopyMemory ByVal VarPtr(ArrayInfo.cDims), ByVal lp, 16
' Ensure the array has been dimensioned before getting SAFEARRAYBOUND information
If ArrayInfo.cDims > 0 Then
' Size the array to fit the # of bounds
ReDim .rgsabound(1 To .cDims)
' Fill the SAFEARRAYBOUND structure with the array info
CopyMemory ByVal VarPtr(.rgsabound(1)), ByVal lp + 16,
ArrayInfo.cDims * Len(.rgsabound(1))
 
Back
Top