Home All Groups Group Topic Archive Search About
Author
20 Oct 2005 10:54 AM
Robert
Hello folks,

I've written a function to compare two Variant variables some time ago. It
could do variant arrays and all the simple data types (I don't know what's
actually contained within the variant, it depends on what it's used for).

Now I'd like to add a comparison between two variables of user-defined types
(each stored in a variant). I don't know anything about their structure,
excpect what I can get from the variant variable (that is: the size in
bytes)
I've found out that the variant hold a pointer to the UDT, and I can dump
the memory content of the UDT into a byte (or long) array - info about the
internal data structure can be found here:
http://www.codeguru.com/vb/gen/vb_misc/algorithms/article.php/c7495/

Now, as soon as the UDT contains strings or variants, I'll once again have
pointers within the data I wish to compare - and I don't know where they
are, so I cannot compare strings stored within the UDT. Does anyone have an
idea how I could compare two UDTs stored in a variant each? What I don't
need are references to objects, but I do need the ability to compare strings
stored in the UDTs.

Here's the code I'm using so far:

Private Declare Sub CopyMemoryRead Lib "kernel32" Alias _
"RtlMoveMemory" (Destination As Any, ByVal Source As Long, _
ByVal Length As Long)

Private Declare Sub ZeroMemory Lib "kernel32.dll" Alias "RtlZeroMemory" ( _
    Destination As Any, _
    ByVal Length As Long)

Public Function PackedVariantEqual(vntCmp1 As Variant, _
                                   vntCmp2 As Variant) As Boolean
   ' Returns True if both variants contain exactly the same data

   Dim i As Long
   Dim ptr As Long
   Dim buf1() As Long
   Dim buf2() As Long

   PackedVariantEqual = False

   If (VarType(vntCmp1) <> VarType(vntCmp2)) Then
      Exit Function
   End If

   If (IsObject(vntCmp1) Or IsObject(vntCmp2)) Then
      ' Todo: Compare contents of objects
      Call Err.Raise(9753, "modClientMisc::PackedVariantEqual", "Internal
error: Object comparison not possible!")
   End If

   If (Not (IsArray(vntCmp1))) Or (Not (IsArray(vntCmp2))) Then
      ' Simple types
      If (LenB(vntCmp1) <> LenB(vntCmp2)) Then
         Exit Function
      End If

      If (LenB(vntCmp1) > 0) Then
         ' Compare content
         ReDim buf1(1 To 4)
         ReDim buf2(1 To 4)

         If (VarType(vntCmp1) = vbString) Then
            ' vntCmp2 must have the same type anyway
            If (StrComp(vntCmp1, vntCmp2) <> 0) Then
               Exit Function
            End If
         Else
            Call CopyMemoryRead(buf1(1), VarPtr(vntCmp1), 16)
            Call CopyMemoryRead(buf2(1), VarPtr(vntCmp2), 16)

            If (VarType(vntCmp1) = vbUserDefinedType) Then
               ptr = buf1(3)
               ReDim buf1(1 To (LenB(vntCmp1) / 4) + 1)
               Call ZeroMemory(buf1(1), (UBound(buf1) - LBound(buf1) + 1) *
4)
               Call CopyMemoryRead(buf1(1), ptr, LenB(vntCmp1))

               ptr = buf2(3)
               ReDim buf2(1 To (LenB(vntCmp2) / 4) + 1)
               Call ZeroMemory(buf2(1), (UBound(buf2) - LBound(buf2) + 1) *
4)
               Call CopyMemoryRead(buf2(1), ptr, LenB(vntCmp2))

               ' Problem: If the UDT contains strings or variants, I'll only
compare the pointers,
               '  not the data!
            End If

            For i = LBound(buf1) To UBound(buf1)
               If (buf1(i) <> buf2(i)) Then
                  Exit Function
               End If
            Next i
         End If
      End If
   Else
      ' Arrays
      If ((LBound(vntCmp1) <> LBound(vntCmp2)) Or _
          (UBound(vntCmp1) <> UBound(vntCmp2))) Then
         Exit Function
      End If

      For i = LBound(vntCmp1) To UBound(vntCmp2)
         ' Recursive call for each element of the array
         If (Not (PackedVariantEqual(vntCmp1(i), vntCmp2(i)))) Then
            Exit Function
         End If
      Next i
   End If

   PackedVariantEqual = True
End Function


Thanks for any ideas!

Robert

Author
20 Oct 2005 12:08 PM
Phill. W
"Robert" <no***@nowhere.com> wrote in message
news:O6DtzSW1FHA.1252@TK2MSFTNGP09.phx.gbl...

> Now I'd like to add a comparison between two variables of
> user-defined types (each stored in a variant).

Now that would be a good trick, because if you really /do/ mean
User Defined Type, as in  ...

Private Type SimplePoint
    X as Long
    Y as Long
End Type

.... you /cannot/ assign these to a Variant, since it fails with the error

"Only user-defined types defined in public object modules can be
coerced to or from a variant or passed to late bound functions."

or something like it.

> I don't know anything about their structure,

And that's the fundamental problem with UDT's; they're not
"self-describing" (as opposed to Classes, which are), which is
probably why Variants don't want to play with them.

If you want to create, use and compare Classes, that's a whole
new ball game, but I don't think you stand an awful lot of
chance getting this to work with Types.

Regards,
    Phill  W.
Author
20 Oct 2005 1:27 PM
Robert
Since the UDT IS defined in a public class (public not creatable), I can
assign them to a Variant just fine.

Well, the function itself doesn't know anything about the UDT, but the
caller does. I would be happy if I could find a way the caller could tell
the function how to handle the UDTs contained within the variant. Handing
over a pointer to a compare function would be cool, but calling a function
pointer is quite complicated (or does someone know a simple way to do
this?). Any other simple way I could hand over a description of the UDT
would be a fine solution, too.

Robert

Show quoteHide quote
"Phill. W" <P.A.Ward@o-p-e-n-.-a-c-.-u-k> wrote in message
news:dj80q8$59p$1@yarrow.open.ac.uk...
> "Robert" <no***@nowhere.com> wrote in message
> news:O6DtzSW1FHA.1252@TK2MSFTNGP09.phx.gbl...
>
> > Now I'd like to add a comparison between two variables of
> > user-defined types (each stored in a variant).
>
> Now that would be a good trick, because if you really /do/ mean
> User Defined Type, as in  ...
>
> Private Type SimplePoint
>     X as Long
>     Y as Long
> End Type
>
> ... you /cannot/ assign these to a Variant, since it fails with the error
>
> "Only user-defined types defined in public object modules can be
> coerced to or from a variant or passed to late bound functions."
>
> or something like it.
>
> > I don't know anything about their structure,
>
> And that's the fundamental problem with UDT's; they're not
> "self-describing" (as opposed to Classes, which are), which is
> probably why Variants don't want to play with them.
>
> If you want to create, use and compare Classes, that's a whole
> new ball game, but I don't think you stand an awful lot of
> chance getting this to work with Types.
>
> Regards,
>     Phill  W.
>
>
Author
20 Oct 2005 5:56 PM
Karl E. Peterson
Robert wrote:
> Now, as soon as the UDT contains strings or variants, I'll once again
> have pointers within the data I wish to compare - and I don't know
> where they are, so I cannot compare strings stored within the UDT.

Take a look over here, for what looks to be a pretty cool method:

---- Original Message ----
From: "Schmidt" <s**@online.de>
Newsgroups: microsoft.public.vb.com
Sent: Wednesday, October 19, 2005 6:15 PM
Subject: Re: Convert user-defined data type to byte array?

I haven't tried it yet, but I definitely intend to give it a workout myself!
--
Working Without a .NET?
http://classicvb.org/petition
Author
21 Oct 2005 7:25 AM
Robert
That's an interesting approach. However, I've found a simpler solution that
works for me: I create a class with the compare function, and whenever I
stumble across a UDT, I raise an event asking my parent to compare it for
me. Works just fine in my case.

Thanks all

Robert

Show quoteHide quote
"Karl E. Peterson" <k***@mvps.org> wrote in message
news:emBoI%23Z1FHA.2788@TK2MSFTNGP10.phx.gbl...
> Robert wrote:
> > Now, as soon as the UDT contains strings or variants, I'll once again
> > have pointers within the data I wish to compare - and I don't know
> > where they are, so I cannot compare strings stored within the UDT.
>
> Take a look over here, for what looks to be a pretty cool method:
>
> ---- Original Message ----
> From: "Schmidt" <s**@online.de>
> Newsgroups: microsoft.public.vb.com
> Sent: Wednesday, October 19, 2005 6:15 PM
> Subject: Re: Convert user-defined data type to byte array?
>
> I haven't tried it yet, but I definitely intend to give it a workout
myself!
> --
> Working Without a .NET?
> http://classicvb.org/petition
>
>