Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Fun with HEX.and &H

Status
Not open for further replies.

GFrantsen

Programmer
Sep 16, 2002
37
0
0
US
I am having a problem with the HEX() and &H functions.
I need to turn &HFFFF into 65532, not -1. Can anyone tell me how to do this?

If you do a HEX(65532) you get FFFF.
If you do a HEX(-1) you get FFFF.

I'm assuming because the default &H has something to do with being signed. How do I UNsign it?

Constants will NOT help. I need an unsigned coversion for ANY hex number.

Thanks in advance.
Greg.
 
&HFFFF is 65535 not 65532. With that aside, I am not sure if I fully understand what you are tring to do but give this code a look and see if it does what you need.

Private Sub Command1_Click()
Dim iBit As Long
Dim iResult As Long
Dim iHexNum As Long

iHexNum = &HFFFF 'Assign the Hex Number

For iBit = 0 To 15
If BitOnA(iHexNum, iBit) Then iResult = iResult + (2 ^ iBit)
Next
Print iResult
End Sub

Private Function BitOnA(Numb As Long, Bit As Long) As Boolean
BitOnA = (Numb And (2 ^ Bit))
End Function

Let me know if that is what you need. If you choose to battle wits with the witless be prepared to lose.
[machinegun][hammer]

[cheers]
 
Thanks. I'll check that out.
I can't believe there's not an easier way to do this.

All I want to do is get a Hex value between 0 and FFFF and turn it into a normal (NON-HEX) number.

Thanks.
Greg.
 
The problem is the way that VB does internal conversions (essentially treating an implict assignments as variants).

So what happens is that when you say:

Fred=&HFFFF

vb looks at the right hand side of the assignment, and 'decides' that this is a signed integer (mainly because, when making these decisions Vb choses the data type based on a least-storage concept), so

Print Fred

gives you -1, becuase it has interpreted FFFF as a two-byte signed integer, rather than as a 4-byte long - which is what you might have been expecting.

The way to deal with this is by doing an explicit cast using the 'archaic' postscript conventions for variables:

Fred = &HFFFF&

where the trailing & tells VB that we are looking at a Long on the right hand side rather than a variant. Once you've done this:

Print Fred

will give you the right result.

One way of seeing what is happening is to do the following: create a new project and add a form. Add a single command button to the form. Drop in the following code:
[tt]
Option Explicit

Private Sub Command1_Click()
Dim fred As Long
Dim john As Variant

john = &HFFFF
fred = &HFFFF&
Debug.Print fred
End Sub
[/tt]
Put a breakpoint on the debug line, then run the program and click the command button. The program will stop on the breakline. Now select View/Locals in the IDE. You will see that 'john' is of type variant/integer
 
Perhaps it would help to write your own routine, as the code of foada works only in the range of &h0 to &hFFFF relayable, but not below (minus) and not above... at least as my tests revealed...
Here a code snippet as a startingpoint:
Code:
Public Function Base2Dec(strHex As String, intBase) As Double
    Dim intMax As Integer
    Dim intCnt As Integer
    Dim dblRes As Double
    Dim strPos As String * 1
    Dim intPos As Integer
    
    intMax = Len(strHex)
    For intCnt = intMax To 1 Step -1
        strPos = UCase$(Mid$(strHex, intCnt, 1))
        If strPos <> &quot;-&quot; Then
            If Not IsNumeric(strPos) Then
                intPos = 10 + (Asc(strPos) - 65)  ' 65 = ASCII of A
            Else
                intPos = CInt(strPos)
            End If
            If intPos <= intBase Then
                dblRes = dblRes + intPos * intBase ^ (intMax - intCnt)
            Else
                Err.Raise vbObjectError + 10001, &quot;Base2Dec&quot;, &quot;Value not in Range&quot;
            End If
        Else
            If intCnt <> 1 Then
                Err.Raise vbObjectError + 10002, &quot;Base2Dec&quot;, &quot;Missplaced minus (-) sign&quot;
            Else
                dblRes = -dblRes
            End If
        End If
    Next intCnt
    Base2Dec = dblRes
    
End Function
To Convert from Hexadecimal to Decimal you would call:
Code:
?Base2Dec(&quot;FFFF&quot;,16)
To Convert from Octal to Decimal you would call:
Code:
?Base2Dec(&quot;1428&quot;,8)
Take this as an example... I wrote it just in without testing...

hope this helps
Andreas
 
I suppose I should have concluded with the fact that all you need to do is stop VB making the implicit cast. So, using the example I gave before, with one minor modification (emboldened below), you should get the result that you want:

Option Explicit

Private Sub Command1_Click()
Dim fred As Long
Dim john As Variant

john = CLng(&HFFFF) ' Stops implicit recasting to signed integer
fred = &HFFFF&
Debug.Print john
End Sub
 
Thanks everyone.
I don't need to go any bigger than &HFFFF since this is the max volume of one sound channel. The actual sound API function returns something like &quot;FFFFFFFF&quot; where the first 4 are one channel, and the second 4 are the other channel.

I just needed a way to get, store, and manipulate the volume of both/either channels without having to worry about doing math in hex.

Greg.
 
That was the first thing I tried. But on my machine
john = CLng(&HFFFF) returns -1.

Greg.
 
I'll bet it doesn't. I bet you just tried it in the immediate window.

If you type:

? Clng(&HFFFF)

in the immediate window, guess what happens. Firstly, the Clng works correctly - but THEN because there is no assignment going on VB looks at the result and again does an implicit cast to a signed integer to keep storage requirements down before returning the result for display.

If you do it in code, with an assignment, the cast doesn't occur.
 
OK, so now I have a string containing &quot;FFFF&quot;. How do I make that into 65535?
 
Dim lngJohn As Long
Dim varGreg As Variant
varGreg = CLng(&HFFFF)
lngJohn = &HFFFF&

Print varGreg, lngJohn

returns -
-1 65535

 
Here is some other code I had.

Option Explicit

Enum base
Bin = 2
Oct = 8
Dec = 10
Hex = 16
End Enum

Function Any2Dec(ByVal NumberBaseX As String, ByVal base As base) As Long
Dim index As Long
Dim Digits As String
Dim digitValue As Long

On Error GoTo ErrHandler

If base < 2 Or base > 36 Then Err.Raise 5
Digits = Left(&quot;0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;, base)
For index = 1 To Len(NumberBaseX)
digitValue = InStr(1, Digits, Mid$(NumberBaseX, index, 1), vbTextCompare) - 1
If digitValue < 0 Then Err.Raise 5
Any2Dec = Any2Dec * base + digitValue
Next
Exit Function

ErrHandler:
Resume Next
End Function

Private Sub Command1_Click()
Command1.Caption = CStr(Any2Dec(&quot;FFFF&quot;, Hex))
End Sub If you choose to battle wits with the witless be prepared to lose.
[machinegun][hammer]

[cheers]
 
Yes, if you make the lefthand side of the assignment a variant then VB will tend to cast the righthand side down into the smallest size it can. This is one of the reasons that using variants in your code can be a bad idea.
 
I was just following your example.
I also tried it with a long instead of a variant.
Same result.
 
Val will convert the hex string into a number. Using the trailing & will give you the correct conversion.

Val(&HFFFF) will return -1

Val(&HFFFF&) will return 65535

This will work even in the immediate window.

Robert
 
But I need to be able to turn the &quot;FFFF&quot; into a non-hex value.
I have a string with &quot;FFFF&quot; in it.
NOW, I need to make it 65535. I can't do something like

dim strString as string
dim lngJohn as long

strString = &quot;FFFF&quot;
lngJohn = &HstrString&

There has GOT to be an opposite function to HEX(). I can't believe there wouldn't be.

 
Sorry - quite right; you need the ampersand after the hex to stop the implict conversion. or you need some way to advise VB not to do the conversion. Which you can do as follows:

john = &HFFFF AND &HFFFF&

Or, assuming that one of the parameters is a variable, something like:

Dim fred As Long
Dim john As Long

john = &HFFFF
fred = john & &HFFFF& ' Forces VB to use a long rather than unsigned integer. The ampersand is vital here.
Debug.Print john
 
I'm not sure how this helps.
I need to be able to take a hex value in a variable, and turn it into a long. Not signed.

I get a value back from the API call that is supposed to be a long with the volume in it. If I do a HEX on it, I get &quot;FFFFFFFF&quot; which is the MAX volume of the left side and the MAX volume of the right side.
I want to be able to adjust the volume programatically, but to do that, I have to be able to convert that volume into something that I can use, like a long. That &quot;FFFFFFFF&quot; SHOULD convert into two longs of value 65535 each. But they convert to -1.
Now, to halve the volume, I should be able to divide the converted(long) volume by 2, convert it back to hex and use an API to set it.
But, divide -1 by 2 and see what you get.
It doesn't work.

This is getting EXTREMELY frustrating.
 
Greg,

Believe it. MS didn't put everything we'd like to have in VB ( I'm sad to say ), so you sometimes have to resort to a workaround.

If you have the value &quot;FFFF&quot; in a string, you have to add onto the sring like this:

Hexstring = &quot;&H&quot; & HexString & &quot;&&quot;

then do the conversion:

DecimalValue = Val(HexString)


Robert
 
Well, once you've understood what is happening, the following should make sense:

Option Explicit
Private Type HexHack
HiLong As Long
LoLong As Long
End Type

Private Sub Command1_Click()
Dim myHack As HexHack
HackHex &HFFFFFFFF, myHack '&FFFFFFFF represents return from API call
Debug.Print myHack.HiLong
Debug.Print myHack.LoLong
End Sub

Private Sub HackHex(ByVal lHex As Long, tHexHack As HexHack)
tHexHack.HiLong = ((lHex And &HFFFF0000) \ &H10000) And &HFFFF&
tHexHack.LoLong = lHex And &HFFFF&
End Sub
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top