Jump to content

Recommended Posts

Posted
3 hours ago, WildByDesign said:

Matty, may I please have your permission to use this code in the Files Au3 file manager project?

For curiosity sake, I tested it out there briefly. It allowed me to drag and drop nicely from the ListView but also the TreeView as well once I modified the code slightly.

@MattyD Sorry to load you up on comments here. The wheels of thought keep on spinning.

One thing that I've found to be problematic about this whole DoDragDrop functionality is that it doesn't allow AutoIt to perform any other functions until the drop is complete. I assume that this has something to do with AutoIt not having multiple thread support.

For example, in Files Au3 in the previous drag and drop code, I have some code that takes care of bringing up the drop highlightiing of the TreeView items and ListView items as the cursor hovers over them to give the user a better idea of where they are dropping. But this doesn't seem to work with the DoDragDrop method. Nothing from the main While loop executes either. This drag and drop stuff is certainly complicated. 

Posted
3 minutes ago, MattyD said:

Supposedly it's meant to make working with drag images easier too. (if we want more than that cursor with the little plus-in-a-box).

Speaking of this, I have never had any success in creating any drag images with treeview or listview. There are only about 10-12 previous examples for this in the forum and none of them seem to work either. Nor the examples from the AutoIt help files. I wanted to create a drag image of the file type, for example, but was never successful with that unfortunately.

Posted
5 minutes ago, WildByDesign said:

it doesn't allow AutoIt to perform any other functions until the drop is complete

Yep, we're in a loop until DoDragDrop returns.  But, the GiveFeedback method is called as part of that loop - so maybe just hook into that for the short term  ;)

I think the proper way (from a very superficial look) is to setup a DropTarget object which is supposed to help with insertion marks for listviews. Not sure how that looks for a treeview, but its probably worth reading up on.

12 minutes ago, WildByDesign said:

I have never had any success in creating any drag images with treeview or listview

Ok, I'll add that to the list of things to investigate. 

Posted (edited)
8 hours ago, MattyD said:

I think the proper way (from a very superficial look) is to setup a DropTarget object which is supposed to help with insertion marks for listviews.

I spent some time looking into this today but I didn't fully understand how to create the DropTarget.

8 hours ago, MattyD said:

But, the GiveFeedback method is called as part of that loop - so maybe just hook into that for the short term  ;).

This does work pretty good for now. You've created some great structure with the __Mthd_GiveFeedback, __Mthd_DragEnterTarget and __Mthd_DragLeaveTarget functions. I'm using a combination of those right now to determine the handle of which ListView or TreeView I am currently hovering over and making the necessary drophilite changes. It may not be the proper way to do it but it seems to be working well enough.

Edited by WildByDesign
Posted

@MattyD

Will this work for creating an IDataObject? I don't know, as I haven't tried it.
Create a blank IDataObject using SHCreateDataObject, and then fill it using SetData.

Func __SHCreateDataObject($tIID_IDataObject, $ppidlFolder = 0, $cidl = 0, $papidl = 0, $pdtInner = 0)
    Local $aRes = DllCall("shell32.dll", "long", "SHCreateDataObject", _
                                         "ptr", $ppidlFolder, _          
                                         "uint", $cidl, _
                                         "ptr", $papidl, _ 
                                         "ptr", $pdtInner, _
                                         "struct*", $tIID_IDataObject, _
                                         "ptr*", 0)
    If @error Then Return SetError(1, 0, $aRes[0])
    Return $aRes[6]
EndFunc

Local $sIID_IDataObject = "{0000010E-0000-0000-C000-000000000046}"
Local $triid = _WinAPI_GUIDFromString($sIID_IDataObject)
Local $pIDataObject = __SHCreateDataObject($triid, 0, 0, 0, 0)      ;~ blank IDataObject

Local Const $tag_IDataObject = _
                    "GetData hresult(ptr;ptr*);" & _
                    "GetDataHere hresult(ptr;ptr*);" & _
                    "QueryGetData hresult(ptr);" & _
                    "GetCanonicalFormatEtc hresult(ptr;ptr*);" & _
                    "SetData hresult(ptr;ptr;bool);" & _
                    "EnumFormatEtc hresult(dword;ptr*);" & _
                    "DAdvise hresult(ptr;dword;ptr;dword*);" & _
                    "DUnadvise hresult(dword);" & _
                    "EnumDAdvise hresult(ptr*);"
Local $oIDataObject = ObjCreateInterface($pIDataObject, $sIID_IDataObject, $tag_IDataObject)

$tFORMATETC = _Create_FORMATETC()
$tSTGMEDIUM = _Create_STGMEDIUM_FileData($s_FilePath)

$oIDataObject.SetData(DllStructGetPtr($tFORMATETC), DllStructGetPtr($tSTGMEDIUM), 1)    ;~ fill IDataObject

 

Posted (edited)
On 1/23/2026 at 10:52 PM, MattyD said:

There seems to be a drag-drop mechanism baked into AutoIt's message handling

I noticed that you had to comment out Opt("GUICloseOnESC", 0) in your example. That baked in drag-drop mechanism is definitely problematic. You would typically want that Esc key available to cancel the operation.

Since I use OnEventMode for the majority of my projects, I decided to test Opt("GUIOnEventMode", 1) with your Demo example. I was expecting it to fail anyway. As expected, it also fails which is unfortunate. I think it's safe to assume that any of the Opt("GUI...") options will not work.

If you do end up thinking of a way to disable that baked in AutoIt drag-drop functionality without losing out on the Opt("GUI...") options or if you find a way to stop the built in drag-drop functionality from getting left in drag mode as Nine mentioned as well, please let me know. :)

Obviously, your subclassing fixes all of that. But I'm not certain that losing the Opt("GUI...") options is worth it.

EDIT: I think that I may have figured it out. Or at least a workaround.

Case $LVN_BEGINDRAG
    Return 1 ; or Return 0

As we know, $LVN_BEGINDRAG is not supposed to have a return value. However, I've just tested and it does cancel the built in drag operation while the DoDragDrop operation continues.

I don't fully understand all of the ramifications from this. However, in my own testing, both Return 0 and Return 1 work beautifully and solves the issue on my end. 

EDIT2: The best way to test this is with @MattyD's first Demo example where he had not yet subclassed the GUI.

Return      ; fails, 
Return 0    ; works
Return 1    ; works

 

Edited by WildByDesign
Posted (edited)
10 hours ago, jugador said:

Will this work for creating an IDataObject?

yep, seems like that should work. Thank you - that's going to save a bunch of time!

8 hours ago, WildByDesign said:
Return      ; fails, 
Return 0    ; works
Return 1    ; works

Also great pickup, yes this makes more sense than subclassing:

Return 0 from WM_DROPFILES
Return 0 from WM_NOTIFY when its a $LVN_BEGINDRAG or $LVN_BEGINRDRAG, otherwise return $GUI_RUNDEFMSG..

Edit: 

8 hours ago, WildByDesign said:

I noticed that you had to comment out Opt("GUICloseOnESC", 0) in your example

nah, I didn't have to - It just doesn't serve a purpose when we're bypassing all the autoIt handlers in the window proc :). The esc key can't close the window if we break the mechanism!

Edited by MattyD
Posted

@MattyD I have a question for you regarding the cursor from DRAGDROP_S_USEDEFAULTCURSORS.

Outside of this DoDragDrop function, do you know of any way to obtain the handle for that drag/drop cursor that is returned by DRAGDROP_S_USEDEFAULTCURSORS?

I am just curious about trying some things with _WinAPI_SetSystemCursor function or other similar functions. Thanks. :)

Posted

After a lot of trial and error, I finally got the proper OS drag image working and it has the built-in tooltip. Part of the problem was that it doesn't work when the script runs as x86. It seems to be 64-bit only.

I used the function from @ProgAndy's older script and modified it to work with your Demo example.

; Call function with:
; _SHDoDragDrop($hGUI, $pDataObj, $pDropSource,  BitOR($DROPEFFECT_COPY,$DROPEFFECT_LINK))

Func _SHDoDragDrop($hWnd, ByRef $pDataObj, ByRef $pDropSource, $dwDropEffects)
    Local $result = DllCall("shell32.dll","lresult","SHDoDragDrop", "hwnd", Null, "ptr", $pDataObj,"ptr", Null, "dword", BitOR($DROPEFFECT_COPY,$DROPEFFECT_LINK), "dword*", 0)
EndFunc

The real trick that ended up making it work was the Null for hWnd and the Null for drop source. Since with SHDoDragDrop, the OS will take care of both of those. In the end, we get the same beautiful drag image (with tooltip) that File Explorer uses that shows the file type icon. The tooltip shows whether the file is being copied or moved and to which directory the cursor is hovering over. This makes everything so much easier. 

Posted (edited)
9 hours ago, Netol said:

This code working fine only drag and drop element to outside but not permit drag and drop files inside of the listview

We can always handle the WM_DROPFILES messages for that.

However from my understanding, it would be better to register the window (and specific controls?) as drop targets with the RegisterDragDrop and handle the various methods by return certain effects.

The developer for Explorer++ suggests:

(from source and source)

Quote

    // The main window is registered as a drop target only so that the drag image will be
    // consistently shown when an item is being dragged. For the drag image to be shown, the
    // relevant IDropTargetHelper methods need to be called during the drag. To do that, the window
    // under the mouse needs to be registered as a drop target.
    // Rather than having to register every window, the top-level window can simply be registered
    // instead. That way, it will act as a fallback if there isn't a more specific child window
    // registered.

So that explains why we cannot see the drag image on our own window. The problem where I am right now is that I don't know how to setup an IDropTarget interface.

EDIT: Looks like we really need an IDropTargetHelper interface if we want to show the drag image over our own window.

Edited by WildByDesign

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
×
×
  • Create New...