Jump to content

_WinAPI_DragQueryFileEx()


Recommended Posts

Hi everybody,

I found a hidden bug in function _WinAPI_DragQueryFileEx() , for example :
* When its 2nd parameter is 1 (return files only)
* Then the user drags and drops some files... including mistakenly a folder in the pack.

To reproduce the bug, let's modify 1 line in AutoIt help example, to return files only :

; Local $aFileList = _WinAPI_DragQueryFileEx($wParam)
Local $aFileList = _WinAPI_DragQueryFileEx($wParam, 1)

Now we run the example and tick the checkbox "Enable Drag and drop" at the bottom of the GUI.
Then we select 1 folder and 1 file, dragging & dropping them at same time inside the droppable zone of the GUI

1) If the drag operation has been done with mouse left button pressed over the file line, then the console will correctly show :

--------------------------------------------------
Filename 1.txt

2) But if the drag operation has been done with mouse left button pressed over the folder line, then the console will show nothing :

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

Filename 1.txt is no more in "the list of dropped files" and it's not what is expected.

This bug can be explained : WinAPISysWin.au3 (AutoIt 3.3.14.5), function _WinAPI_DragQueryFileEx(), I'm pasting the original function below :

Func _WinAPI_DragQueryFileEx($hDrop, $iFlag = 0)
    Local $aRet = DllCall('shell32.dll', 'uint', 'DragQueryFileW', 'handle', $hDrop, 'uint', -1, 'ptr', 0, 'uint', 0)
    If @error Then Return SetError(@error, @extended, 0)
    If Not $aRet[0] Then Return SetError(10, 0, 0)

    Local $iCount = $aRet[0]
    Local $aResult[$iCount + 1]
    For $i = 0 To $iCount - 1
        $aRet = DllCall('shell32.dll', 'uint', 'DragQueryFileW', 'handle', $hDrop, 'uint', $i, 'wstr', '', 'uint', 4096)
        If Not $aRet[0] Then Return SetError(11, 0, 0)
        If $iFlag Then
            Local $bDir = _WinAPI_PathIsDirectory($aRet[3])
            If (($iFlag = 1) And $bDir) Or (($iFlag = 2) And Not $bDir) Then
                ContinueLoop
            EndIf
        EndIf
        $aResult[$i + 1] = $aRet[3]
        $aResult[0] += 1
    Next
    If Not $aResult[0] Then Return SetError(12, 0, 0)

    __Inc($aResult, -1)
    Return $aResult
EndFunc   ;==>_WinAPI_DragQueryFileEx

When folder names are dropped (and we don't want them in the final array result), then the "ContinueLoop" in the middle of the function keeps incrementing $i . Because of the way $aresult[] was declared (containing empty elements), this will result in a final array filled with empty rows (rejected folders) followed by valid rows (files accepted only)

Then __Inc() function is called at the end. This __Inc() function (found in WinAPIInternals.au3) will Redim the resulting array, based on what's found in its element [0] : in our case, it will delete the "good" rows placed at the end (path file rows) and keep the "bad" rows (empty folder rows) placed at the beginning of the array. Here is __Inc() Redim code :

If $iIncrement < 0 Then
    ReDim $aData[$aData[0] + 1]
Else
...
EndIf

This __Inc() function has to be called because of the way $aResult[] is declared in _WinAPI_DragQueryFileEx()  :

Local $iCount = $aRet[0]    ; count of all files & folders dropped
Local $aResult[$iCount + 1] ; declare them all for now, __Inc() will Redim in the end

The patch could be something like this, in _WinAPI_DragQueryFileEx() :

Local $iCount = $aRet[0], $iValidRow = 0 ; MODIFIED (added $iValidRow)
    ... 
    
    $iValidRow += 1 ; ADDED
;~  $aResult[$i + 1] = $aRet[3] ; COMMENTED
    $aResult[$iValidRow] = $aRet[3] ; ADDED

    $aResult[0] += 1 ; UNCHANGED

I didn't test the other case (2nd param = 2, which means return folders only) but it should be the same issue.

A simpler solution ?
Blame the user ! "Why did you drag a folder among your files ?" :D

Edit: for the record, I'm using a customized version of this function. The result looks like this, when the user should only drag files but mistakenly drags a folder among them :

429323520_dragdrop1.png.bf5e13ac01b85d34a391467a82fb225d.png

7 items on the drag, then just after the drop :

1776822476_dragdrop2.png.dcaa73a506475a16a7b21f18e01111e6.png

Edited by pixelsearch
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...