AngryHacker
AngryHacker

Reputation: 61606

How to represent 64-bit integer in VB6?

I am having to augment a legacy app to handle 64-bit integers. However, VB6 doesn't have a data type for that. The recommendation online that I've found has been to use the Currency data type.

However, I've found that I am running into some overflow issues.

Example - Results in Overflow during CCur call:

dim c as currency

' set maximum value of int64
c = CCur("9223372036854775807")

However, if I apply a smaller number (but still much larger than int32), it does work:

dim c as currency

' Remove the last 4 digits
c = CCur("922337203685477")

So what am I missing here? How can I handle a 64-bit value?

The only thing that I need to do with the 64-bit values is to read them from a SQL Server stored procedure (it comes as sql type bigint) and then display it to the form.

Upvotes: 5

Views: 4639

Answers (4)

DavidUK
DavidUK

Reputation: 11

VB6 can be used with variant type of I8 to provide a 64-bit signed integer. (UI8 does not work with VB6). There are some limitations, for example TypeName does not work, whilst VarType does.

Example of function cInt64 to create a 64-bit integer variant which first creates a decimal variant then converts this to an I8 variant:

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

Private Enum VARENUM
   VT_I8 = &H14
End Enum ' } VARENUM;

Private Type Dec_Hdr
    DecType     As Integer
    DecScale    As Byte
    DecSign     As Byte
End Type

Function cInt64(v As Variant) As Variant
Dim DecHdr As Dec_Hdr
    cInt64 = CDec(v) ' first create a Decimal Variant
    CopyMemory DecHdr, ByVal VarPtr(cInt64), Len(DecHdr)
'Correct possible CDec conversion errors with Hex strings
    If VarType(v) = vbString Then
        If InStr(1, v, "&h", vbTextCompare) = 1 Then DecHdr.DecSign = 0
    End If
'Remove any decimal places
    If DecHdr.DecScale Then cInt64 = Fix(cInt64)
'Convert Decimal to Int64, setting sign and scale to zero
    CopyMemory ByVal VarPtr(cInt64), CLng(VT_I8), 4 
'Adjust for Decimal Sign
    If (DecHdr.DecSign <> 0) And (cInt64 > 0) Then cInt64 = -cInt64
'Finally check variant is of type I8
    If (VarType(cInt64) <> VT_I8) Then Err.Raise 6
End Function

Upvotes: 1

Milan Oparnica
Milan Oparnica

Reputation: 340

You can use Variant datatype with CDec() conversion.

dim c as variant

' set maximum value of int64
c = CDec("9223372036854775807")

Now you can even use standard vb6 math operations, or string conversion functions on c.

Dim c As Variant, d As Variant

c = CDec("9223372036854775807")

Dim i As Integer

i = 1000
d = 10

Debug.Print c + i
Debug.Print c / d
Debug.Print CStr(c)

Results

 9223372036854776807 
 922337203685477580,7 
9223372036854775807

Just be aware that Decimal type Variant is wider than 64 bits, so you don't get the 'Overflow' on the server side :)

Upvotes: 4

Guillermo Phillips
Guillermo Phillips

Reputation: 2216

The answer is, it depends on what you're going to do with the 64 bit value. If you simply want to hold a value without doing any arithmetic on it, then it may be better to create a byte array or long array. For example:

Dim SixtFourBit(7) As Byte

or

Dim SixtyFourBit(1) As Long

Using the currency type is a simpler solution since you can apply arithmetic to it. But the Currency type is a fixed format representation, always having four decimal places. That means the lower bytes of the 64 bit representation go to make up the fractional part of the Currency value (sort of).

To coerce between Currency and arrays use the devilish CopyMemory windows API function:

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Long, ByVal Source As Long, ByVal Length As Integer)

Sub SomeFunction()
    Dim AnArray(7) As Byte
    Dim ACurrency as Currency

    ACurrency = 123.4567
    CopyMemory AnArray(0), VarPtr(ACurrency), 8&

    ' Inspecting AnArray in the watch window will show you the byte representation of ACurrency
End Sub

With the caveat, that this sort of trickery is to be generally avoided. Incorrect use of CopyMemory can kill your program.

Upvotes: 1

Bob77
Bob77

Reputation: 13267

ADO Field.Value is type Variant. When you retrieve an adBigInt in VB6 the Variant will be of subtype Decimal.

Upvotes: 5

Related Questions