Jump to content

_WinAPI_HiWord and LoWord: signing mismatch?


Recommended Posts

_WinAPI_HiWord() and _WinAPI_LoWord() seem to have inconsistent treatment of their parameters. The former seems to treat integers as signed, and the latter as unsigned. See this simple example:

#include <WinAPI.au3>
Global $Test = 0xFFFFFFFF

MsgBox(0, "HiLoWord Test", "HiWord: " & _WinAPI_HiWord($Test) & @CRLF & _
                           "LoWord: " & _WinAPI_LoWord($Test) & @CRLF)

; [Output]
; HiWord: -1
; LoWord: 65535

Is that intended behavior? I believe both functions should output the same value in this example, as both the low and high words are 0xFFFF.

Edited by danielkza
Link to comment
Share on other sites

danielkza,

There is NO inconsistent behavior, nor is this an accident. $test is a double word with the sign carried in the most significant bit. When you break this into two words the low order word is positive and the hi order word is negative in your example. Google data representation for detailed explanations.

kylomas

Forum Rules         Procedure for posting code

"I like pigs.  Dogs look up to us.  Cats look down on us.  Pigs treat us as equals."

- Sir Winston Churchill

Link to comment
Share on other sites

danielkza,

There is NO inconsistent behavior, nor is this an accident. $test is a double word with the sign carried in the most significant bit. When you break this into two words the low order word is positive and the hi order word is negative in your example. Google data representation for detailed explanations.

kylomas

The sign bit would matter if I were trying to represent a single integer as a doubleword. In my case, the dword happens to be the concatenation of two separate words. The most significant bit is not a sign bit: it is simply part of one of the words. LoWord and HiWord exist for that exact case that shows up quite often in the Windows API. Since the values they return are always single words, they should treat them as so, and not carry the sign bit from whatever intermediate representation exists inside them (that's what is happening on the current code, with BitAND treating all it's parameters as unsigned).

This behavior is not consistent with the function's goals. I ran into the problem while handling the WM_CONTEXTMENU message. See some of the description:

xPos = GET_X_LPARAM(lParam); 
yPos = GET_Y_LPARAM(lParam);

If the context menu is generated from the keyboard—for example, if the user types SHIFT+F10—then the x- and y-coordinates are -1 and the application should display the context menu at the location of the current selection rather than at (xPos, yPos).

GET_X_PARAM is defined as
((int)(short)LOWORD(lp))

I tried the most obvious code, which obviously doesn't work.

Local $PosX = _WinAPI_LoWord($lParam), $PosY = _WinAPI_HiWord($lParam)
If $PosX = -1 And $PosY = -1 Then
  ; Do Stuff
EndIF

This issue should at least be documented somewhere. I spent 1:30h debugging the rest of my code because I never expected LoWord and HiWord not to work as they would in C code. A notice in the help file would be very helpful already.

Edited by danielkza
Link to comment
Share on other sites

Did you take in consideration that auotit(oops) autoit only has and uses signed integer's. (int32 or int64 flavor)

Anyway. Its always a good thing to check any assumptions ... if your not completely 100% sure about how something might work or turn out ... in a other code language.

Edited by iEvKI3gv9Wrkd41u

"Straight_and_Crooked_Thinking" : A "classic guide to ferreting out untruths, half-truths, and other distortions of facts in political and social discussions."
"The Secrets of Quantum Physics" : New and excellent 2 part documentary on Quantum Physics by Jim Al-Khalili. (Dec 2014)

"Believing what you know ain't so" ...

Knock Knock ...
 

Link to comment
Share on other sites

danielkza,

This is one of those issues that can be argued forever, depending on expectations and point of view. I do agree with you on one point, the doc for the WinAPI could be better. On the other hand...

You get my point, I hope!

kylomas

Forum Rules         Procedure for posting code

"I like pigs.  Dogs look up to us.  Cats look down on us.  Pigs treat us as equals."

- Sir Winston Churchill

Link to comment
Share on other sites

Did you take in consideration that auotit(oops) autoit only has and uses signed integer's. (int32 or int64 flavor)

Anyway. Its always a good thing to check any assumptions ... if your not completely 100% sure about how something might work or turn out ... in a other code language.

If both numbers were treated as signed it would work exactly as I expect. The problem is that BitAND treats it's arguments as unsigned, messing up everything. If this was documented I would indeed have found out about it early on, but unfortunately it is not.

danielkza,

This is one of those issues that can be argued forever, depending on expectations and point of view. I do agree with you on one point, the doc for the WinAPI could be better. On the other hand...

You get my point, I hope!

kylomas

I'd be satisfied as long as things were consistent, with both words treated as signed or unsigned.

Link to comment
Share on other sites

... The problem is that BitAND treats it's arguments as unsigned, ..

... Wow ... I'm out.

"Straight_and_Crooked_Thinking" : A "classic guide to ferreting out untruths, half-truths, and other distortions of facts in political and social discussions."
"The Secrets of Quantum Physics" : New and excellent 2 part documentary on Quantum Physics by Jim Al-Khalili. (Dec 2014)

"Believing what you know ain't so" ...

Knock Knock ...
 

Link to comment
Share on other sites

Here's my two cents worth.

Does Yes = Si = Oui = Da = Ya ?

Answer: Yes and no.

Does -1 = 0xFFFFFFFF?

Answer: Yes and no. (signed and unsigned integers)

Here's Post #1 example completed.

#include <WinAPI.au3>
Global $Test = 0xFFFFFFFF

MsgBox(0, "HiLoWord Test", "0xFFFFFFFF: " & 0xFFFFFFFF & @CRLF & _
                                                        "HiWord: " & _WinAPI_HiWord($Test) & @CRLF & _
                        "LoWord: " & _WinAPI_LoWord($Test) & @CRLF & _
                        "HiWord: " & hex(_WinAPI_HiWord($Test),4) & @CRLF & _
                        "LoWord: " & hex(_WinAPI_LoWord($Test),4) & @CRLF)

#cs 
[Output]
0xFFFFFFFF: -1
HiWord: -1
LoWord: 65535
HiWord: FFFF
LoWord: FFFF

[Copied from WinAPI.au3 include file.]
Func _WinAPI_HiWord($iLong)
    Return BitShift($iLong, 16)
EndFunc   ;==>_WinAPI_HiWord

Func _WinAPI_LoWord($iLong)
    Return BitAND($iLong, 0xFFFF)
EndFunc   ;==>_WinAPI_LoWord
#ce

This works.

#include <WinAPI.au3>

Local $lParam = 0xFFFFFFFF
Local $PosX = Hex(_WinAPI_LoWord($lParam), 4), $PosY = Hex(_WinAPI_HiWord($lParam), 4)

If "0X" & $PosX = 0xFFFF And "0X" & $PosY = 0xFFFF And $PosX = "FFFF" And $PosY = "FFFF" Then ;
    MsgBox(0, "Results", "$PosX And $PosY equal.")
EndIf
Link to comment
Share on other sites

Method 1

Global $Test = 0xFFFFFFFF

$PosX = BitAND($Test, 0xFFFF)
$PosY = BitShift($Test, 16)
If $PosX > 0x7FFF Then $PosX -= 0x10000
If $PosY > 0x7FFF Then $PosY -= 0x10000

MsgBox(0, "HiLoWord Test", "HiWord: " & $PosX & @CRLF & _
                           "LoWord: " & $PosY & @CRLF)

Method 2

Global $Test = 0xFFFFFFFF

$tStruct1 = DllStructCreate('dword XY')
$tStruct2 = DllStructCreate('short Y;short X', DllStructGetPtr($tStruct1))
DllStructSetData($tStruct1, 'XY', $Test)
$PosX = DllStructGetData($tStruct2, 'X')
$PosY = DllStructGetData($tStruct2, 'Y')

MsgBox(0, "HiLoWord Test", "HiWord: " & $PosX & @CRLF & _
                           "LoWord: " & $PosY & @CRLF)
Link to comment
Share on other sites

Thank you guys, I had found a workaround already (in this particular case I just need to check for -1 in both words, so checking for 0xFFFFFFFF is enough). Maybe'll file a bug report one of these days asking if the devs want to change it or at least document things better.

Edited by danielkza
Link to comment
Share on other sites

  • 10 years later...

The feature request would be to add functions:

_WinAPI_GetXParam and _WinAPI_GetYParam

Here is my attempt

Func _WinAPI_GetXParam($lParam)
    $t = DllStructCreate("dword XY")
    $t.XY = $lParam
    $t2 = DllStructCreate("short X; short Y", DllStructGetPtr($t))
    Return $t2.X
EndFunc

Func _WinAPI_GetYParam($lParam)
    $t = DllStructCreate("dword XY")
    $t.XY = $lParam
    $t2 = DllStructCreate("short X; short Y", DllStructGetPtr($t))
    Return $t2.Y
EndFunc

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...