Results 1 to 8 of 8

Thread: [RESOLVED] How to test an uninitialized dynamic array without using On Error Sentence

  1. #1

    Thread Starter
    Hyperactive Member
    Join Date
    Sep 2014
    Posts
    341

    Resolved [RESOLVED] How to test an uninitialized dynamic array without using On Error Sentence

    As written in the title.

  2. #2
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    5,910

    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?

  3. #3
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    5,910

    Re: How to test an uninitialized dynamic array without using On Error Sentence


  4. #4
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,601

    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.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  5. #5
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    5,910

    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

  6. #6
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    5,910

    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

  7. #7
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,259

    Re: How to test an uninitialized dynamic array without using On Error Sentence

    Quote Originally Posted by Arnoutdv View Post
    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.

  8. #8

    Thread Starter
    Hyperactive Member
    Join Date
    Sep 2014
    Posts
    341

    Re: How to test an uninitialized dynamic array without using On Error Sentence

    Quote Originally Posted by Niya View Post
    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
  •  



Click Here to Expand Forum to Full Width