VB5 and Btrieve

From: grw@*clark.net* (George Waddell)
Newsgroups: comp.databases.btrieve
Subject: VB 5 and BTRIEVE (long)
Date: Sat, 12 Dec 1998 16:00:09 GMT
Organization: Verio Mid-Atlantic

Recently, there has been considerable traffic on this NG about BTRIEVE and VB5.0. The problem with accessing BTRIEVE this way is that VB has some "optimization" characteristics that will make you pull your hair out.

The problem is that VB5 (or VB4 32-bit) pads the user defined types to fit on addressing boundaries. These are the rules:

* Integers - must be on even (WORD) boundaries.
* Longs - must be on DWORD boundaries
* Floats - must be on DWORD boundaries

Look at the following UDT:


    sKey As String * 7
    sDesc As String * 36
    iData As Integer

End Type

This is gauranteed to give problems. VB5 will secretly add a byte after sDesc. The iData member will be incorrect and so will every member after that. If you have long or float data then the problem is only compounded. Oh, well. Thats what we get for using a language that has no international standard.

I've seen two solutions to this. I believe Jim Kyle has a solution on his web site where he loads the entire record into a string and then uses MID$ to pull the individual columns out. Thats the kind of stuff I used to do when
I was writing Quickbasic 1.0 programs. Not something I want to recall.

The second solution is from Pervasive. That idea is to use strings and use LSET on the data. This is in fact part of the solution but it doesn't work that way under VB5.

The first thing you have to do is to make all of your integers, longs, and floats in your UDT to fixed length
strings.Like this:


* integers - String * 2
* longs - String * 4
* singles - String * 4
* doubles - String * 8

Next define these UDTs. This is what we will use to do the conversion.

Public Type UdtByte2
    bBuffer(1) As Byte
End Type

Public Type UdtByte4
    bBuffer(3) As Byte
End Type

Public Type UdtByte8
    bBuffer(7) As Byte
End Type

Public Type UdtLong
    lBuffer As Long
End Type

Public Type UdtDouble
    dfBuffer As Double
End Type

Public Type UdtSingle
    fBuffer As Single
End Type

Public Type UdtInteger
    iBuffer As Integer
End Type

Then you need to define routines for saving and reading the data. Here's an example.

Public Function String4ToLong(sIn As String) As Long

    Dim i As Integer
    Dim oByte As UdtByte4
    Dim oLong As UdtLong
    'Loop for each character
    For i = 1 To 4
        oByte.bBuffer(i - 1) = Asc(Mid$(sIn, i, 1))
    Next i
    'the bytes in the long are reversed
    'The Lset function takes care of this
    LSet oLong = oByte
    'Set the return value
    String4ToLong = oLong.bBuffer

End Function

And the reverse

Public Function LongToString4(lIn As Long) As String

    Dim sOut As String * 4
    Dim oByte As UdtByte4
    Dim oLong As UdtLong
    Dim i As Integer
    'Set the long equal to the User-defined type for Long
    oLong.bBuffer = lIn
    'LSet to reverse the bytes
    LSet oByte = oLong
    'Copy the CHR value for each byte into the string to return
    For i = 1 To 4
        Mid(sOut, i, 1) = Chr(oByte.bBuffer(i - 1))
    'Set the return value
    LongToString4 = sOut

End Function

Do the same for the other types.

I've had to transcribe some code to show this. Any mistakes I have made I hope are obvious and easily fixable.But the general idea is here and it does work.

Hope I've helped.


Copyright © Madis Kaal 2000-