Results 1 to 3 of 3

Thread: Here's how to reference the same variable in 2 different ways.

  1. #1

    Thread Starter
    Frenzied Member
    Join Date
    Oct 2008
    Posts
    1,238

    Here's how to reference the same variable in 2 different ways.

    This is similar to the way a union works in C or C++. It works by applying custom settings to a SAFEARRAY structure (aka safe array descriptor). I've done a lot of commenting on the code, so others can see exactly how it works.

    Below is the code for the module, which contains the Windows API declarations part of the program.
    Code:
    Public Declare Sub PutMem4 Lib "msvbvm60.dll" (ByRef Destination As Any, ByVal Source As Long)
    Public Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (ByRef ptr() As Any) As Long
    
    Public Type SAFEARRAYBOUND
        NumberOfElements As Long
        FirstElementIndex As Long
    End Type
    
    Public Type SAFEARRAY
        VariantType As Long 'This is actually at offset = -4 in the structure.
        cDims As Integer 'THIS is the official start of the structure (offset = 0).
        fFeatures As Integer
        cbElements As Long
        cLocks As Long
        pvData As Long
        Dim1Info As SAFEARRAYBOUND
    End Type

    And here's the code for Form1. It contains the body of the program's code.
    Code:
    Private Sub Form_Load()
        Dim MyLong As Long
        Dim MyArrayDescriptor As SAFEARRAY
        Dim ptrMyArrayDescriptor() As Byte
        
        'Set up the array descriptor so that the array will be a bytewise representation of the MyLong variable.
        With MyArrayDescriptor
            .VariantType = vbByte 'Data type is byte, and this is how the program would set it if using Redim to initialize the array, though programs written in VB6 actually ignore this field when reading the structure, and instead use the type originally set in the Dim statement when defining the array variable.
            .cDims = 1 'Number of dimensions.
            .cbElements = 1 'Number of bytes per element.
            .fFeatures = &H80 'Tell it to use the VariantType field, though this is actually ignored when VB6 programs read the descriptor in VB6 programs. I just set it like this because this is how VB6 programs set it as well if using Redim to initialize the array.
            .Dim1Info.NumberOfElements = 4
            .pvData = VarPtr(MyLong) 'This makes the array refer to the same location in memory as the MyLong variable.
        End With
        
        
        'Activate the array descriptor by pointing the ptrMyArrayDescriptor variable to the actual array descriptor.
        PutMem4 ByVal VarPtrArray(ptrMyArrayDescriptor), VarPtr(MyArrayDescriptor.cDims)
        
        'Set the MyLong variable to a large value that covers all 4 of its bytes.
        MyLong = &H12345678
        
        'Indepndantly print the value of each of the variable's 4 bytes, in hexadecimal format.
        Print Hex$(ptrMyArrayDescriptor(3))
        Print Hex$(ptrMyArrayDescriptor(2))
        Print Hex$(ptrMyArrayDescriptor(1))
        Print Hex$(ptrMyArrayDescriptor(0))
        
        
        PutMem4 ByVal VarPtrArray(ptrMyArrayDescriptor), 0
        'This last line of code deactivates the pointer to the safe array descriptor, by setting the pointer to 0.
        'This is needed to prevent the program from automatically attempting to deallocate both the descriptor and array content from memory.
        'VB6 automatically inserts code after the end of each function to clean up memory, by deallocating arrays that have gone out of scope.
        'This is normally good. As normally these would be allocated to the heap, or other system assigned memory location, when using Windows API functions to create a safe array.
        'However in this example, this memory is allocated to the stack by the variables called MyLong and MyArrayDescriptor.
        'The result is that the automatic array cleanup could corrupt the stack. Therefore manually setting this pointer to 0 is needed.
        'The stack itself is cleaned up when the function ends.
        'In fact, if the stack got corrupted as previously mentioned, the stack cleanup would likely make the program unstable or even crash immediately.
    End Sub
    Note that you need to set the AutoRedraw property of Form1 to True, in order for the output text to actually display (otherwise it gets cleared before the form displays on the screen).

    If you have everything set up correctly, when you run the program you should see these 4 lines of text printed on the form.
    12
    34
    56
    78

  2. #2
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    6,192

    Re: Here's how to reference the same variable in 2 different ways.

    If you put &H81 in fFeatures you won't have to cleanup the array (last PutMem4) *and* your running project can be safely terminated with End button while array aliasing is active.

    Here is an explanation of the magic numbers:

    FADF_HAVEVARTYPE 0x0080 An array that has a variant type. The variant type can be retrieved with SafeArrayGetVartype.
    FADF_AUTO 0x0001 An array that is allocated on the stack.

    cheers,
    </wqw>

  3. #3
    New Member
    Join Date
    Mar 2012
    Posts
    7

    Re: Here's how to reference the same variable in 2 different ways.

    Quote Originally Posted by wqweto View Post
    If you put &H81 in fFeatures you won't have to cleanup the array (last PutMem4) *and* your running project can be safely terminated with End button while array aliasing is active.

    Here is an explanation of the magic numbers:

    FADF_HAVEVARTYPE 0x0080 An array that has a variant type. The variant type can be retrieved with SafeArrayGetVartype.
    FADF_AUTO 0x0001 An array that is allocated on the stack.

    cheers,
    </wqw>
    Is it possible to achieve this with an array which has been created with COM Safearray api? SafeArrayAllocDescriptorEx with fFeatures = &H81 + SafeArrayAllocData etc.

    I create an alias this way:
    Dim adblAlias() as Double
    CopyMemory ByVal VarPtrArray(adblAlias), pSafeArrayReturnedFromSafeArrayAllocDescriptorEx, SIZEOF_VBA_LONGPTR
    adblArray(1, 1) = 5
    But it crashes when adblAlias goes out of scope.
    (It works if I wipe adblAlias afterwards)

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