Jump to content

Turn a Listbox control into a Draglist


quaizywabbit
 Share

Recommended Posts

iv'e been trying to make a listbox into a draglist via Comctrl32's "MakeDraglist" function but it always returns 0 (failure)

i've got this so far:

#include "guiconstants.au3"
#include "guilist.au3"
#region Constants
;'Windows API Constants
Global Const $DRAGLISTMSGSTRING = "commctrl_DragListMsg"
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)
#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 Makedraglist($hwnd)
 $r = DllCall("comctrl32", "int", "MakeDraglist","hwnd",$hwnd);$r is 0 if unsucccesful
 MsgBox(0, "makedraglist failure =0", $r)
EndFunc
Func DrawInsert( $Parent, $Hlb, $nItem)
 $r = DllCall("comctrl32", "int", "DrawInsert", "hwnd", $Parent, "hwnd", $Hlb, "int", $nItem)
EndFunc

#cs
 int LBItemFromPt(        HWND hLB,
 POINT pt,
 BOOL bAutoScroll
 );
#ce
Func LBItemFromPt( $Hlb, $Point, $autoscroll = 1)
 $r = DllCall("comctrl32", "int", "LbItemfromPt", "hwnd", $Hlb, "ptr", $Point, "int", 1)
EndFunc


#endregion
#region Main
$Parent = GUICreate("draglist test")
$list = GUICtrlCreateList("my draglist", 40, -1, Default, Default, $WS_VSCROLL)
$Hlb = ControlGetHandle("","",$list)
GUICtrlSetData($list, "you|me|them|us")
GUISetState (@SW_SHOW)    ; will display an empty dialog box
Makedraglist($Hlb)
dim $draglistmessage = DllCall("user32", "uint", "RegisterWindowsMessage", "str", $DRAGLISTMSGSTRING)
MsgBox(0, "", $draglistmessage)
GUIRegisterMsg($draglistmessage, "MyDraglistHandler")

; Run the GUI until the dialog is closed
While 1
 Dim $msg = GUIGetMsg()
 if ControlGetFocus($Hlb) Then
  DllStructSetData($Point,1, MouseGetPos(0))
  DllStructSetData($Point,2, MouseGetPos(1))
 EndIf
 
 
 If $msg = $GUI_EVENT_CLOSE Then ExitLoop
 
Wend
#cs
 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($Parent, $draglistmessage, $wParam, $lParam)
 $nNotifyCode   = $lParam
 $nID           = BitAnd($wParam, 0x0000FFFF)
 $hCtrl       = $lParam

 Select
  Case $nNotifyCode = $DL_BEGINDRAG
   _GUICtrlListAddItem($Hlb,"")
   $dragIdx = LBItemFromPt($Hlb, $Point)
  ;reset screen here
  ;return something
  Case $nNotifyCode = $DL_CANCELDRAG
  ;reset screen here
  ;return something
  Case $nNotifyCode = $DL_DRAGGING
   $dragIdto = LbItemfromPt($Hlb, $Point)
   DrawInsert($Parent, $Hlb, $dragIdto)
  ;return something
  Case $nNotifyCode = $DL_DROPPED
  ;reset screen here
   if LbItemfromPt($Hlb, $Point) <> $dragIdx Then
   ;do something with it
   EndIf
 EndSelect
EndFunc

BTW, I know the "MyDraglistHandler" func is wrong, just having a hard time wrapping my mind around it at the moment...

anyhow, I put a Msgbox on Makedraglist() to see if it fails as well as the line with the call to Comctl32's "RegisterWindowsMessage" ...............they both fail

anyone know why?

[u]Do more with pre-existing apps![/u]ANYGUIv2.8
Link to comment
Share on other sites

One thing I see wrong is you try to get the handle of the control in the active window. You haven't even shown the GUI yet so of course you're not going to get a handle to the right control. Use the HWND returned by GUICreate() in your call to ControlGetHandle().

Link to comment
Share on other sites

  • Moderators

I'm off to bed, but I'll have a gander in the morning... but this doesn't look like it would pass

Func Makedraglist($hwnd)
$r = DllCall("comctrl32", "int", "MakeDraglist","hwnd",$hwnd);$r is 0 if unsucccesful
MsgBox(0, "makedraglist failure =0", $r)
EndFunc
DllCall should return an array... your catching just the var.

If IsArray() or maybe if @error = 0 would be more suitable.

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

I'm off to bed, but I'll have a gander in the morning... but this doesn't look like it would pass

Func Makedraglist($hwnd)
$r = DllCall("comctrl32", "int", "MakeDraglist","hwnd",$hwnd);$r is 0 if unsucccesful
MsgBox(0, "makedraglist failure =0", $r)
EndFunc
DllCall should return an array... your catching just the var.

If IsArray() or maybe if @error = 0 would be more suitable.

I tried using $r[0] to catch the return value but it keeps giving me errors that the variable wasn't an array, even though it's supposed to be.

[u]Do more with pre-existing apps![/u]ANYGUIv2.8
Link to comment
Share on other sites

  • Moderators

Are you sure it's a hwnd your passing?

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
Local $sError = @error
If $sError = 0 Then 
    MsgBox(0, "makedraglist failure =0", $r[0])
Else
    MsgBox(0, 'Error', $sError)
EndIf
EndFunc

Edit:

don't know if you needed the .dll on the end or not ... but I added it anyway.

Edit2:

You also had comctrl32 ... MSDN says it's comctl32.dll

Edited by SmOke_N

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

Changes the specified single-selection list box to a drag list box.

Syntax

BOOL MakeDragList( HWND hLB);

Parameters

hLB Handle to the single-selection list box.

Return Value

Returns nonzero if successful, or zero otherwise.

Function Information

Minimum DLL Versioncomctl32.dll

[u]Do more with pre-existing apps![/u]ANYGUIv2.8
Link to comment
Share on other sites

#include "guiconstants.au3"
#include "guilist.au3"
#region Constants
;'Windows API Constants
Global Const $DRAGLISTMSGSTRING = "commctrl_DragListMsg"
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)
#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 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

#region Main
$Parent = GUICreate("draglist test")
$list = GUICtrlCreateList("my draglist", 40, -1, Default, Default, $WS_VSCROLL)
GUISetState (@SW_SHOW)
$Hlb = ControlGetHandle($Parent,"",$list)
GUICtrlSetData($list, "you|me|them|us")
GUISetState (@SW_SHOW)  
Makedraglist($Hlb)
$draglistmessage = DllCall("user32.dll", "uint", "RegisterWindowsMessage", "str", $DRAGLISTMSGSTRING)
MsgBox(0, "", $draglistmessage[0])
;GUIRegisterMsg($draglistmessage, "MyDraglistHandler")

; Run the GUI until the dialog is closed
While 1
Dim $msg = GUIGetMsg()
if ControlGetFocus($list) Then
  DllStructSetData($Point,1, MouseGetPos(0))
  DllStructSetData($Point,2, MouseGetPos(1))
EndIf


If $msg = $GUI_EVENT_CLOSE Then ExitLoop

Wend

#endregion
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
Local $sError = @error
If $sError = 0 Then 
    MsgBox(0, "makedraglist failure =0", $r[0])
Else
    MsgBox(0, 'Error', $sError)
EndIf
EndFunc

there it is as im testing. I get the msgbox "error" with 3 inside and an error in the output pane that says:

==> Subscript used with non-Array variable.:

MsgBox(0, "", $draglistmessage[0])

MsgBox(0, "", $draglistmessage^ ERROR

Edited by quaizywabbit
[u]Do more with pre-existing apps![/u]ANYGUIv2.8
Link to comment
Share on other sites

  • Moderators

Functions are case sensitive when using DLLCall. It's MakeDragList not MakeDraglist.

The call for uint is int ...

You also have RegisterWindowsMessage not RegisterWindowMessage ...

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

;***************************************************
; by Lazycat
;***************************************************
#include <GUIConstants.au3>

Global $WM_DROPFILES = 0x233
Global $gaDropFiles[1], $str = ""

### Koda GUI section start ###
$hGUI = GUICreate("Test", 400, 200, 219, 178, -1, BitOR($WS_EX_ACCEPTFILES, $WS_EX_TOPMOST))
$hList = GUICtrlCreateList("", 5, 5, 390, 190)
GUICtrlSetState (-1, $GUI_DROPACCEPTED)
GUISetState(@SW_SHOW)
### Koda GUI section end   ###

GUIRegisterMsg ($WM_DROPFILES, "WM_DROPFILES_FUNC")

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $GUI_EVENT_DROPPED
            $str = ""
            For $i = 0 To UBound($gaDropFiles) - 1
               $str &= "|" & $gaDropFiles[$i]
            Next
            GUICtrlSetData($hList, $str)
    EndSwitch
WEnd

Func WM_DROPFILES_FUNC($hWnd, $msgID, $wParam, $lParam)
    Local $nSize, $pFileName
    Local $nAmt = DllCall("shell32.dll", "int", "DragQueryFile", "hwnd", $wParam, "int", 0xFFFFFFFF, "ptr", 0, "int", 255)
    For $i = 0 To $nAmt[0] - 1
        $nSize = DllCall("shell32.dll", "int", "DragQueryFile", "hwnd", $wParam, "int", $i, "ptr", 0, "int", 0) 
        $nSize = $nSize[0] + 1
        $pFileName = DllStructCreate("char[" & $nSize & "]")
        DllCall("shell32.dll", "int", "DragQueryFile", "hwnd", $wParam, "int", $i, "ptr", DllStructGetPtr($pFileName), "int", $nSize)
        ReDim $gaDropFiles[$i+1]
        $gaDropFiles[$i] = DllStructGetData($pFileName, 1)
        $pFileName = 0
    Next
EndFunc

SciTE for AutoItDirections for Submitting Standard UDFs

 

Don't argue with an idiot; people watching may not be able to tell the difference.

 

Link to comment
Share on other sites

Functions are case sensitive when using DLLCall. It's MakeDragList not MakeDraglist.

The call for uint is int ...

You also have RegisterWindowsMessage not RegisterWindowMessage ...

Thanks so much for pointing this out! Little details lke that make a world of difference, yet I couldn't see the trees for the forest.........

Now that these key functions don't fail anymore, things can proceed!!!!

Thanks again dude!!!!!!!!!!!!

Edited by quaizywabbit
[u]Do more with pre-existing apps![/u]ANYGUIv2.8
Link to comment
Share on other sites

anyhow, I've verified that the dll calls work using Winspector. :evil:

however , my new problem is how to use the DRAGLISTINFO struct in conjunction with GuiRegisterMessage() [and my defined Message Handler function] :lmao:

I don't see a way to point to the struct rather than Autoit's internals.

I've included the au3 file im using

any help is greatly appreciated ;)

Edited by quaizywabbit
[u]Do more with pre-existing apps![/u]ANYGUIv2.8
Link to comment
Share on other sites

CopyMemoryCopies a block of memory from one location to another.

void CopyMemory( PVOID <A class=synParam onclick=showTip(this) href="">Destination, const VOID* Length);

Parameters

Destination [in] A pointer to the starting address of the copied block's destination. Source [in] A pointer to the starting address of the block of memory to copy. Length [in] The size of the block of memory to copy, in bytes.

Return Values

This function has no return value.

how would i get the length as described above where:

the destination is the ptr to my DRAGLISTINFO struct

the source is the ptr returned in lparam from GuiRegisterMessage (see below)

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

what i'm not understanding is where this data actually went, since it doesn't seem to want to copy into my struct so i can get the notify code.

Edited by quaizywabbit
[u]Do more with pre-existing apps![/u]ANYGUIv2.8
Link to comment
Share on other sites

correct me if im wrong, but to actually make this work I'd need to subclass this control(give it an alternate window procedure.

Part of that would require a pointer to a function..............when calling setwindowlong

or I'd need to read the memory starting from lparam into the struct (copymemory isn't working)

am I correct???

Edited by quaizywabbit
[u]Do more with pre-existing apps![/u]ANYGUIv2.8
Link to comment
Share on other sites

Func MyDraglistHandler($hwnd, $msg, $wParam, $lParam)
    $nID = BitAND($wParam, 0x0000FFFF)
    If $nID = $list Then
        Local $DraglistInfo = DllStructCreate("uint;uint;int;int",$lParam)
        $nNotifyCode = DllStructGetData($DraglistInfo,1)
        ConsoleWrite("uNotification: " & DllStructGetData($DraglistInfo,1) & @LF)
        ConsoleWrite("hWnd: " & DllStructGetData($DraglistInfo,2) & @LF)
        ConsoleWrite("x: " & DllStructGetData($DraglistInfo,3) & @LF)
        ConsoleWrite("y: " & DllStructGetData($DraglistInfo,4) & @LF)
        Select
            Case $nNotifyCode = $DL_BEGINDRAG
                _GUICtrlListAddItem($Hlb, "")
;~              $dragIdx = LBItemFromPt($Hlb, $Point)
                ;reset screen here
                ;return something
            Case $nNotifyCode = $DL_CANCELDRAG
                ;reset screen here
                ;return something
            Case $nNotifyCode = $DL_DRAGGING
;~              $dragIdto = LBItemFromPt($Hlb, $Point)
                DrawInsert($Parent, $Hlb, $dragIdto)
                ;return something
            Case $nNotifyCode = $DL_DROPPED
                ;reset screen here
;~              If LBItemFromPt($Hlb, $Point) <> $dragIdx Then
                    ;do something with it
;~              EndIf
        EndSelect
    EndIf
EndFunc   ;==>MyDraglistHandler

SciTE for AutoItDirections for Submitting Standard UDFs

 

Don't argue with an idiot; people watching may not be able to tell the difference.

 

Link to comment
Share on other sites

having trouble with LBItemFromPt()

only returns -1

probably something simple i'm overlooking.............

see attached script

Replied to your pm, not sure where your getting some of your info from, what I sent is un-tested.

SciTE for AutoItDirections for Submitting Standard UDFs

 

Don't argue with an idiot; people watching may not be able to tell the difference.

 

Link to comment
Share on other sites

  • 1 year later...

Func MyDraglistHandler($hwnd, $msg, $wParam, $lParam)
    $nID = BitAND($wParam, 0x0000FFFF)
    If $nID = $list Then
        Local $DraglistInfo = DllStructCreate("uint;uint;int;int",$lParam)
        $nNotifyCode = DllStructGetData($DraglistInfo,1)
        ConsoleWrite("uNotification: " & DllStructGetData($DraglistInfo,1) & @LF)
        ConsoleWrite("hWnd: " & DllStructGetData($DraglistInfo,2) & @LF)
        ConsoleWrite("x: " & DllStructGetData($DraglistInfo,3) & @LF)
        ConsoleWrite("y: " & DllStructGetData($DraglistInfo,4) & @LF)
        Select
            Case $nNotifyCode = $DL_BEGINDRAG
                _GUICtrlListAddItem($Hlb, "")
;~              $dragIdx = LBItemFromPt($Hlb, $Point)
                ;reset screen here
                ;return something
            Case $nNotifyCode = $DL_CANCELDRAG
                ;reset screen here
                ;return something
            Case $nNotifyCode = $DL_DRAGGING
;~              $dragIdto = LBItemFromPt($Hlb, $Point)
                DrawInsert($Parent, $Hlb, $dragIdto)
                ;return something
            Case $nNotifyCode = $DL_DROPPED
                ;reset screen here
;~              If LBItemFromPt($Hlb, $Point) <> $dragIdx Then
                    ;do something with it
;~              EndIf
        EndSelect
    EndIf
EndFunc   ;==>MyDraglistHandler

is this suppose to let our ListBox items become drag&drop-able items? and i still don't know how to use it.

MyDraglistHandler($hwnd, $msg, $wParam, $lParam) ;$hwnd = listbox right?, what is $msg, $wParam, $lParam?

please add more a very simple ListBox example to use with this. thanks.

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...