I worry your low value will be wrong using ABS.
I think the problem when you don't use ABS is that when you convert value.low (a 32 bit integer I beleve) to a 64 bit integer it fills in all the new bits with a 1. I forget the terms, but there are two ways of doing a right shift. One fills in the values on the left with a 0, the other with whatever the leftmost bit started as. So, looking at a small example:
Using 0s: 11010010 >> 2 = 00110100
Extending last bit: 11010010 >> 11110100
The second one (extending) tends to be the default as it preserves the mathematical operation of << and >> being equivalent to multiplying and dividing by 2.
When you case to a larger size integer it essentially does this kind of shift. Since you're starting with a negative number it's filling in the new bits with a 1. So what you really want to do is mask the new number. I don't know the VB syntax, but I'll hazard a guess:
Public Function Build64(ByVal value As Object) As UInt64
Dim ui64High As UInt64 = value.high
Dim ui64Low As UInt64 = (value.low And 0x00000000FFFFFFFF)
ui64High = ui64High << 32
Return Convert.ToUInt64(ui64High Or ui64Low)
End Function
You shouldn't need to mask the high value since you'll be shifting it left anyway.
EDIT: Adding an explanation as to why ABS wouldn't work
When you're generating the binary for the 64 bit number, the low 32 bits need to be exactly the same as the 32 bits used in the low value you're given. Doing an absolute value calculation will change those bits very significantly.
For a really simple example, say the low value is -5.
-5 in binary (just one byte to make it easier) is: 11111011
Abs(-5) = 5, which in binary is: 00000101
In 2s complement numbers, Abs(val) is equivalent to (~val) + 1, where ~ is the binary complement operator, which changes all 0s to 1s and all 1s to 0s.
Thus, using the ABS of the low value will give you almost the exact opposite of the binary data you should have in the low 32 bits of the final number.