-
Dec 17th, 2014, 02:57 AM
#1
Thread Starter
Hyperactive Member
[RESOLVED] How to test an uninitialized dynamic array without using On Error Sentence
-
Dec 17th, 2014, 03:48 AM
#2
Re: How to test an uninitialized dynamic array without using On Error Sentence
There is recent thread discussing this topic.
But why insisting on not having error trapping?
-
Dec 17th, 2014, 06:19 AM
#3
Re: How to test an uninitialized dynamic array without using On Error Sentence
-
Dec 17th, 2014, 07:45 AM
#4
Re: How to test an uninitialized dynamic array without using On Error Sentence
To summarize what those three threads would tell you: Either you live with error trapping or you delve into the OLE API that deals with SAFEARRAYs. In the past I always used error trapping, never liked it but using OLE felt like overkill. You're gonna have to live with it.
-
Dec 17th, 2014, 07:52 AM
#5
Re: How to test an uninitialized dynamic array without using On Error Sentence
The API is quite simple:
Code:
Option Explicit
Private Declare Function SafeArrayGetDim Lib "oleaut32" (ByRef saArray() As Any) As Long
Private Sub Form_Load()
Dim testarray() As String
Debug.Print SafeArrayGetDim(testarray)
End Sub
-
Dec 17th, 2014, 08:32 AM
#6
Re: How to test an uninitialized dynamic array without using On Error Sentence
Quite an interesting module here:
http://web.mit.edu/sde/interface/arc...SSafeArray.bas
Code:
' modSDSSafeArray
'
' Utility functions for SafeArrays. Visual Basic arrays are
' SafeArrays.
'
' 2003-06-12 - Thomas H. Grayson - Creation
'
' Copyright 2003 by the Massachusetts Institute of Technology
' All Rights Reserved.
'
' Copyright Notes:
' Much of this code are copied or adapted from other
' sources, whose copyrights are noted along with the code.
'
' Much of the code comes from the vbAdvance website at this
' page:
' http://www.vbadvance.com/arrays.htm
'
' This page bears the following copyright notice:
' Copyright 2002
' Young Dynamic Software
' All Rights Reserved.
'
' The URL above can be reached from a link on their code
' samples page, which includes the same copyright notice
' and this explanatory text:
' The following code samples are provided as a courtesy.
' We assume no liability resulting from their use. Use at
' your own risk. We're just trying to be helpful by
' providing them. If you find any problems with the
' samples, please drop us a line so that we can make
' corrections. They've been tested under VB6 and are
' believed to be accurate.
'
' Note that the definitions of UBoundEx and ArrayHasDims
' closely match the functions UBoundEx and ArrayIsEmpty
' posted by Peter Young under the subject "Re: VB5 code
' generation error - lbound/on error resume next" in the
' newsgroup microsoft.public.vb.bugs on 2002-06-26, viewable
' at this URL:
' http://groups.google.com/groups?hl=e...ftngp13&rnum=2
' He gives the impression that he wrote the functions himself,
' and it is possible that vbAdvance.com adapted his posting.
' The LBoundEx function is a minor modification of UBoundEx.
Option Explicit
' CopyMemory
'
' This function copies Length bytes of data from the Source
' to the Destination. A pointer stored in a long variable can
' be dereference by passing it ByVal in the Source argument.
'
' The declaration of CopyMemory was copied from the WIN32API.TXT
' file that ships with Microsoft Visual Studio 6.0, then slightly
' modified. The content of this file may be reused freely, and
' includes this copyright notice:
'
' Copyright (C) 1994-98 Microsoft Corporation
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(Destination As Any, Source As Any, ByVal Length As Long)
' SafeArrayGetDim
'
' This function returns the numbers of dimensions in a SafeArray. We are
' using it to determine if a dynamic array has been initialized as suggested
' on this web page:
' http://www.platformdev.com/newsletter/tips01.htm
' Another source is here:
' http://www.vbadvance.com/arrays.htm
'
' Yet another source for this information, with a different form of the
' Declare Function statement, can be found here:
' http://www.vbxtras.com/vbhowto/VBHowTo90.txt
' This version defines the argument as "ByRef SafeArray() As Any".
' This sounds like a great idea, but VB passes a pointer to the pointer
' to the array, not the array pointer itself (as documented in the
' file VB4DLL.TXT that shipped with VB4 (and found in the Google cache)).
' Hence, we need to dereference the pointer and then pass that to the
' SafeArrayGetDim function.
'
' Microsoft's documentation on passing VB arrays to C functions is
' here:
' http://support.microsoft.com/default.aspx?scid=kb;[LN];207931
'
' Microsoft's documentation on the function can be found on MSDN here:
' http://msdn.microsoft.com/library/en...chap7_7mwd.asp
' The psa argument is a pointer to a SafeArray (SAFEARRAY * in C).
'
' This particular version of the declaration of SafeArrayGetDim
' matches the version at:
' http://www.vbadvance.com/arrays.htm
Private Declare Function SafeArrayGetDim Lib "oleaut32.dll" _
(ByVal pSA As Long) As Long
'(ByRef SafeArray() As Any) As Long
' The VarPtrArray function is documented in Microsoft Knowlege Base
' article 199824 entitled "HOWTO: Get the Address of Variables in Visual
' Basic" here:
' http://support.microsoft.com/default...b;en-us;199824
Private Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" _
(Var() As Any) As Long
' This function declaration copied from:
' http://www.vbadvance.com/arrays.htm
' Copyright 2002
' Young Dynamic Software
' All Rights Reserved.
Private Declare Function SafeArrayGetUBound Lib "oleaut32.dll" _
(ByVal pSA As Long, _
ByVal nDim As Long, _
ByRef plUbound As Long) As Long
' This function declaration copied from:
' http://www.vbadvance.com/arrays.htm
' Copyright 2002
' Young Dynamic Software
' All Rights Reserved.
Private Declare Function SafeArrayGetLBound Lib "oleaut32.dll" _
(ByVal pSA As Long, _
ByVal nDim As Long, _
ByRef plLbound As Long) As Long
' This function copied from:
' http://www.vbadvance.com/arrays.htm
' Copyright 2002
' Young Dynamic Software
' All Rights Reserved.
'
' Note: This function should probably do the same test that
' UBoundEx and LBoundEx do to see if the array was passed
' by reference, which it usually is, but perhaps might not be.
Public Function ArrayHasDims(vArray As Variant) As Boolean
Dim pSA As Long
'Make sure an array was passed in:
If IsArray(vArray) Then
'Get the pointer out of the Variant:
CopyMemory pSA, ByVal VarPtr(vArray) + 8, 4
If pSA Then
'Try to get the descriptor:
CopyMemory pSA, ByVal pSA, 4
'Array is initialized only if we got the SAFEARRAY descriptor:
ArrayHasDims = pSA
End If
End If
End Function
' This function copied from:
' http://www.vbadvance.com/arrays.htm
' Copyright 2002
' Young Dynamic Software
' All Rights Reserved.
Public Function UBoundEx(ByRef vArray As Variant, _
Optional ByVal lDimension As Long = 1) As Long
Dim iDataType As Integer
Dim pSA As Long
Dim lRet As Long
Const VT_BYREF = &H4000
Const VARIANT_DATA_OFFSET As Long = 8
'Make sure an array was passed in:
If IsArray(vArray) Then
'Try to get the pointer:
CopyMemory pSA, ByVal VarPtr(vArray) + VARIANT_DATA_OFFSET, 4
If pSA Then
'If byref then deref the pointer to get the actual pointer:
CopyMemory iDataType, vArray, 2
If iDataType And VT_BYREF Then
CopyMemory pSA, ByVal pSA, 4
End If
If pSA Then
If lDimension > 0 Then
'Make sure this is a valid array dimension:
If lDimension <= SafeArrayGetDim(pSA) Then
'Get the UBound:
SafeArrayGetUBound pSA, lDimension, UBoundEx
Else
UBoundEx = -1
End If
Else
Err.Raise vbObjectError Or 10000, "UBoundEx", "Invalid Dimension"
End If
Else
UBoundEx = -1
End If
Else
UBoundEx = -1
End If
Else
Err.Raise vbObjectError Or 10000, "UBoundEx", "Not an array"
End If
End Function
' This function copied from:
' http://www.vbadvance.com/arrays.htm
' Copyright 2002
' Young Dynamic Software
' All Rights Reserved.
Public Function LBoundEx(ByRef vArray As Variant, _
Optional ByVal lDimension As Long = 1) As Long
Dim iDataType As Integer
Dim pSA As Long
Dim lRet As Long
Const VT_BYREF = &H4000
Const VARIANT_DATA_OFFSET As Long = 8
'Make sure an array was passed in:
If IsArray(vArray) Then
'Try to get the pointer:
CopyMemory pSA, ByVal VarPtr(vArray) + VARIANT_DATA_OFFSET, 4
If pSA Then
'If byref then deref the pointer to get the actual pointer:
CopyMemory iDataType, vArray, 2
If iDataType And VT_BYREF Then
CopyMemory pSA, ByVal pSA, 4
End If
If pSA Then
If lDimension > 0 Then
'Make sure this is a valid array dimension:
If lDimension <= SafeArrayGetDim(pSA) Then
'Get the LBound:
SafeArrayGetLBound pSA, lDimension, LBoundEx
Else
LBoundEx = -1
End If
Else
Err.Raise vbObjectError Or 10000, "LBoundEx", "Invalid Dimension"
End If
Else
LBoundEx = -1
End If
Else
LBoundEx = -1
End If
Else
Err.Raise vbObjectError Or 10000, "LBoundEx", "Not an array"
End If
End Function
' This function adapted from the UBoundEx function, which was
' copied from:
' http://www.vbadvance.com/arrays.htm
' Copyright 2002
' Young Dynamic Software
' All Rights Reserved.
'
' 2003-06-12 - Thomas H. Grayson - Creation
' Adapted the UBoundEx function to return the number of dimensions
' in the array
Public Function ArrayGetDim(ByRef vArray As Variant) As Long
Dim iDataType As Integer
Dim pSA As Long
Dim lRet As Long
Dim lDimension As Long
Const VT_BYREF = &H4000
Const VARIANT_DATA_OFFSET As Long = 8
'Make sure an array was passed in:
If IsArray(vArray) Then
'Try to get the pointer:
CopyMemory pSA, ByVal VarPtr(vArray) + VARIANT_DATA_OFFSET, 4
If pSA Then
'If byref then deref the pointer to get the actual pointer:
CopyMemory iDataType, vArray, 2
If iDataType And VT_BYREF Then
CopyMemory pSA, ByVal pSA, 4
End If
If pSA Then
ArrayGetDim = SafeArrayGetDim(pSA)
End If
End If
Else
Err.Raise vbObjectError Or 10000, "ArrayGetDim", "Not an array"
End If
End Function
-
Dec 17th, 2014, 11:29 AM
#7
Re: How to test an uninitialized dynamic array without using On Error Sentence
Originally Posted by Arnoutdv
The API is quite simple:
Code:
Option Explicit
Private Declare Function SafeArrayGetDim Lib "oleaut32" (ByRef saArray() As Any) As Long
Private Sub Form_Load()
Dim testarray() As String
Debug.Print SafeArrayGetDim(testarray)
End Sub
That's not reliable (and was already pointed out in one of the threads you linked to).
http://www.vbforums.com/showthread.p...=1#post4533513
Code:
Option Explicit
Private Declare Function GetDim Lib "oleaut32" Alias "SafeArrayGetDim" (Arr() As Any) As Long
Private Sub Form_Load()
Dim L1&(): ReDim L1(0)
Dim L2&(): ReDim L2(0)
Dim L3&(): ReDim L3(0)
Dim L4&(): ReDim L4(0)
Dim L5&(): ReDim L5(0)
Debug.Print GetDim(L1), GetDim(L2), GetDim(L3), GetDim(L4), GetDim(L5)
End Sub
This prints out increasing values here on my machine:
18496 18736 19312 19456 19504
So these are the lower 16 Bits of the *Pointer* of the SafeArray-Struct, not the first
16 Bits of the Memory this Pointer points to (which would be the SafeArray.cDims Member).
And these Values of the lower 16Bit (as you see see them increase above) could
quite easily come out at exactly the next 16Bit-Overflow-Boundaries - which would
mean - that in this case you will get handed out a Zero as return-value, *despite*
that the array was dimmed.
Well, it would be more critical when it was the other way around...:
when the array would be reported as dimmed, but in fact was not dimmed -
whereas the above could only mislead in telling, that the array was not dimmed, although it was.
Anyways, if one wants to use a more reliable way per API, then the stuff wqweto
has posted at the end of the thread I linked to above covered the topic quite well...
Though in most cases it will be enough to use an error-handler-based simple function like
this in a *.bas.
Code:
Function IsDimmed(Arr As Variant) As Boolean
On Error GoTo ReturnFalse
IsDimmed = UBound(Arr) >= LBound(Arr)
ReturnFalse:
End Function
Olaf
Last edited by Schmidt; Dec 17th, 2014 at 11:39 AM.
-
Dec 23rd, 2014, 10:05 AM
#8
Thread Starter
Hyperactive Member
Re: How to test an uninitialized dynamic array without using On Error Sentence
Originally Posted by Niya
To summarize what those three threads would tell you: Either you live with error trapping or you delve into the OLE API that deals with SAFEARRAYs. In the past I always used error trapping, never liked it but using OLE felt like overkill. You're gonna have to live with it.
This is probably true ...
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|