Jump to content
mdwerne

[SOLVED] Drag and Drop flies including those in Directories to an edit box?

Recommended Posts

mdwerne
Posted (edited)

So here is my script thus far. I would like to enhance it by adding the ability to drag/drop, and list, not only files, but also files within folders (the folder names can be omitted). For example, if I were to drop the Windows directory on top of the edit window, all files contained within, including those in all the sub-directories, would be listed. Hopefully seeing the GUI will clarify what I'm trying to achieve.

Thank for any suggestions!
-Mike

#include <GDIPlus.au3>
#include <Misc.au3>
#include <Date.au3>
#include <GUIConstants.au3>
;#include <ServiceControl.au3>

Opt('MustDeclareVars', 1)
Opt("TrayMenuMode", 1)

Global $MinimalGUI, $DTUser, $DateTime, $Group, $MediaTypeLabel, $MediaType, $MediaTypeData, $DTObserverLabel, $DTObserver, $DTObserverData, $ActionPerformedLabel, $ActionPerformed, $ActionPerformedData, $ExplanationLabel, $Explanation, $ExplanationData, $SubmitLog, $nMsg, $LogData, $FullGUI, $FilenameWextensionLabel, $FilenameWextension, $FilenameWextensionData, $Result
Global $IP_Address = @IPAddress1
Global $MAC_Address = GET_MAC($IP_Address)
Global $OS_Version = @OSVersion
Global $UserName = @UserName


; =======================================================================
; Command Line Interpretation
; =======================================================================
If $CmdLine[0] = 0 Then ;gui mode

    $FullGUI = GUICreate("DEMO GUI", 640, 500, -1, -1, -1, $WS_EX_ACCEPTFILES)
    Global $idFilemenu = GUICtrlCreateMenu("&File")
    Global $idExititem = GUICtrlCreateMenuItem("Exit", $idFilemenu)
    Global $idHelpmenu = GUICtrlCreateMenu("Help")
    Global $idUserGuide = GUICtrlCreateMenuItem("DEMO User Guide", $idHelpmenu)
    $DTUser = GUICtrlCreateLabel("Approved Username: " & $UserName, 25, 10, 400, 24)
    GUICtrlSetFont(-1, 11 * _GDIPlus_GraphicsGetDPIRatio()[0], 600, 0, "Arial")
    $DateTime = GUICtrlCreateLabel(_Now(), 440, 10, 175, 24, $SS_RIGHT)
    GUICtrlSetFont(-1, 10 * _GDIPlus_GraphicsGetDPIRatio()[0], 600, 0, "Arial")
    $Group = GUICtrlCreateGroup("Please complete the fields below.", 25, 40, 593, 420)
    GUICtrlSetFont(-1, 9 * _GDIPlus_GraphicsGetDPIRatio()[0], 600, 0, "Arial")
    DllCall("UxTheme.dll", "int", "SetWindowTheme", "hwnd", GUICtrlGetHandle($Group), "wstr", 0, "wstr", 0)
    GUICtrlSetColor(-1, 0xFF0000)
    GUICtrlCreateGroup("", -99, -99, 1, 1)
    $DTObserverLabel = GUICtrlCreateLabel("Observers Username:", 35, 66, 250, 24)
    GUICtrlSetFont(-1, 12 * _GDIPlus_GraphicsGetDPIRatio()[0], 400, 0, "MS Sans Serif")
    $DTObserver = GUICtrlCreateInput("e.g. John Doe", 35, 89, 215, 24)
    GUICtrlSetFont(-1, 12 * _GDIPlus_GraphicsGetDPIRatio()[0], 400, 0, "MS Sans Serif")
    $MediaTypeLabel = GUICtrlCreateLabel("Type of removable media:", 260, 66, 200, 24)
    GUICtrlSetFont(-1, 12 * _GDIPlus_GraphicsGetDPIRatio()[0], 400, 0, "MS Sans Serif")
    $MediaType = GUICtrlCreateInput("e.g. CD, USB, TAPE", 260, 89, 180, 24)
    GUICtrlSetFont(-1, 12 * _GDIPlus_GraphicsGetDPIRatio()[0], 400, 0, "MS Sans Serif")
    $FilenameWextensionLabel = GUICtrlCreateLabel("File name/s with extension", 35, 125, 480, 24)
    GUICtrlSetFont(-1, 12 * _GDIPlus_GraphicsGetDPIRatio()[0], 400, 0, "MS Sans Serif")
    $FilenameWextension = GUICtrlCreateEdit("", 35, 150, 575, 155, BitOR($ES_WANTRETURN, $ES_AUTOVSCROLL, $WS_VSCROLL, $ES_MULTILINE))
    GUICtrlSetState(-1, $GUI_DROPACCEPTED)
    GUICtrlSetFont(-1, 9 * _GDIPlus_GraphicsGetDPIRatio()[0], 400, 0, "MS Sans Serif")
    GUICtrlSendMsg($FilenameWextension, $EM_LIMITTEXT, -1, 0)
    $ActionPerformedLabel = GUICtrlCreateLabel("Action Performed:", 35, 313, 250, 24)
    GUICtrlSetFont(-1, 12 * _GDIPlus_GraphicsGetDPIRatio()[0], 400, 0, "MS Sans Serif")
    $ActionPerformed = GUICtrlCreateInput("e.g. Copied project documents from C: drive to F: drive", 35, 335, 575, 24)
    GUICtrlSetFont(-1, 12 * _GDIPlus_GraphicsGetDPIRatio()[0], 400, 0, "MS Sans Serif")
    $ExplanationLabel = GUICtrlCreateLabel("Brief description of how removable media will be used:", 35, 368, 600, 24)
    GUICtrlSetFont(-1, 12 * _GDIPlus_GraphicsGetDPIRatio()[0], 400, 0, "MS Sans Serif")
    $Explanation = GUICtrlCreateEdit("e.g. To allow working on projects document from another workstation.", 35, 390, 575, 60, $ES_MULTILINE)
    GUICtrlSetFont(-1, 12 * _GDIPlus_GraphicsGetDPIRatio()[0], 400, 0, "MS Sans Serif")
    $SubmitLog = GUICtrlCreateButton("SUBMIT LOG", 460, 58, 149, 56, $BS_MULTILINE)
    GUICtrlSetFont(-1, 14 * _GDIPlus_GraphicsGetDPIRatio()[0], 500, 0, "Arial")

    ;GUICtrlSetBkColor($DTUser, 0xFFFFBF) ;For testing
    GUICtrlSetBkColor($DTObserver, 0xFFFFBF)
    GUICtrlSetBkColor($MediaType, 0xFFFFBF)
    GUICtrlSetBkColor($FilenameWextension, 0xFFFFBF)
    ;GUICtrlSetBkColor($FilenameWextensionLabel, 0xFFFFBF)
    GUICtrlSetBkColor($ActionPerformed, 0xFFFFBF)
    GUICtrlSetBkColor($Explanation, 0xFFFFBF)

    GUISetState(@SW_SHOW)

    While 1
        $nMsg = GUIGetMsg()
        Switch $nMsg
            Case $SubmitLog
                $DTObserverData = GUICtrlRead($DTObserver)
                $MediaTypeData = GUICtrlRead($MediaType)
                $FilenameWextensionData = GUICtrlRead($FilenameWextension)
                $ActionPerformedData = GUICtrlRead($ActionPerformed)
                $ExplanationData = GUICtrlRead($Explanation)

                GUISetState(@SW_HIDE)
                $LogData = "data_transfer_agent=" & "'" & $UserName & "'" & "  " & "observer_username=" & "'" & $DTObserverData & "'" & "  " & "media_type=" & "'" & $MediaTypeData & "'" & "  " & "file_names_with_extension=" & "'" & $FilenameWextensionData & "'" & "  " & "action_performed=" & "'" & $ActionPerformedData & "'" & "  " & "explanation=" & "'" & $ExplanationData & "'" & "  " & "machine_name=" & "'" & @ComputerName & "'" & "  " & "ip_address=" & "'" & $IP_Address & "'" & "  " & "mac_address=" & "'" & $MAC_Address & "'" & "  " & "os_version=" & "'" & $OS_Version & "'"
                MsgBox(0, "LogData", $LogData)
                Exit
            Case $idUserGuide
                MsgBox(0, "Coming soon!", "The user guide is not quite ready. We will automatically upgrade your DEMO application once it's complete.")
                ContinueLoop
            Case $GUI_EVENT_CLOSE, $idExititem
                Exit
        EndSwitch
    WEnd
Else
    _Terminate()
EndIf


; #FUNCTION# ====================================================================================================================
; Name ..........: _GDIPlus_GraphicsGetDPIRatio
; Description ...: Get DPI Ratio
; Syntax ........: _GDIPlus_GraphicsGetDPIRatio([$iDPIDef = 96])
; Parameters ....: $iDPIDef             - [optional] An integer value. Default is 96.
; Return values .: actual DPI Ratio as Array, or set @error to non zero, also @extended may be set
; Author ........: UEZ
; Modified ......: argumentum 2015.06.05 / better error return
; Remarks .......:
; Related .......:
; Link ..........: https://www.autoitscript.com/forum/topic/166479-writing-dpi-awareness-app-workaround/
; Example .......: yes
; ===============================================================================================================================
Func _GDIPlus_GraphicsGetDPIRatio($iDPIDef = 96)
    Local $aResults[2] = [1, 1]
    _GDIPlus_Startup()

    Local $hGfx = _GDIPlus_GraphicsCreateFromHWND(0)
    If @error Then Return SetError(1, @extended, $aResults)

    Local $aResult
    #forcedef $__g_hGDIPDll, $ghGDIPDll
    $aResult = DllCall($__g_hGDIPDll, "int", "GdipGetDpiX", "handle", $hGfx, "float*", 0)
    If @error Then Return SetError(2, @error, $aResults)

    Local $iDPI = $aResult[2]
    Local $aResults[2] = [$iDPIDef / $iDPI, $iDPI / $iDPIDef]
    _GDIPlus_GraphicsDispose($hGfx)
    _GDIPlus_Shutdown()
    Return $aResults

EndFunc   ;==>_GDIPlus_GraphicsGetDPIRatio


;Ref https://www.autoitscript.com/forum/topic/165393-get-mac-address-efficiently/
Func GET_MAC($_MACsIP)
    Local $_MAC, $_MACSize
    Local $_MACi, $_MACs, $_MACr, $_MACiIP
    $_MAC = DllStructCreate("byte[6]")
    $_MACSize = DllStructCreate("int")
    DllStructSetData($_MACSize, 1, 6)
    $_MACr = DllCall("Ws2_32.dll", "int", "inet_addr", "str", $_MACsIP)
    $_MACiIP = $_MACr[0]
    $_MACr = DllCall("iphlpapi.dll", "int", "SendARP", "int", $_MACiIP, "int", 0, "ptr", DllStructGetPtr($_MAC), "ptr", DllStructGetPtr($_MACSize))
    $_MACs = ""
    For $_MACi = 0 To 5
        If $_MACi Then $_MACs = $_MACs & ":"
        $_MACs = $_MACs & Hex(DllStructGetData($_MAC, 1, $_MACi + 1), 2)
    Next
    DllClose($_MAC)
    DllClose($_MACSize)
    Return $_MACs
EndFunc   ;==>GET_MAC

Func _Terminate()
    Exit (0)
EndFunc   ;==>_Terminate

 

Edited by mdwerne

Share this post


Link to post
Share on other sites
mdwerne

Any suggestions? Sadly I've just reached the limitations of my skillset, and so far I can find any previous posts that will point me in the right direction.

 

-Mike

Share this post


Link to post
Share on other sites
Earthshine
Posted (edited)

doesn't compile. where did you get servicecontrol.au3 ? I was puzzled about your post, and I can't run it to "see what you mean". when you post code, please tell us where to get the custom udfs that you use or provide links.

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites
mdwerne

Thank for your reply Earthshine. It turns out that the servicecontrol.au3 udf is not needed for this example. I have commented it out in the code above if you still have some time to give it a try.

Again, thank you for your reply.

-Mike

Share this post


Link to post
Share on other sites
Bilgus
Posted (edited)

I threw something together for you

Used an example from Melba https://www.autoitscript.com/forum/topic/143643-using-guisetonevent-with-drag-drop/

Altered it to do what you want

#include <GUIConstantsEx.au3> ; $GUI_EVENT_CLOSE
#include <WindowsConstants.au3>
#include <GuiListBox.au3>

#include <WinAPISys.au3> ;WinAPI_ChangeWindowMessageFilterEx ;_WinAPI_DragQueryFileEx
#include <WinAPIFiles.au3> ;_WinAPI_FindFirstFile

$hGUI = GUICreate("FileDrop", 550, 300, Default, Default, Default, $WS_EX_ACCEPTFILES)

$cList = GUICtrlCreateList("", 0, 0, 450, 300)

$bClear = GUICtrlCreateButton("Clear", 460, 0, 75, 25)
GUICtrlSetFont(-1, 8, 800, 0, "MS Sans Serif")

$cDrop_Dummy = GUICtrlCreateDummy() ;Dummy control recieves notifications on filedrop
GUISetState(@SW_SHOW)

If IsAdmin() Then ; Allow WM_DROPFILES to be received from lower privileged processes (Windows Vista or later)
    _WinAPI_ChangeWindowMessageFilterEx($hGUI, $WM_COPYGLOBALDATA, $MSGFLT_ALLOW)
    _WinAPI_ChangeWindowMessageFilterEx($hGUI, $WM_DROPFILES, $MSGFLT_ALLOW)
EndIf

; Register $WM_DROPFILES function to detect drops anywhere on the GUI
GUIRegisterMsg($WM_DROPFILES, "_WM_DROPFILES")

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit
        Case $cDrop_Dummy
            _On_Drop(GUICtrlRead($cDrop_Dummy))
        Case $bClear
            GUICtrlSetData($cList, "")
    EndSwitch
WEnd

Func _On_Drop($hDrop)
    Local $aDrop_List = _WinAPI_DragQueryFileEx($hDrop, 0) ; 0 = Returns files and folders
    Local $aList[1000][2] = [[0]] ;[FileName][FileSz]
    For $i = 1 To $aDrop_List[0]
        GUICtrlSetData($cList, $aDrop_List[$i]) ;Dumps dropped files to listview
        Find_AllFiles($aDrop_List[$i], $aList) ;Recursively finds files
    Next

    For $i = 1 To $aList[0][0] ;Dumps found files to listview
        GUICtrlSetData($cList, $aList[$i][0])
    Next

EndFunc   ;==>_On_Drop


; React to items dropped on the GUI
Func _WM_DROPFILES($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $lParam
    GUICtrlSendToDummy($cDrop_Dummy, $wParam) ;Send the wParam data to the dummy control
EndFunc   ;==>_WM_DROPFILES

Func Find_AllFiles($sPath, ByRef $aList)

    Local $tData = DllStructCreate($tagWIN32_FIND_DATA)

    Local $sFile
    Local $hSearch = _WinAPI_FindFirstFile($sPath & '\*', $tData)
    While Not @error
        $sFile = DllStructGetData($tData, 'cFileName')
        Switch $sFile
            Case '.', '..'

            Case Else
                If Not BitAND(DllStructGetData($tData, 'dwFileAttributes'), $FILE_ATTRIBUTE_DIRECTORY) Then
                    $aList[0][0] += 1
                    If $aList[0][0] > UBound($aList) - 1 Then
                        ReDim $aList[UBound($aList) + 1000][2]
                    EndIf
                    $aList[$aList[0][0]][0] = $sFile ;if you want full path.. $sPath & "\" & $sFile
                    $aList[$aList[0][0]][1] = _WinAPI_MakeQWord(DllStructGetData($tData, 'nFileSizeLow'), DllStructGetData($tData, 'nFileSizeHigh'))
                Else
                    Find_AllFiles($sFile, $aList)
                EndIf
        EndSwitch
        _WinAPI_FindNextFile($hSearch, $tData)
    WEnd
    _WinAPI_FindClose($hSearch)
EndFunc   ;==>Find_AllFiles

 

 

Edited by Bilgus

Share this post


Link to post
Share on other sites
mdwerne
Posted (edited)

Hi Bilgus,

Thanks for taking the time to poke at this, it's definitely closer than I was before. Unfortunately it seems to be ignoring the files at the same level as the sub directory that is being enumerated. And I don't see how to make it recurse through multiple levels of sub directories. As an example of what I'm after, dropping this folder structure from the root of C:\

File1.txt
File2.txt
Folder1
    File3.txt
    File4.txt
    Folder2
        File5.txt
        File6.txt

Would produce this list in the edit box:

C:\File1.txt
C:\File2.txt
C:\Folder1\File3.txt
C:\Folder1\File4.txt
C:\Folder1\Folder2\File5.txt
C:\Folder1\Folder2\File6.txt

Only the filenames with their full path are displayed...no folders.

Thanks again for looking at this, way above my current skill set.

-Mike

Edited by mdwerne

Share this post


Link to post
Share on other sites
kaz

If i understand that you want, look at the line

$aList[$aList[0][0]][0] = $sFile ;if you want full path.. $sPath & "\" & $sFile

 

Share this post


Link to post
Share on other sites
Bilgus

If you are going to be dropping whole drives a few changes need to be made

One we need a way to limit the recursion not sure of the limit but there will for sure be one.. Autoit will bail if you reach it

Two is it could take a while so you need to inform the user somehow

 

I just put in a message box you'll probably want a status item and to change the cursor to busy etc..

#include <GUIConstantsEx.au3> ; $GUI_EVENT_CLOSE
#include <WindowsConstants.au3>
#include <GuiListBox.au3>

#include <WinAPISys.au3> ;WinAPI_ChangeWindowMessageFilterEx ;_WinAPI_DragQueryFileEx
#include <WinAPIFiles.au3> ;_WinAPI_FindFirstFile

$hGUI = GUICreate("FileDrop", 550, 300, Default, Default, Default, $WS_EX_ACCEPTFILES)

$cList = GUICtrlCreateList("", 0, 0, 450, 300)

$bClear = GUICtrlCreateButton("Clear", 460, 0, 75, 25)
GUICtrlSetFont(-1, 8, 800, 0, "MS Sans Serif")

$cDrop_Dummy = GUICtrlCreateDummy() ;Dummy control recieves notifications on filedrop
GUISetState(@SW_SHOW)

If IsAdmin() Then ; Allow WM_DROPFILES to be received from lower privileged processes (Windows Vista or later)
    _WinAPI_ChangeWindowMessageFilterEx($hGUI, $WM_COPYGLOBALDATA, $MSGFLT_ALLOW)
    _WinAPI_ChangeWindowMessageFilterEx($hGUI, $WM_DROPFILES, $MSGFLT_ALLOW)
EndIf

; Register $WM_DROPFILES function to detect drops anywhere on the GUI
GUIRegisterMsg($WM_DROPFILES, "_WM_DROPFILES")

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit
        Case $cDrop_Dummy
            _On_Drop(GUICtrlRead($cDrop_Dummy))
        Case $bClear
            GUICtrlSetData($cList, "")
    EndSwitch
WEnd

Func _On_Drop($hDrop)
    Local $aDrop_List = _WinAPI_DragQueryFileEx($hDrop, 0) ; 0 = Returns files and folders
    Local $aList[1000][2] = [[0]] ;[FileName][FileSz]

    For $i = 1 To $aDrop_List[0]
        GUICtrlSetData($cList, $aDrop_List[$i]) ;Dumps dropped files to listview
        IF StringLen($aDrop_List[$i]) < 4 Then MsgBox(0,"Test", "This Will Take a While Message Etc...")
        Find_AllFiles($aDrop_List[$i], $aList, 100) ;Recursively finds files
    Next
    _GUICtrlListBox_BeginUpdate ($cList)
    For $i = 1 To $aList[0][0] ;Dumps found files to listview
        GUICtrlSetData($cList, $aList[$i][0])
    Next
    _GUICtrlListBox_EndUpdate ($cList)
EndFunc   ;==>_On_Drop


; React to items dropped on the GUI
Func _WM_DROPFILES($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $lParam
    GUICtrlSendToDummy($cDrop_Dummy, $wParam) ;Send the wParam data to the dummy control
EndFunc   ;==>_WM_DROPFILES

Func Find_AllFiles($sPath, ByRef $aList, $iMaxRecursion, $bRecurse = True)

    Local $tData = DllStructCreate($tagWIN32_FIND_DATA)

    Local $sFile
    If StringRight($sPath, 1) <> "\" Then $sPath &= "\"
    Local $hSearch = _WinAPI_FindFirstFile($sPath & '*', $tData)
    While Not @error
        $sFile = DllStructGetData($tData, 'cFileName')
        Switch $sFile
            Case '.', '..'

            Case Else
                If Not BitAND(DllStructGetData($tData, 'dwFileAttributes'), $FILE_ATTRIBUTE_DIRECTORY) Then
                    $aList[0][0] += 1
                    If $aList[0][0] > UBound($aList) - 1 Then
                        ReDim $aList[UBound($aList) + 4096][2]
                    EndIf
                    $aList[$aList[0][0]][0] = $sPath & $sFile;;$sFile ;if you want full path.. $sPath & "\" & $sFile
                    $aList[$aList[0][0]][1] = _WinAPI_MakeQWord(DllStructGetData($tData, 'nFileSizeLow'), DllStructGetData($tData, 'nFileSizeHigh'))
                Elseif $bRecurse Then
                    if $iMaxRecursion > 0 Then
                    Find_AllFiles($sPath & $sFile, $aList, $iMaxRecursion - 1, $bRecurse)
                    Else
                        Msgbox(0,"Error", "Max Recursion Exceeded")
                    EndIF
                EndIf
        EndSwitch
        _WinAPI_FindNextFile($hSearch, $tData)
    WEnd
    _WinAPI_FindClose($hSearch)
EndFunc   ;==>Find_AllFiles

 

  • Thanks 1

Share this post


Link to post
Share on other sites
mdwerne

WOW, this looks great, thank you both, Bilgus and kaz!!

I may be able to take it from here, but feel free to jump back in if you see an easy way to switch from a list control, to an edit control. I allow users to not only drop files in, but also type them in (but I may just change that).

Just so you know, I would never drop a whole drive on the GUI, this utility will be used in conjunction with a CD burning program. Typical use case is the customer would drag the files/folders to be burned to a CD, and then run this utility, drag the same files to the GUI to then "log" the files that were burned. Yes, not the best process, but it's what I've been asked to work on.

So if making this an edit control is pretty trivial, then I can give it a shot, otherwise I may just keep what you've done with the list control. At this point, I see no reason why they could not just drag and drop additional files, and if they make a mistake, "clear" and start over.

You guys rock!
-Mike

Share this post


Link to post
Share on other sites
Bilgus

You could either set up the listbox to allow selecting items + a delete button and an edit control to type or drop the files in 

or a treeview or even better add a FileOpenDialog

Share this post


Link to post
Share on other sites
mdwerne

Great suggestions, thank you!!

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

×