Jump to content
Sign in to follow this  
quaizywabbit

listbox client area error

Recommended Posts

Ive tried the LBItemfromPt( ) in comctl32.dll as well as _SendMessage($Hlb, $LB_ITEMFROMPOINT, 0, $Point) where $Hlb is the hwnd to the listbox.

The $Point structure coordinates used are originally screen coordinates, and ive converted them to client coordinates, as well as window coordinates, but in any case both functions return minus 1 ( not in the client area ) instead of the index.

why this is so, Ive no clue whatsoever...........

EDIT: got it to return index using SendMessage()

Edited by quaizywabbit

[u]Do more with pre-existing apps![/u]ANYGUIv2.8

Share this post


Link to post
Share on other sites

This forum is for AutoIt bugs. You are using the function wrong; this is not a problem with AutoIt.

The function expects screen coordinates.

I added the ScreenToClient functon after it failed with the original screen coordinates. In fact, I've tried every possible combination.

I'm more than happy to be proved wrong on this. If I did it wrong, please post an example of how you got either function to return an Index instead of -1 everytime.


[u]Do more with pre-existing apps![/u]ANYGUIv2.8

Share this post


Link to post
Share on other sites

You are passing a ptr to POINT not POINT itself.

NOBUG.

PS Your subject is more and help&support one :P

Share this post


Link to post
Share on other sites

You are passing a ptr to POINT not POINT itself.

NOBUG.

PS Your subject is more and help&support one :P

How do i pass $Point as you describe?

I have solved getting SendMessage() to return the index....

But I am still interested how to call LBItemFromPt() in Comctl32.dll properly passing the $Point via DllCall()

Edited by quaizywabbit

[u]Do more with pre-existing apps![/u]ANYGUIv2.8

Share this post


Link to post
Share on other sites

How do i pass $Point as you describe?

I have solved getting SendMessage() to return the index....

But I am still interested how to call LBItemFromPt() in Comctl32.dll properly passing the $Point via DllCall()

From the A3LListBox file in Auto3Lib:

; =================================================================================================
; Description ..: Retrieves the zero based index of the item nearest the specified point in a list box
; Parameters ...: $hWnd         - Handle to control
;                 $iX           - X coordinate, relative to the upper-left corner of the client area
;                 $iY           - Y coordinate, relative to the upper-left corner of the client area
; Return values : The index of the nearest item or -1 if the point is outside of the client area
; =================================================================================================
Func _Listbox_ItemFromPoint($hWnd, $iX, $iY)
  Local $iResult

  $iResult = _SendMessage($hWnd, $LB_ITEMFROMPOINT, 0, _MakeLong($iX, $iY))
  if _HiWord($iResult) = 0 then
    Return $iResult
  else
    Return -1
  endif
EndFuncoÝ÷ ØZèØ^r˺گ'âè§ëhܸjëh×6; =================================================================================================
; Description ..: Returns an longint value from two int values
; Parameters ...: $iLo          - Low word
;                 $iHi          - Hi word
; Return values : Longint value
; =================================================================================================
Func _MakeLong($iLo, $iHi)
  Return BitOR(BitShift($iHi, -16), BitAND($iLo, 0xFFFF))
EndFunc

; =================================================================================================
; Description ..: Returns the high word of a longword
; Parameters ...: $iLong        - Longword value
; Return values : High order word of the longword value
; =================================================================================================
Func _HiWord($iLong)
  Return BitShift($iLong, 16)
EndFunc

Auto3Lib: A library of over 1200 functions for AutoIt

Share this post


Link to post
Share on other sites

Thanks PaulIA, I had already found the MakeLong() function.......

Would you happen to know how to call LBItemFromPt() in ComCtl32.dll using DllCall ??

apparently it doesn't use a ptr to the Point Struct, but the struct itself (somehow)

Solved SendMessage() returning Index (Updated Script---> see 1st post )

Edited by quaizywabbit

[u]Do more with pre-existing apps![/u]ANYGUIv2.8

Share this post


Link to post
Share on other sites

Thanks PaulIA, I had already found the MakeLong() function.......

Would you happen to know how to call LBItemFromPt() in ComCtl32.dll using DllCall ??

apparently it doesn't use a ptr to the Point Struct, but the struct itself (somehow)

Solved SendMessage() returning Index (Updated Script---> see 1st post )

Here is your script using the DllCall:

CODE
#include "guiconstants.au3"
#include "guilist.au3"
#include <Misc.au3>
;Opt("MouseCoordMode", 2)
#region Constants
;'Windows API Constants
Global Const $DRAGLISTMSGSTRING = "commctrl_DragListMsg" & Chr(0)
Global Const $DL_BEGINDRAG = ($WM_USER + 133)
Global Const $DL_DRAGGING = ($WM_USER + 134)
Global Const $DL_DROPPED = ($WM_USER + 135)
Global Const $DL_CANCELDRAG = ($WM_USER + 136)

Global Const $LB_ITEMFROMPOINT = 0x1A9

#endregion
#region Vars
Dim $Parent; hwnd of parent window where draglist is located
Dim $Hlb; handle to list control modified by MakeDraglist() function
Dim $nItem; item where to place insert image next to
#endregion
#region Structs
#comments-start
    typedef struct {
    UINT uNotification;
    HWND hWnd;
    POINT ptCursor;
    } DRAGLISTINFO, *LPDRAGLISTINFO;
#comments-end
;Dim $Point = DllStructCreate("int;int")
;dim $DraglistInfo = DllStructCreate("uint;uint",$Point)
#endregion
#region Func's
Func DrawInsert( $Parent, $Hlb, $nItem)
    $r = DllCall("comctl32.dll", "int", "DrawInsert", "hwnd", $Parent, "hwnd", $Hlb, "int", $nItem)
    Return $r[0]
EndFunc
Func Makedraglist($hwnd)
    If Not IsHwnd($hwnd) Then $hwnd = Hwnd($hwnd)
    Local $r = DllCall("comctl32.dll", "int", "MakeDragList","hwnd",$hwnd);$r is 0 if unsucccesful
    Return $r[0]
EndFunc
#cs
    int LBItemFromPt(          HWND hLB,
    POINT pt,
    BOOL bAutoScroll
    );
#ce
Func LBItemFromPt( $Hlb, $Point, $autoscroll = 0)
    ;Return _SendMessage($Hlb, $LB_ITEMFROMPOINT, 0, $Point)
    ;Return Value
;The return value contains the index of the nearest item in the low-order word.
;The high-order word is zero if the specified point is in the client area of the list box,
;or one if it is outside the client area.>>>Note. this call to sendmessage always results in the same number<<<
$x=DllStructGetData($Point, 1)
$y=DllStructGetData($Point, 2)
;   $r = DllCall("comctl32.dll", "int", "LBItemFromPt", "hwnd", $Hlb, "ptr", $Point,  "int", $autoscroll)
    $r = DllCall("comctl32.dll", "int", "LBItemFromPt", "hwnd", $Hlb, "int", $x, "int", $y,  "int", $autoscroll)
    ConsoleWrite("ItemFromPt: x: " & $x & " y: " & $y & " Error: " & @Error & " Result: " & $r[0] & @CR)
    Return $r[0]

EndFunc

Func _ResetScreen($TargethWnd)
    Const $SWP_NOMOVE = 0x0002, $SWP_NOSIZE = 0x0001, $SWP_NOZORDER = 0x0004, $SWP_FRAMECHANGED = 0x0020 ;from Winuser.h
    DllCall("user32.dll", "long", "SetWindowPos", "hwnd", $TargethWnd, "hwnd", $TargethWnd, "int", 0, "int", 0, "int", 0, "int", 0, _
            "long", BitOR($SWP_NOMOVE, $SWP_NOSIZE, $SWP_NOZORDER, $SWP_FRAMECHANGED))
EndFunc

#endregion
#region Main
$Parent = GUICreate("draglist test")
$list = GUICtrlCreateList("my draglist", 40, -1, Default, Default)
$label = GUICtrlCreateLabel("" ,30, 200,100, 40 )
GUISetState (@SW_SHOW)
$Hlb = ControlGetHandle($Parent,"",$list)
GUICtrlSetData($list, "you|me|them|us")
GUISetState (@SW_SHOW)       ; will display an empty dialog box
Makedraglist($Hlb)
$draglistmessage = DllCall("user32.dll", "int", "RegisterWindowMessage", "str", $DRAGLISTMSGSTRING)
;MsgBox(0, "",($draglistmessage[0]))
$x = GUIRegisterMsg(($draglistmessage[0]), "MyDraglistHandler")
;MsgBox(0, "guiregmssge", $x)
; Run the GUI until the dialog is closed
While 1
    Dim $msg = GUIGetMsg()


    If $msg = $GUI_EVENT_CLOSE Then ExitLoop

Wend
#cs from msdn:
    The wParam parameter of the drag list message is the control identifier for the drag list box.
    The lParam parameter is the address of a DRAGLISTINFO structure,
    which contains the notification code for the drag event and other information.
    The return value of the message depends on the notification
#ce
Func MyDraglistHandler($hwnd, $msg, $wParam, $lParam)
    ;Opt("MouseCoordMode", 2)
    $nID = BitAND($wParam, 0x0000FFFF)
    If $nID = $list Then
        Local $DraglistInfo = DllStructCreate("uint;hwnd;int;int",$lParam)
        $nNotifyCode = (DllStructGetData($DraglistInfo,1))
        $Hlb = DllStructGetData($DraglistInfo, 2)
        ;if not IsHWnd($Hlb) then ConsoleWrite("control hwnd invalid")
        dim $chwnd = ControlGetHandle($Parent, "", $list)
;       $Point = _MakeWord(DllStructGetData($DraglistInfo, 3), DllStructGetData($DraglistInfo, 4))
        $Point = DllStructCreate("int;int")
        DllStructSetData($Point,1, DllStructGetData($DraglistInfo, 3))
        DllStructSetData($Point,2, DllStructGetData($DraglistInfo, 4))
;       DllCall("User32.dll", "int", "ScreenToClient", "hwnd", $chwnd, "ptr", DllStructGetPtr($Point))
;       ConsoleWrite("$Point1: " & DllStructGetData($Point,1) & @LF)
;       ConsoleWrite("$Point2: " & DllStructGetData($Point,2) & @LF)
;       ConsoleWrite($chwnd & "  " & "0x"&Hex($Hlb) & @LF)
        Select
            Case $nNotifyCode = $DL_BEGINDRAG

                $dragIdx = LBItemFromPt($chwnd, $Point)
                ;reset screen here
                ;return something
;               ConsoleWrite("$DRAGIDX =" & $dragIdx & @LF)
;               ConsoleWrite("begin drag" & @LF)
                Return True
            Case $nNotifyCode = $DL_CANCELDRAG
                ;reset screen here
                ;return something
                ConsoleWrite("drag canceled")
            Case $nNotifyCode = $DL_DRAGGING
                $dragIdto = LBItemFromPt($chwnd, $Point)
                DrawInsert($Parent, $chwnd, $dragIdto)
                ConsoleWrite("dragging" & @LF & "Dragidto = " & $dragIdto & @LF)
                ;return something
            Case $nNotifyCode = $DL_DROPPED
                ;reset screen here
                ;If LBItemFromPt($Hlb, $Pointx) <> $dragIdx Then
                ConsoleWrite("ok  Dl_Dropped" & @LF)
                ;do something with it
                ;EndIf
            Case Else
                Return $GUI_RUNDEFMSG
        EndSelect
        $Point = 0

    EndIf
EndFunc   ;==>MyDraglistHandler

Func _MakeWord($LoByte, $HiByte)
    Return BitOR($LoByte, 0x100 * $HiByte)
EndFunc   ;==>_MakeWord

Auto3Lib: A library of over 1200 functions for AutoIt

Share this post


Link to post
Share on other sites

Here is your script using the DllCall:

CODE
#include "guiconstants.au3"
#include "guilist.au3"
#include <Misc.au3>
;Opt("MouseCoordMode", 2)
#region Constants
;'Windows API Constants
Global Const $DRAGLISTMSGSTRING = "commctrl_DragListMsg" & Chr(0)
Global Const $DL_BEGINDRAG = ($WM_USER + 133)
Global Const $DL_DRAGGING = ($WM_USER + 134)
Global Const $DL_DROPPED = ($WM_USER + 135)
Global Const $DL_CANCELDRAG = ($WM_USER + 136)

Global Const $LB_ITEMFROMPOINT = 0x1A9

#endregion
#region Vars
Dim $Parent; hwnd of parent window where draglist is located
Dim $Hlb; handle to list control modified by MakeDraglist() function
Dim $nItem; item where to place insert image next to
#endregion
#region Structs
#comments-start
    typedef struct {
    UINT uNotification;
    HWND hWnd;
    POINT ptCursor;
    } DRAGLISTINFO, *LPDRAGLISTINFO;
#comments-end
;Dim $Point = DllStructCreate("int;int")
;dim $DraglistInfo = DllStructCreate("uint;uint",$Point)
#endregion
#region Func's
Func DrawInsert( $Parent, $Hlb, $nItem)
    $r = DllCall("comctl32.dll", "int", "DrawInsert", "hwnd", $Parent, "hwnd", $Hlb, "int", $nItem)
    Return $r[0]
EndFunc
Func Makedraglist($hwnd)
    If Not IsHwnd($hwnd) Then $hwnd = Hwnd($hwnd)
    Local $r = DllCall("comctl32.dll", "int", "MakeDragList","hwnd",$hwnd);$r is 0 if unsucccesful
    Return $r[0]
EndFunc
#cs
    int LBItemFromPt(          HWND hLB,
    POINT pt,
    BOOL bAutoScroll
    );
#ce
Func LBItemFromPt( $Hlb, $Point, $autoscroll = 0)
    ;Return _SendMessage($Hlb, $LB_ITEMFROMPOINT, 0, $Point)
    ;Return Value
;The return value contains the index of the nearest item in the low-order word.
;The high-order word is zero if the specified point is in the client area of the list box,
;or one if it is outside the client area.>>>Note. this call to sendmessage always results in the same number<<<
$x=DllStructGetData($Point, 1)
$y=DllStructGetData($Point, 2)
;   $r = DllCall("comctl32.dll", "int", "LBItemFromPt", "hwnd", $Hlb, "ptr", $Point,  "int", $autoscroll)
    $r = DllCall("comctl32.dll", "int", "LBItemFromPt", "hwnd", $Hlb, "int", $x, "int", $y,  "int", $autoscroll)
    ConsoleWrite("ItemFromPt: x: " & $x & " y: " & $y & " Error: " & @Error & " Result: " & $r[0] & @CR)
    Return $r[0]

EndFunc

Func _ResetScreen($TargethWnd)
    Const $SWP_NOMOVE = 0x0002, $SWP_NOSIZE = 0x0001, $SWP_NOZORDER = 0x0004, $SWP_FRAMECHANGED = 0x0020 ;from Winuser.h
    DllCall("user32.dll", "long", "SetWindowPos", "hwnd", $TargethWnd, "hwnd", $TargethWnd, "int", 0, "int", 0, "int", 0, "int", 0, _
            "long", BitOR($SWP_NOMOVE, $SWP_NOSIZE, $SWP_NOZORDER, $SWP_FRAMECHANGED))
EndFunc

#endregion
#region Main
$Parent = GUICreate("draglist test")
$list = GUICtrlCreateList("my draglist", 40, -1, Default, Default)
$label = GUICtrlCreateLabel("" ,30, 200,100, 40 )
GUISetState (@SW_SHOW)
$Hlb = ControlGetHandle($Parent,"",$list)
GUICtrlSetData($list, "you|me|them|us")
GUISetState (@SW_SHOW)       ; will display an empty dialog box
Makedraglist($Hlb)
$draglistmessage = DllCall("user32.dll", "int", "RegisterWindowMessage", "str", $DRAGLISTMSGSTRING)
;MsgBox(0, "",($draglistmessage[0]))
$x = GUIRegisterMsg(($draglistmessage[0]), "MyDraglistHandler")
;MsgBox(0, "guiregmssge", $x)
; Run the GUI until the dialog is closed
While 1
    Dim $msg = GUIGetMsg()


    If $msg = $GUI_EVENT_CLOSE Then ExitLoop

Wend
#cs from msdn:
    The wParam parameter of the drag list message is the control identifier for the drag list box.
    The lParam parameter is the address of a DRAGLISTINFO structure,
    which contains the notification code for the drag event and other information.
    The return value of the message depends on the notification
#ce
Func MyDraglistHandler($hwnd, $msg, $wParam, $lParam)
    ;Opt("MouseCoordMode", 2)
    $nID = BitAND($wParam, 0x0000FFFF)
    If $nID = $list Then
        Local $DraglistInfo = DllStructCreate("uint;hwnd;int;int",$lParam)
        $nNotifyCode = (DllStructGetData($DraglistInfo,1))
        $Hlb = DllStructGetData($DraglistInfo, 2)
        ;if not IsHWnd($Hlb) then ConsoleWrite("control hwnd invalid")
        dim $chwnd = ControlGetHandle($Parent, "", $list)
;      $Point = _MakeWord(DllStructGetData($DraglistInfo, 3), DllStructGetData($DraglistInfo, 4))
        $Point = DllStructCreate("int;int")
        DllStructSetData($Point,1, DllStructGetData($DraglistInfo, 3))
        DllStructSetData($Point,2, DllStructGetData($DraglistInfo, 4))
;      DllCall("User32.dll", "int", "ScreenToClient", "hwnd", $chwnd, "ptr", DllStructGetPtr($Point))
;      ConsoleWrite("$Point1: " & DllStructGetData($Point,1) & @LF)
;      ConsoleWrite("$Point2: " & DllStructGetData($Point,2) & @LF)
;      ConsoleWrite($chwnd & "  " & "0x"&Hex($Hlb) & @LF)
        Select
            Case $nNotifyCode = $DL_BEGINDRAG

                $dragIdx = LBItemFromPt($chwnd, $Point)
                ;reset screen here
                ;return something
;            ConsoleWrite("$DRAGIDX =" & $dragIdx & @LF)
;            ConsoleWrite("begin drag" & @LF)
                Return True
            Case $nNotifyCode = $DL_CANCELDRAG
                ;reset screen here
                ;return something
                ConsoleWrite("drag canceled")
            Case $nNotifyCode = $DL_DRAGGING
                $dragIdto = LBItemFromPt($chwnd, $Point)
                DrawInsert($Parent, $chwnd, $dragIdto)
                ConsoleWrite("dragging" & @LF & "Dragidto = " & $dragIdto & @LF)
                ;return something
            Case $nNotifyCode = $DL_DROPPED
                ;reset screen here
                ;If LBItemFromPt($Hlb, $Pointx) <> $dragIdx Then
                ConsoleWrite("ok  Dl_Dropped" & @LF)
                ;do something with it
                ;EndIf
            Case Else
                Return $GUI_RUNDEFMSG
        EndSelect
        $Point = 0

    EndIf
EndFunc   ;==>MyDraglistHandler

Func _MakeWord($LoByte, $HiByte)
    Return BitOR($LoByte, 0x100 * $HiByte)
EndFunc   ;==>_MakeWord
Thanks so much Paul!

Here's a working version of a DragListBox:

still have a few things to add like changing cursors from arrow to hand )and back, as well as to the NOTALLOWED when out of range.....

Edited by quaizywabbit

[u]Do more with pre-existing apps![/u]ANYGUIv2.8

Share this post


Link to post
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
Sign in to follow this  

×
×
  • Create New...