Quantcast
Channel: VBForums - CodeBank - Visual Basic 6 and earlier
Viewing all articles
Browse latest Browse all 1480

[VB6] VB6.tlb - Passing a ParamArray without Copying

$
0
0
As with all things VB6, these methods get perfected and streamlined over time.
The typelib included in this project is the only typelib I use in every VB6
project, and addresses the most common issues and holes with the language and
runtime. Obvious things like checking if an array has been allocated, or
reading/writing the pointers of VB's reference types is much easier with a
typelib. Feel free to decompile it, or use it however you want.

The Issue: How do you access a ParamArray, and pass it to another function,
without copying it.
The Answer: Pointer magic. ParamArrays are really just a
Variant Array - managed by the runtime. For whatever reason though - the
runtime / ide doesn't allow you to get at it's address easily, or even pass it
to another function without making a copy

This particular technique I believe was first pioneered by Matt Curland.
Originally Curland used assembly to get the stack pointer,
add a hard coded offset (depending on the function parameters passed before
the ParamArray) to calculate where the SAFEARRAY** is on the stack, then
return the dereferenced pointer. Then you can safely swap the SAFEARRAY
reference with another SAFEARRAY.

Really though - it 's as simple as using a typelib defined __vbaRefVarAry.
Why does it have to be in a typelib? I don't know, but the side effect is
that the runtime marshals the ParamArray ByRef into a VARIANT, without
creating a copy first. This is not typically allowed by the IDE. I haven't
verified if this only applies to midl generated typelibs vs mktyplib.

Anyway... here's the code. Feel free to run it through a debugger to verify
that the ParamArray is indeed not copied.

Code:

Option Explicit

Private Sub Form_Load()
    FuncWithParamArray 1, 2, 3, "test4", "test5"
End Sub

Sub FuncWithParamArray(ParamArray Params())
    OtherFunc GetParams(RefVarAry(Params))
End Sub

Sub OtherFunc(Params())
    Dim Param
    For Each Param In Params
        Debug.Print Param & " ";
    Next
    Debug.Print
End Sub

Function GetParams(ByVal RefParamArray As Long) As Variant()
    GetMem4 ByVal RefParamArray, ByVal RefAry(GetParams)
    PutMem4 ByVal RefParamArray, vbNullPtr
End Function

Attached Files

Viewing all articles
Browse latest Browse all 1480

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>