PRB: Compare User-Defined Type Variables w/ PEEK or _fmemcmp

ID: Q101258


The information in this article applies to:


SYMPTOMS

An attempt to use the relational operators (=, <>, and so on) to compare user-defined type variables results in a "Type mismatch" error.


CAUSE

The relational operators do not support the comparison of user-defined type variables.


RESOLUTION

This article discusses two alternative methods for comparing user-defined type variables.

The first method compares user-defined type variables by converting the variables to strings, and then comparing the strings. It uses PEEK, VARPTR, and CHR$ to convert the user-defined type variable to a string.

The second method uses the C function _fmemcmp to compare two user-defined type variables. This second method is much faster than the first, particularly when comparing large (up to 64k in size) user-defined type variables. In addition, the second method avoids "out of string space" errors which can occur with the first method and it can be modified to compare arrays of numeric, fixed length strings or user-defined types up to 64k in size.


STATUS

This behavior is by design.


MORE INFORMATION

WARNING: One or more of the following functions are discussed in this article; VarPtr, VarPtrArray, VarPtrStringArray, StrPtr, ObjPtr. These functions are not supported by Microsoft Technical Support. They are not documented in the Visual Basic documentation and are provided in this Knowledge Base article "as is." Microsoft does not guarantee that they will be available in future releases of Visual Basic.

When comparing user-defined type variables, you can check to see if they are Equal or Not Equal ('=' or '<>'), but don't attempt to use the other relational operators (<, >, <=, >=) unless the user-defined type variable contains fixed length strings. This behavior is due to how numeric variables are stored and how these functions accomplish their comparisons. These methods treat the numeric variables as unsigned numbers and because the negative sign is stored in the most significant bit of a numeric variable, comparing positive and negative numbers would result in the negative number being seen as greater than the positive number.

Method One

The following example program demonstrates how to compare user-defined type variables by converting the variables to strings:

DECLARE FUNCTION type2str$ (t AS ANY)

TYPE myType

   f1 AS STRING * 2
   f2 AS SINGLE

END TYPE
<BR/><BR/>
DIM x AS myType
DIM y AS myType
<BR/><BR/>
x.f1 = "ab"
x.f2 = 2
y = x
<BR/><BR/>
IF type2str(x) = type2str(y) THEN

   PRINT "x = y"
ELSE
   PRINT "x <> y"
END IF
y.f1 = "ba"
IF type2str(x) > type2str(y) THEN

   PRINT "x > y"
ELSE
   PRINT "x < = y"
END IF
'
' type2str converts a user-defined type variable to a string.
'
FUNCTION type2str$ (t AS myType)
   DEF SEG = VARSEG(t)   ' In case the variable is in a dynamic array.
   FOR i% = 0 TO LEN(t) - 1
      s$ = s$ + CHR$(PEEK(VARPTR(t) + i%))
   NEXT
   DEF SEG
   type2str = s$

END FUNCTION 

Method Two

The _fmemcmp function takes three parameters. The first two parameters are far pointers to the memory buffers it compares, and the third parameter is the number of bytes to check. The function returns a value to be tested against zero: To use the function, link your compiled Basic program with the medium or large model C library (MLIBCE.LIB or LLIBCE.LIB) of the appropriate version; that is, use Microsoft C version 5.1 for Microsoft Quickbasic version 4.50, use Microsoft C version 6.0 for Microsoft Basic PDS version 7.10, and use Microsoft C version 7.0 for Microsoft Visual Basic for MS-DOS version 1.0.

If you want to run this program inside the Visual Basic for MS-DOS environment, use the following code to build a library and quicklibrary:

LIB MLIBCE.LIB*FMEMCMP.OBJ;  ' extract fmemcmp object
   LIB MLIBCE.LIB*DIFFHLP.OBJ;  ' and a support object
   LIB TYPECOMP.LIB+FMEMCMP.OBJ+DIFFHLP.OBJ;  ' build new library
   LINK /Q TYPECOMP.LIB,TYPECOMP.QLB,,VBDOSQLB.LIB; ' build quicklib
                                                    ' use QBXQLB.LIB
                                                    ' for Basic PDS or
                                                    ' BQLB45.LIB for QB45 

Then invoke Visual Basic for MS-DOS with the /L switch to load the new quicklibrary:

VBDOS /L TYPECOMP 

Below is a Basic program that calls the C _fmemcmp function. Note that the underscore character (_) is used as a line continuation character and should not be used inside the Visual Basic for MS-DOS environment:

DEFINT A-Z
' Declare the C function

DECLARE FUNCTION TypeCmp% CDECL ALIAS "__fmemcmp" _
   (SEG buf1 AS ANY, SEG buf2 AS ANY, BYVAL Length%)

CONST max = 1000
TYPE RecType                     ' Set Up the User Defined Type

   CustID AS INTEGER
   AcctCode AS LONG
   Memo AS STRING * 6
   Dates(1 TO max)  AS STRING * 10

END TYPE

CLS
DIM Rec1 AS RecType    ' Dimension 2 variables
DIM Rec2 AS RecType

Rec1.CustID = 2        ' Initialize first record
Rec1.AcctCode = 42356
Rec1.Memo = "mojoho"
FOR i = 1 TO max

   Rec1.Dates(i) = "Test" + STR$(i)

NEXT i

Rec2 = Rec1            ' Initialize second record

result% = TypeCmp%(Rec1, Rec2, LEN(Rec1))   ' Compare the records:
IF result% <> 0 THEN             ' if result% = 0, Rec1 = Rec2
   PRINT "Not Equal"                   ' if result% > 0, Rec1 > Rec2
ELSE                                   ' if result% > 0, Rec1 < Rec2

   PRINT "Rec1 = Rec2"

END IF

Rec2.Memo = "toasty"   ' Change information in 2nd record

result% = TypeCmp%(Rec1, Rec2, LEN(Rec1))  ' Compare
IF result% <> 0 THEN                 ' Print result

   PRINT "Not Equal"

ELSE

   PRINT "Rec1 = Rec2"

END IF
END 

This program prints the following output:

Rec1 = Rec2 Not Equal

Additional query words:


Keywords          : kbVBp 
Version           : MS-DOS:1.0,4.0,7.1
Platform          : MS-DOS 
Issue type        : kbprb 

Last Reviewed: July 20, 1999