# Visual Basic > Visual Basic 6 and Earlier >  [RESOLVED] CopyVariant or MoveVariant?

## SearchingDataOnly

I often need to copy variants or move variants. Here are some of the methods I used:

*Method 1:*


```
'--- Copies one variant to a destination
'--- @param {ByRef Variant} dest Destination to copy variant to
'--- @param {Variant} value Source to copy variant from.
'--- @perf This appears to be a faster variant of "oleaut32.dll\VariantCopy" + it's multi-platform
Public Sub CopyVariant(ByRef Destination As Variant, ByVal Source As Variant)
    If IsObject(Source) Then
      Set Destination = Source
    Else
      Destination = Source
    End If
End Sub
```

*Method 2:*


```

''
' Provides a way to copy a variant value to another variant without the
' knowledge if Set needs to be used for objects.
'
' @param Destination The variant variable to receive a copy of the value.
' @param Source The variant variable to be copied.
' @remarks This works identical to the Win32 VariantCopyInd API function.
' <p>Any value in the destination variant will be released correctly
' before the source variants is copied into it.</p>
Public Sub CopyVariant(ByRef Destination As Variant, ByRef Source As Variant)
    VariantCopyInd Destination, Source
End Sub
```

I wonder which of the above two methods is better, or if there are others. 

In addition, vbCorLib implements *MoveVariant* function, and I'd like to know how to implement a function similar to MoveVariant in vbCorLib without using ASM code. Thanks!



```
''
' Provides a way to move a variant datatype to another variant without
' the knowledge if Set needs to be used for objects.
'
' @param Destination The variable to move the variant value to.
' @param Source The variable to move the variant value from.
' @remarks This function moves the contents of the source variant to the
' destination variant. It does not make a copy. This lowers duplication
' overhead when a variant value needs to be transfered to another variant.
' <p>Any value in the destination variant will be released correctly
' before the source variants is moved into it.</p>
Public Sub MoveVariant(ByRef Destination As Variant, ByRef Source As Variant)
    Helper.MoveVariant Destination, Source
End Sub
```



```
Private Sub WriteCollection(ByVal Index As Long, ByVal SizeOfCollection As Long, ByRef Source As Variant, ByVal Insert As Boolean)
    If Insert Then
        EnsureCapacity mCount + SizeOfCollection
        InsertSpace Index, SizeOfCollection
        mCount = mCount + SizeOfCollection
    End If
        
    Dim Value As Variant
    For Each Value In Source
        Helper.MoveVariant mItems(Index), Value
        Index = Index + 1
    Next Value
End Sub
```

*Note:*
*Helper* in vbCorLib used Matt Curland's ASM code, and it had a lot of weird problems on my computer. I'd like to be able to implement something similar to vbCorLib's MoveVariant function without using ASM code.

----------


## bahbahbah

Here's one more version, similar to your first one but a bit faster.



```
Private Function MoveVariant2(ByRef Destination As Variant, ByVal Source As Variant)

If VarType(Source) = vbObject Then
   Set Destination = Source
Else
   Destination = Source
End If

End Function
```


Here's my timing for them:
CopyVariant (10000000 its): 1781ms
CopyVariantInd (10000000 its): 984ms
MoveVariant VBCor (10000000 its): 453ms
MoveVariant2 (10000000 its): 1172ms

----------


## bahbahbah

Actually, ignore my response! 

If VarType(Source) = vbObject Then

is never true. The timings for the other functions still stand!

----------


## wqweto

Btw, MoveVariant thunk can be disassembled to this



```
    mov     eax,DWORD PTR [esp+0xc]
    mov     edx,DWORD PTR [esp+0x8]
    mov     ecx,eax
    push    esi
    mov     esi,DWORD PTR [ecx]
    mov     DWORD PTR [edx],esi
    mov     esi,DWORD PTR [ecx+0x4]
    mov     DWORD PTR [edx+0x4],esi
    mov     esi,DWORD PTR [ecx+0x8]
    mov     DWORD PTR [edx+0x8],esi
    pop     esi
    mov     ecx,DWORD PTR [ecx+0xc]
    mov     DWORD PTR [edx+0xc],ecx
    mov     WORD PTR [eax],0x0
    ret     0xc
    nop
    nop
```

cheers,
</wqw>

----------


## georgekar

VarType() on objects return the type of the Default property if any exist

So this code do not do that, check only the type at variant level




```
Public Declare Sub GetMem2 Lib "msvbvm60" (ByVal Addr As Long, retval As Integer)
Public Function myVarType(z, j As Integer) As Boolean
   Dim i As Integer
   GetMem2 VarPtr(z), i
   myVarType = i = j
End Function
```

Some other useful subs.



```
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
    lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)
Private Sub SwapVariant(ByRef a As Variant, ByRef b As Variant)
   Static t(0 To 3) As Long  ' 4 Longs * 4 bytes each = 16 bytes
   CopyMemory t(0), ByVal VarPtr(a), 16
   CopyMemory ByVal VarPtr(a), ByVal VarPtr(b), 16
   CopyMemory ByVal VarPtr(b), t(0), 16
End Sub
Sub SwapString2Variant(ByRef s$, ByRef a As Variant)
   Static t As Long
   CopyMemory ByVal VarPtr(t), ByVal VarPtr(a) + 8, 4
   CopyMemory ByVal VarPtr(a) + 8, ByVal VarPtr(s$), 4
   CopyMemory ByVal VarPtr(s$), ByVal VarPtr(t), 4
End Sub
Sub MoveStringToVariant(ByRef s$, ByRef a As Variant)
   Static t As Long
   a = vbNullString
   CopyMemory ByVal VarPtr(t), ByVal VarPtr(a) + 8, 4
   CopyMemory ByVal VarPtr(a) + 8, ByVal VarPtr(s$), 4
   CopyMemory ByVal VarPtr(s$), ByVal VarPtr(t), 4
End Sub
Function IsOptional(ByRef v) As Boolean
Dim t(0 To 2) As Long
CopyMemory t(0), ByVal VarPtr(v), 12
IsOptional = t(0) = 10 And t(2) = -2147352572
End Function
Function VariantIsRef(ByVal a As Long) As Boolean
Static z As Integer
   CopyMemory z, ByVal a, 2
   VariantIsRef = (z And &H4000) = &H4000
End Function
Sub SwapVariantRef(ByRef a As Variant, ByVal b As Long)
    Static z As Variant
   Static t(0 To 3) As Long
   CopyMemory ByVal VarPtr(t(0)), ByVal b, 16  
   CopyMemory ByVal VarPtr(a), ByVal VarPtr(t(0)), 16
   CopyMemory ByVal b, ByVal VarPtr(z), 16
End Sub
```



```
Private Declare Sub GetMem4 Lib "msvbvm60" (ByVal Addr As Long, retval As Long
Private Declare Sub PutMem4 Lib "msvbvm60" (ByVal Addr As Long, ByVal NewVal As Long)
Sub SwapStrings(a$, b$)
    Dim i As Long, j As Long
    GetMem4 VarPtr(a$), i
    GetMem4 VarPtr(b$), j
    PutMem4 VarPtr(a$), j
    PutMem4 VarPtr(b$), i
End Sub
```

----------


## SearchingDataOnly

> Here's one more version, similar to your first one but a bit faster.
> 
> 
> 
> ```
> Private Function MoveVariant2(ByRef Destination As Variant, ByVal Source As Variant)
> 
> If VarType(Source) = vbObject Then
>    Set Destination = Source
> ...





> Actually, ignore my response! 
> 
> If VarType(Source) = vbObject Then
> 
> is never true. The timings for the other functions still stand!


Yes, if Source is an object and contains default properties, then VarType(Source) is actually VarType(Source.DefaultProperty). But your performance tests are very useful, thank you very much, bahbahbah.

Also, could you test Georgekar's *SwapVariantRef*?  

"*SwapVariantRef a, ByVal VarPtr(b)*" seems to be a good alternative to "*Helper.MoveVariant a, b*".

----------


## SearchingDataOnly

> Btw, MoveVariant thunk can be disassembled to this
> 
> 
> 
> ```
>     mov     eax,DWORD PTR [esp+0xc]
>     mov     edx,DWORD PTR [esp+0x8]
>     mov     ecx,eax
>     push    esi
> ...


Thank you, wqweto. Could you take a look at my other thread Equivalent functions (or APIs) to Matt Curland's ASM code?

----------


## SearchingDataOnly

> VarType() on objects return the type of the Default property if any exist
> 
> So this code do not do that, check only the type at variant level
> 
> 
> 
> 
> ```
> Public Declare Sub GetMem2 Lib "msvbvm60" (ByVal Addr As Long, retval As Integer)
> ...


Very useful code, thank you very much, georgekar.

"*SwapVariantRef a, ByVal VarPtr(b)*" seems to be a good alternative to "*Helper.MoveVariant a, b*".

But *SwapString2Variant* doesn't seem to work, here's my test code:


```
Public Sub Test_SwapString2Variant()
    Dim a, s$
    
    s = "Hello World"
    Debug.Print s, TypeName(s), a, TypeName(a)
    
    SwapString2Variant s, a
    Debug.Assert False
    Debug.Print s, TypeName(s), a, TypeName(a)

End Sub
```

----------


## georgekar

Work, you have to place vbNullString to a
a = vbNullString

----------


## SearchingDataOnly

> Work, you have to place vbNullString to a
> a = vbNullString


Yes, it works. Thank you very much, georgekar.

----------

