Announcement

Collapse
No announcement yet.

Use LOWRD and HIWRD carefully with API messages

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Steve Hutchesson
    replied
    As Chris was kind enough to find this problem, here are two very small
    functions for those who don't like mixing assembler with their normal
    code.

    Code:
      ' -------------------------------------------
      ' This is the code to load the LONG integer.
      ' -------------------------------------------
          LOCAL yy as LONG
      
          ! mov ax, -100  ; high integer
          ! rol eax, 16
          ! mov ax, -50   ; low integer
          ! mov yy, eax
      
      ' -------------------------------------------
      ' The message Box to test the return values.
      ' -------------------------------------------
          MessageBox hWin,ByCopy str$(LoInt(yy))+str$(HiInt(yy)), _
                     "Hi & Lo Integer from LONG", _
                     %MB_OK or %MB_ICONINFORMATION
      
      ' -------------------
      ' The two functions.
      ' -------------------
      '##########################################################################
      
      FUNCTION HiInt(ByVal lVal as LONG) as Integer
      
          #REGISTER NONE
      
          ! mov eax, lVal
          ! rol eax, 16
          ! mov FUNCTION, ax
      
      END FUNCTION
      
      '##########################################################################
      
      FUNCTION LoInt(ByVal lVal as LONG) as Integer
      
          #REGISTER NONE
      
          ! mov eax, lVal
          ! mov FUNCTION, ax
      
      END FUNCTION
      
      '##########################################################################
    I just saw Peter's small code version using push/pop which I think is very neat.

    Regards,

    [email protected]

    ------------------

    Leave a comment:


  • Peter Manders
    replied
    This should work fine, the fastest way I can think of:

    ! push lParam
    ! pop int1
    ! pop int2

    Of course lParam is a DWORD and int1 and int2 are INTEGERs here.


    Peter.


    ------------------

    Leave a comment:


  • Dominic Mitchell
    replied
    For example, when a window captures the mouse, it is possible to get a negative value back for a coordinate when
    processing a message like WM_LBUTTONDOWN. Using LOWRD and HIWRD to extract a negative value from lParam,
    will produce an error in your program, since you can't get a negative value back.
    The trick here is to pay careful attention to what is actually packed in the LONGs.
    You have to read the docs carefully and use type casting (pay attention to the hungarian
    not always acurate but helps) . For example,
    Code:
    WM_LBUTTONDOWN - lParam is packed as two SHORTs(INTEGERs in PB) so,
                     LOCAL x AS INTEGER
                     LOCAL y AS INTEGER
                     x = LOWRD(lParam)
                     y = HIWRD(lParam)
    WM_SETCURSOR   - lParam is packed as a SHORT(INTEGER in PB) and a WORD(WORD in PB) so,
                     LOCAL nHittest  AS INTEGER
                     LOCAL wMouseMsg AS WORD
                     nHittest  = LOWRD(lParam)
                     wMouseMsg = HIWRD(lParam)
    LOWRD and HIWRD is not the problem.

    ------------------

    Leave a comment:


  • Lance Edmonds
    replied
    Semen, it will in the next compiler update... No, we don't have a date for shipping yet.


    ------------------
    Lance
    PowerBASIC Support
    mailto:[email protected][email protected]</A>

    Leave a comment:


  • Semen Matusovski
    replied
    Lance --
    your code doesn't work, at least, on my PC (PB/CC & DLL).
    CInt also.
    CVI(MKI$(LoWrd( works, but it's not serious.

    ------------------

    Leave a comment:


  • Lance Edmonds
    replied
    Added to the list. Thanks!

    I don't know about the names though - maybe more like HIINT() and LOINT() would sound better?

    Regardless, PowerBASIC can another built-in way to convert between signed and unsigned... take a look at BITS() in the help file.

    Code:
    ' Simple PB/CC code to demonstrate how to return signed integers from a composite unsigned DWORD
    #COMPILE EXE
    FUNCTION PBMAIN
        DIM a AS DWORD
        a = &H0FFFFFFFE
        PRINT HIWRD(a), LOWRD(a)
        PRINT BITS%(HIWRD(a)),BITS%(LOWRD(a))
        WAITKEY$ 
    END FUNCTION

    ------------------
    Lance
    PowerBASIC Support
    mailto:[email protected][email protected]</A>

    Leave a comment:


  • Chris Boss
    replied
    Yes, the fix is simple.

    The reason I posted this though, is that it is important that HIWRD and LOWRD not be used indescrimately when processing lParam (and wParam) values for Window messages.

    Quite a few bugs can be introduced to our windows programs if we do !

    It would be nice, if the next version of PB offered an alternative set of functions for HIWRD and LOWRD (say HIWRDI and LOWRDI) which return a true Integer value (signed) and then give due warning in the docs about when to use one or the other.

    Just add this to the wish list !


    ------------------

    Leave a comment:


  • Semen Matusovski
    replied
    Chris --
    That it will be problems w/o REGISTER NONE = with register variables is clear from the beginning, because for temporary calculations are used 32-bits registers.
    Exactly because of such reason I never use REGISTER DEFAULT.

    There are some popular functions, linked with keyboard, menu, which really return integer, but declared in Win32Api.Inc as Long.
    Occurs funny situations, if you try to compare with predefined constants.
    So, I use similar trick for these functions: i = ..., where i as Integer. Of course, #Register none.

    ------------------

    Leave a comment:


  • Steve Hutchesson
    replied
    Chris has found an interesting problem here, as per the name of the
    functions, they only return unsigned results which is no use for
    negative numbers. Below is a small test piece where you have signed
    in, signed out.

    Code:
        LOCAL z&    ' signed LONG
      
        x% = -10    ' signed 16 bit integer
        y% = -20    ' signed 16 bit integer
      
      ' -------------------------------------------
      ' Combine the two values into a LONG integer
      ' -------------------------------------------
        ! mov ax, y%
        ! rol eax, 16
        ! mov ax, x%
        ! mov z&, eax
      
        x% = 0      ' clear 16 bit integers
        y% = 0
      
      ' ---------------------------------------------
      ' Extract the two values from the LONG integer
      ' ---------------------------------------------
        ! mov eax, z&
        ! mov x%, ax
        ! rol eax, 16
        ! mov y%, ax
      
        MessageBox hWin,ByCopy str$(x%)+" "+str$(y%),"Result", _
                   %MB_OK or %MB_ICONINFORMATION
    Regards,

    [email protected]

    ------------------

    Leave a comment:


  • Lance Edmonds
    replied
    Old problem, easy solution... to translate between values, use a union (and maybe a UDT to extract low and hi word's, etc).

    Code:
    TYPE DblInt
      Wrd1 AS INTEGER
      Wrd2 AS INTEGER
    END TYPE
     
    TYPE DblWrd
      Wrd1 AS WORD
      Wrd2 AS WORD
    END TYPE
     
    UNION
      Param1 AS LONG
      Param2 AS DWORD
      Param3 AS DblInt
      Param4 AS DBlWord
    END UNION
    Now, by setting any particular member of the union, you'll be able to read the component parts or "convert" between signed and unsigned simply by referring to the desired member of the UNION.

    Simple!


    ------------------
    Lance
    PowerBASIC Support
    mailto:[email protected][email protected]</A>

    Leave a comment:


  • Chris Boss
    replied
    Semen;

    Also if you use LOWRD and HIWRD in a comparison , select case , or any other way which does not set a variable to a value (which is very likely), you will get an error.

    Try the code below:

    Code:
    #COMPILE EXE
    FUNCTION PBMAIN () AS LONG
       DIM l AS LONG
       l = &HFFFEFF00  ' -2  -256
       MSGBOX STR$(LOWRD(l)) + STR$(HIWRD(l))
    END FUNCTION

    ------------------

    Leave a comment:


  • Chris Boss
    replied
    Semen;

    I tested your code and if i and j are Integers it works fine.

    If you change the variables i and j to Longs, it does not work correctly

    This means that if the expression used sets the value of a Long then there is a problem when the number is negative.

    I always use Longs for Integer variables (in 32 bit code) (which were having values set by using LOWRD and HIWRD), so in my code I was not getting a negative value back.



    ------------------

    Leave a comment:


  • Chris Boss
    replied
    Semen;

    This is a quote from the PB docs:

    Remarks:

    LOBYT/LOWRD always return the least significant (first byte/word) unsigned result, even when used with signed values.
    I was using LOWRD and HIWRD in an expression that would set a value in a LONG (not Integer) and I do not get a negative value back. Your expression sets the value of an Integer using LOWRD and HIWRD, so it may be different.

    ------------------


    [This message has been edited by Chris Boss (edited May 19, 2000).]

    Leave a comment:


  • Semen Matusovski
    replied
    Chris -
    try
    Code:
       Dim l As Long, i As Integer, j As Integer
       l = &HFFFEFF00  ' -2  -256 
       i = HiWrd(l): j = LoWrd(l)
       MsgBox Str$(i) + Str$(j)
    ------------------

    Leave a comment:


  • Chris Boss
    started a topic Use LOWRD and HIWRD carefully with API messages

    Use LOWRD and HIWRD carefully with API messages

    When processing some windows messages (ie. WM_LBUTTONDOWN) which pass both the X and Y coordinates of the mouse cursor in the lParam value, you have to extract the X and Y coordinates from a single Long value.

    The MS docs say to use HIWRD and LOWRD to extract each value. The problem with this is that the HIWRD and LOWRD functions in PB do not return negative values. The value will always be a positive value, even if the bit that defines a negative value (in an Integer) is set.

    While in most instances this doesn't cause a problem, there are some instances that you will need to return a negative value.

    For example, when a window captures the mouse, it is possible to get a negative value back for a coordinate when processing a message like WM_LBUTTONDOWN. Using LOWRD and HIWRD to extract a negative value from lParam, will produce an error in your program, since you can't get a negative value back.

    Here are some "replacement" functions for LOWRD and HIWRD which will return a negative value when it exists:

    Code:
    FUNCTION NLOWRD(BYVAL L AS LONG) AS LONG
       LOCAL IP AS INTEGER PTR, I AS INTEGER
       IP=VARPTR(L)
       I=@IP
       FUNCTION=I
    END FUNCTION
    '
    ' -----------------------------------------
    '
    FUNCTION NHIWRD(BYVAL L AS LONG) AS LONG
       LOCAL IP AS INTEGER PTR, I AS INTEGER
       IP=VARPTR(L)+2
       I=@IP
       FUNCTION=I
    END FUNCTION
    If you know that you may get a negative value when extracting a Integer (Low word or high word) from a Long, then use the functions above instead of LOWRD and HIWRD.



    [This message has been edited by Chris Boss (edited May 19, 2000).]
Working...
X
😀
🥰
🤢
😎
😡
👍
👎