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.
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