Jump to content

_FIleListToArrayRec hanging


Recommended Posts

Hello,

I have found a very specific case where _FileListToArrayRec() hangs.

The setup:

  1. Have a mapped network drive
  2. Put a file in a folder starting with a "-".

For example, map a P drive and then create "P:\-test.txt"

#include <File.au3>
Opt("TrayIconDebug", 1)
$files = _FileListToArrayRec("P:\test\sync", "*", $FLTAR_FILES, $FLTAR_RECUR)
MsgBox(48, "Done", "Done")

Running that code for me never hit's the "Done" message box. If you hover over the tray icon you can see it's stuck in File.au3 indefinitely.

I copied _FileListToArrayRec() into my project and started debugging. It seems as though the files get added to the list, "." and ".." do every time as well which is why the While statement:

While $asFolderSearchList[0] > 0

Never evaluates to false.

If I turn of recursion, then the filter "*||.+" seems to fix this. Experimenting with ways to fix it with recursion enabled. However, this appears to be a bug to me. Note that this doesn't happen on local files.

Link to comment
Share on other sites

Seems like if a file with "-" is in the folder, FileFindFirstFile() returns "." and ".." folders which only the DLL call variant of the code handles.

See the following (poorly) instrumented ___FileListToArraRec():
 

Func ___FileListToArrayRec($sFilePath, $sMask = "*", $iReturn = $FLTAR_FILESFOLDERS, $iRecur = $FLTAR_NORECUR, $iSort = $FLTAR_NOSORT, $iReturnPath = $FLTAR_RELPATH)
    If Not FileExists($sFilePath) Then Return SetError(1, 1, "")

    ; Check for Default keyword
    If $sMask = Default Then $sMask = "*"
    If $iReturn = Default Then $iReturn = $FLTAR_FILESFOLDERS
    If $iRecur = Default Then $iRecur = $FLTAR_NORECUR
    If $iSort = Default Then $iSort = $FLTAR_NOSORT
    If $iReturnPath = Default Then $iReturnPath = $FLTAR_RELPATH

    ; Check for valid recur value
    If $iRecur > 1 Or Not IsInt($iRecur) Then Return SetError(1, 6, "")

    Local $bLongPath = False
    ; Check for valid path
    If StringLeft($sFilePath, 4) == "\\?\" Then
        $bLongPath = True
    EndIf

    Local $sFolderSlash = ""
    ; Check if folders should have trailing \ and ensure that initial path does have one
    If StringRight($sFilePath, 1) = "\" Then
        $sFolderSlash = "\"
    Else
        $sFilePath = $sFilePath & "\"
    EndIf

    Local $asFolderSearchList[100] = [1]
    ; Add path to folder search list
    $asFolderSearchList[1] = $sFilePath

    Local $iHide_HS = 0, _
            $sHide_HS = ""
    ; Check for H or S omitted
    If BitAND($iReturn, 4) Then
        $iHide_HS += 2
        $sHide_HS &= "H"
        $iReturn -= 4
    EndIf
    If BitAND($iReturn, 8) Then
        $iHide_HS += 4
        $sHide_HS &= "S"
        $iReturn -= 8
    EndIf

    Local $iHide_Link = 0
    ; Check for link/junction omitted
    If BitAND($iReturn, 16) Then
        $iHide_Link = 0x400
        $iReturn -= 16
    EndIf

    Local $iMaxLevel = 0
    ; If required, determine \ count for max recursive level setting
    If $iRecur < 0 Then
        StringReplace($sFilePath, "\", "", 0, $STR_NOCASESENSEBASIC)
        $iMaxLevel = @extended - $iRecur
    EndIf

    Local $sExclude_List = "", $sExclude_List_Folder = "", $sInclude_List = "*"
    ; Check mask parameter
    Local $aMaskSplit = StringSplit($sMask, "|")
    ; Check for multiple sections and set values
    Switch $aMaskSplit[0]
        Case 3
            $sExclude_List_Folder = $aMaskSplit[3]
            ContinueCase
        Case 2
            $sExclude_List = $aMaskSplit[2]
            ContinueCase
        Case 1
            $sInclude_List = $aMaskSplit[1]
    EndSwitch

    Local $sInclude_File_Mask = ".+"
    ; Create Include mask for files
    If $sInclude_List <> "*" Then
        If Not __FLTAR_ListToMask($sInclude_File_Mask, $sInclude_List) Then Return SetError(1, 2, "")
    EndIf

    Local $sInclude_Folder_Mask = ".+"
    ; Set Include mask for folders
    Switch $iReturn
        Case 0
            ; Folders affected by mask if not recursive
            Switch $iRecur
                Case 0
                    ; Folders match mask for compatibility
                    $sInclude_Folder_Mask = $sInclude_File_Mask
            EndSwitch
        Case 2
            ; Folders affected by mask
            $sInclude_Folder_Mask = $sInclude_File_Mask
    EndSwitch

    Local $sExclude_File_Mask = ":"
    ; Create Exclude List mask for files
    If $sExclude_List <> "" Then
        If Not __FLTAR_ListToMask($sExclude_File_Mask, $sExclude_List) Then Return SetError(1, 3, "")
    EndIf

    Local $sExclude_Folder_Mask = ":"
    ; Create Exclude mask for folders
    If $iRecur Then
        If $sExclude_List_Folder Then
            If Not __FLTAR_ListToMask($sExclude_Folder_Mask, $sExclude_List_Folder) Then Return SetError(1, 4, "")
        EndIf
        ; If folders only
        If $iReturn = 2 Then
            ; Folders affected by normal mask
            $sExclude_Folder_Mask = $sExclude_File_Mask
        EndIf
    Else
        ; Folders affected by normal mask
        $sExclude_Folder_Mask = $sExclude_File_Mask
    EndIf

    ; Verify other parameters
    If Not ($iReturn = 0 Or $iReturn = 1 Or $iReturn = 2) Then Return SetError(1, 5, "")
    If Not ($iSort = 0 Or $iSort = 1 Or $iSort = 2) Then Return SetError(1, 7, "")
    If Not ($iReturnPath = 0 Or $iReturnPath = 1 Or $iReturnPath = 2) Then Return SetError(1, 8, "")

    ; Prepare for DllCall if required
    If $iHide_Link Then
        Local $tFile_Data = DllStructCreate("struct;align 4;dword FileAttributes;uint64 CreationTime;uint64 LastAccessTime;uint64 LastWriteTime;" & _
                "dword FileSizeHigh;dword FileSizeLow;dword Reserved0;dword Reserved1;wchar FileName[260];wchar AlternateFileName[14];endstruct")
        Local $hDLL = DllOpen('kernel32.dll'), $aDLL_Ret
    EndIf

    Local $asReturnList[100] = [0]
    Local $asFileMatchList = $asReturnList, $asRootFileMatchList = $asReturnList, $asFolderMatchList = $asReturnList
    Local $bFolder = False, _
            $hSearch = 0, _
            $sCurrentPath = "", $sName = "", $sRetPath = ""
    Local $iAttribs = 0, _
            $sAttribs = ''
    Local $asFolderFileSectionList[100][2] = [[0, 0]]
    ; Search within listed folders
    While $asFolderSearchList[0] > 0
        _Log("While no folders")
        Sleep(100)
        ; Set path to search
        $sCurrentPath = $asFolderSearchList[$asFolderSearchList[0]]
        ; Reduce folder search list count
        $asFolderSearchList[0] -= 1
        ; Determine return path to add to file/folder name
        Switch $iReturnPath
            ; Case 0 ; Name only
            ; Leave as ""
            Case 1 ;Relative to initial path
                $sRetPath = StringReplace($sCurrentPath, $sFilePath, "")
            Case 2 ; Full path
                If $bLongPath Then
                    $sRetPath = StringTrimLeft($sCurrentPath, 4)
                Else
                    $sRetPath = $sCurrentPath
                EndIf
        EndSwitch

        ; Get search handle - use code matched to required listing
        If $iHide_Link Then
            ; Use DLL code
            $aDLL_Ret = DllCall($hDLL, 'handle', 'FindFirstFileW', 'wstr', $sCurrentPath & "*", 'struct*', $tFile_Data)
            If @error Or Not $aDLL_Ret[0] Then
                ContinueLoop
            EndIf
            $hSearch = $aDLL_Ret[0]
        Else
            ; Use native code
            $hSearch = FileFindFirstFile($sCurrentPath & "*")
            ; If folder empty move to next in list
            If $hSearch = -1 Then
                ContinueLoop
            EndIf
        EndIf

        ; If sorting files and folders with paths then store folder name and position of associated files in list
        If $iReturn = 0 And $iSort And $iReturnPath Then
            __FLTAR_AddToList($asFolderFileSectionList, $sRetPath, $asFileMatchList[0] + 1)
        EndIf
        $sAttribs = ''

        ; Search folder - use code matched to required listing
        While 1
            _Log("While 1 start")
            Sleep(100)
            ; Use DLL code
            If $iHide_Link Then
                _Log("DLL call")
                Sleep(100)
                ; Use DLL code
                $aDLL_Ret = DllCall($hDLL, 'int', 'FindNextFileW', 'handle', $hSearch, 'struct*', $tFile_Data)
                ; Check for end of folder
                If @error Or Not $aDLL_Ret[0] Then
                    ExitLoop
                EndIf
                ; Extract data
                $sName = DllStructGetData($tFile_Data, "FileName")
                ; Check for .. return - only returned by the DllCall
                If $sName = ".." Then
                    ContinueLoop
                EndIf
                $iAttribs = DllStructGetData($tFile_Data, "FileAttributes")
                ; Check for hidden/system attributes and skip if found
                If $iHide_HS And BitAND($iAttribs, $iHide_HS) Then
                    ContinueLoop
                EndIf
                ; Check for link attribute and skip if found
                If BitAND($iAttribs, $iHide_Link) Then
                    ContinueLoop
                EndIf
                ; Set subfolder flag
                $bFolder = False
                If BitAND($iAttribs, 16) Then
                    $bFolder = True
                EndIf
            Else
                _Log("No DLL call")
                Sleep(100)
                ; Reset folder flag
                $bFolder = False
                ; Use native code
                $sName = FileFindNextFile($hSearch, 1)
                ; Check for end of folder
                If @error Then
                    _Log("error find next file")
                    Sleep(100)
                    ExitLoop
                EndIf
                $sAttribs = @extended
                ; Check for folder
                If StringInStr($sAttribs, "D") Then
                    _Log("folder " & $sName)
                    Sleep(100)
                    $bFolder = True
                EndIf
                ; Check for Hidden/System
                If StringRegExp($sAttribs, "[" & $sHide_HS & "]") Then
                    _Log("hidden/system")
                    Sleep(100)
                    ContinueLoop
                EndIf
            EndIf

            ; If folder then check whether to add to search list
            If $bFolder Then
                Select
                    Case $iRecur < 0 ; Check recur depth
                        _Log("recur < 0")
                        StringReplace($sCurrentPath, "\", "", 0, $STR_NOCASESENSEBASIC)
                        If @extended < $iMaxLevel Then
                            _Log("max level ")
                            ContinueCase ; Check if matched to masks
                        EndIf
                    Case $iRecur = 1 ; Full recur
                        _Log("recur = 1")
                        If Not StringRegExp($sName, $sExclude_Folder_Mask) Then ; Add folder unless excluded
                            _Log("aded folder " & $sName & " to list ")
                            __FLTAR_AddToList($asFolderSearchList, $sCurrentPath & $sName & "\")
                        EndIf
                        ; Case $iRecur = 0 ; Never add
                        ; Do nothing
                EndSelect
            EndIf

            If $iSort Then ; Save in relevant folders for later sorting
                If $bFolder Then
                    If StringRegExp($sName, $sInclude_Folder_Mask) And Not StringRegExp($sName, $sExclude_Folder_Mask) Then
                        __FLTAR_AddToList($asFolderMatchList, $sRetPath & $sName & $sFolderSlash)
                    EndIf
                Else
                    If StringRegExp($sName, $sInclude_File_Mask) And Not StringRegExp($sName, $sExclude_File_Mask) Then
                        ; Select required list for files
                        If $sCurrentPath = $sFilePath Then
                            __FLTAR_AddToList($asRootFileMatchList, $sRetPath & $sName)
                        Else
                            __FLTAR_AddToList($asFileMatchList, $sRetPath & $sName)
                        EndIf
                    EndIf
                EndIf
            Else ; Save directly in return list
                If $bFolder Then
                    If $iReturn <> 1 And StringRegExp($sName, $sInclude_Folder_Mask) And Not StringRegExp($sName, $sExclude_Folder_Mask) Then
                        __FLTAR_AddToList($asReturnList, $sRetPath & $sName & $sFolderSlash)
                    EndIf
                Else
                    _Log("Checking file add to list")
                    If $iReturn <> 2 And StringRegExp($sName, $sInclude_File_Mask) And Not StringRegExp($sName, $sExclude_File_Mask) Then
                        _Log("added file " & $sName & " to list ")
                        __FLTAR_AddToList($asReturnList, $sRetPath & $sName)
                    EndIf
                EndIf
            EndIf

        WEnd

        ; Close current search
        If $iHide_Link Then
            DllCall($hDLL, 'int', 'FindClose', 'ptr', $hSearch)
        Else
            FileClose($hSearch)
        EndIf

    WEnd

    ; Close the DLL if needed
    If $iHide_Link Then
        DllClose($hDLL)
    EndIf

    ; Sort results if required
    If $iSort Then
        Switch $iReturn
            Case 2 ; Folders only
                ; Check if any folders found
                If $asFolderMatchList[0] = 0 Then Return SetError(1, 9, "")
                ; Correctly size folder match list
                ReDim $asFolderMatchList[$asFolderMatchList[0] + 1]
                ; Copy size folder match array
                $asReturnList = $asFolderMatchList
                ; Simple sort list
                __ArrayDualPivotSort($asReturnList, 1, $asReturnList[0])
            Case 1 ; Files only
                ; Check if any files found
                If $asRootFileMatchList[0] = 0 And $asFileMatchList[0] = 0 Then Return SetError(1, 9, "")
                If $iReturnPath = 0 Then ; names only so simple sort suffices
                    ; Combine file match lists
                    __FLTAR_AddFileLists($asReturnList, $asRootFileMatchList, $asFileMatchList)
                    ; Simple sort combined file list
                    __ArrayDualPivotSort($asReturnList, 1, $asReturnList[0])
                Else
                    ; Combine sorted file match lists
                    __FLTAR_AddFileLists($asReturnList, $asRootFileMatchList, $asFileMatchList, 1)
                EndIf
            Case 0 ; Both files and folders
                ; Check if any root files or folders found
                If $asRootFileMatchList[0] = 0 And $asFolderMatchList[0] = 0 Then Return SetError(1, 9, "")
                If $iReturnPath = 0 Then ; names only so simple sort suffices
                    ; Combine file match lists
                    __FLTAR_AddFileLists($asReturnList, $asRootFileMatchList, $asFileMatchList)
                    ; Set correct count for folder add
                    $asReturnList[0] += $asFolderMatchList[0]
                    ; Resize and add file match array
                    ReDim $asFolderMatchList[$asFolderMatchList[0] + 1]
                    _ArrayConcatenate($asReturnList, $asFolderMatchList, 1)
                    ; Simple sort final list
                    __ArrayDualPivotSort($asReturnList, 1, $asReturnList[0])
                Else
                    ; Size return list
                    Local $asReturnList[$asFileMatchList[0] + $asRootFileMatchList[0] + $asFolderMatchList[0] + 1]
                    $asReturnList[0] = $asFileMatchList[0] + $asRootFileMatchList[0] + $asFolderMatchList[0]
                    ; Sort root file list
                    __ArrayDualPivotSort($asRootFileMatchList, 1, $asRootFileMatchList[0])
                    ; Add the sorted root files at the top
                    For $i = 1 To $asRootFileMatchList[0]
                        $asReturnList[$i] = $asRootFileMatchList[$i]
                    Next
                    ; Set next insertion index
                    Local $iNextInsertionIndex = $asRootFileMatchList[0] + 1
                    ; Sort folder list
                    __ArrayDualPivotSort($asFolderMatchList, 1, $asFolderMatchList[0])
                    Local $sFolderToFind = ""
                    ; Work through folder list
                    For $i = 1 To $asFolderMatchList[0]
                        ; Add folder to return list
                        $asReturnList[$iNextInsertionIndex] = $asFolderMatchList[$i]
                        $iNextInsertionIndex += 1
                        ; Format folder name for search
                        If $sFolderSlash Then
                            $sFolderToFind = $asFolderMatchList[$i]
                        Else
                            $sFolderToFind = $asFolderMatchList[$i] & "\"
                        EndIf
                        Local $iFileSectionEndIndex = 0, $iFileSectionStartIndex = 0
                        ; Find folder in FolderFileSectionList
                        For $j = 1 To $asFolderFileSectionList[0][0]
                            ; If found then deal with files
                            If $sFolderToFind = $asFolderFileSectionList[$j][0] Then
                                ; Set file list indexes
                                $iFileSectionStartIndex = $asFolderFileSectionList[$j][1]
                                If $j = $asFolderFileSectionList[0][0] Then
                                    $iFileSectionEndIndex = $asFileMatchList[0]
                                Else
                                    $iFileSectionEndIndex = $asFolderFileSectionList[$j + 1][1] - 1
                                EndIf
                                ; Sort files if required
                                If $iSort = 1 Then
                                    __ArrayDualPivotSort($asFileMatchList, $iFileSectionStartIndex, $iFileSectionEndIndex)
                                EndIf
                                ; Add files to return list
                                For $k = $iFileSectionStartIndex To $iFileSectionEndIndex
                                    $asReturnList[$iNextInsertionIndex] = $asFileMatchList[$k]
                                    $iNextInsertionIndex += 1
                                Next
                                ExitLoop
                            EndIf
                        Next
                    Next
                EndIf
        EndSwitch
    Else ; No sort
        ; Check if any file/folders have been added
        If $asReturnList[0] = 0 Then Return SetError(1, 9, "")
        ; Remove any unused return list elements from last ReDim
        ReDim $asReturnList[$asReturnList[0] + 1]

    EndIf

    Return $asReturnList
EndFunc   ;==>_FileListToArrayRec

 

Here is the output of that logging with "test.txt":
 

While no folders
While 1 start
No DLL call
Checking file add to list
added file test.txt to list 
While 1 start
No DLL call
error find next file

Here is the output with "-test.txt":
 

While no folders
While 1 start
No DLL call
Checking file add to list
added file -test.txt to list 
While 1 start
No DLL call
folder .
recur = 1
aded folder . to list 
While 1 start
No DLL call
folder ..
recur = 1
aded folder .. to list 
While 1 start
No DLL call
error find next file

You can see folder . and .. added to the list

Link to comment
Share on other sites

Nevermind, the file doesn't show up if I have "FLTAR_NOLINK" added.  In this case _ArrayDisplay() will not show the array since none was created.

#include <File.au3>
Opt("TrayIconDebug", 1)
$files = _FileListToArrayRec("P:\test\sync", "*", $FLTAR_FILES + $FLTAR_NOLINK, $FLTAR_RECUR)
_ArrayDisplay($files)
MsgBox(48, "Done", "Done")

 

Link to comment
Share on other sites

Ok, the filter "*||.*" seems to work.

Still think "." and ".." should always be handled by _FileListToArrayRec() let me know what you guys think.

#include <File.au3>
Opt("TrayIconDebug", 1)
$files = _FileListToArrayRec("P:\test\sync", "*||.*", $FLTAR_FILES, $FLTAR_RECUR)
_ArrayDisplay($files)
MsgBox(48, "Done", "Done")

@Melba23 you're on the contributor list for File.au3 wondering your thoughts :)

Link to comment
Share on other sites

Note I updated my example with my hacked version of ___FileListToArrayRec()

In this I added 

If $sName = ".." Then
    ContinueLoop
EndIf
If $sName = "." Then
    ContinueLoop
EndIf

To the native code block and the function works.

Also added a simple _Log function so that the code runs.

Complete example:

#include <File.au3>
Opt("TrayIconDebug", 1)
$files = ___FileListToArrayRec("P:\test\sync", "*", $FLTAR_FILES, $FLTAR_RECUR)
_ArrayDisplay($files)
MsgBox(48, "Done", "Done")

Func _Log($message)
    ConsoleWrite($message & @CRLF)
EndFunc

Func ___FileListToArrayRec($sFilePath, $sMask = "*", $iReturn = $FLTAR_FILESFOLDERS, $iRecur = $FLTAR_NORECUR, $iSort = $FLTAR_NOSORT, $iReturnPath = $FLTAR_RELPATH)
    If Not FileExists($sFilePath) Then Return SetError(1, 1, "")

    ; Check for Default keyword
    If $sMask = Default Then $sMask = "*"
    If $iReturn = Default Then $iReturn = $FLTAR_FILESFOLDERS
    If $iRecur = Default Then $iRecur = $FLTAR_NORECUR
    If $iSort = Default Then $iSort = $FLTAR_NOSORT
    If $iReturnPath = Default Then $iReturnPath = $FLTAR_RELPATH

    ; Check for valid recur value
    If $iRecur > 1 Or Not IsInt($iRecur) Then Return SetError(1, 6, "")

    Local $bLongPath = False
    ; Check for valid path
    If StringLeft($sFilePath, 4) == "\\?\" Then
        $bLongPath = True
    EndIf

    Local $sFolderSlash = ""
    ; Check if folders should have trailing \ and ensure that initial path does have one
    If StringRight($sFilePath, 1) = "\" Then
        $sFolderSlash = "\"
    Else
        $sFilePath = $sFilePath & "\"
    EndIf

    Local $asFolderSearchList[100] = [1]
    ; Add path to folder search list
    $asFolderSearchList[1] = $sFilePath

    Local $iHide_HS = 0, _
            $sHide_HS = ""
    ; Check for H or S omitted
    If BitAND($iReturn, 4) Then
        $iHide_HS += 2
        $sHide_HS &= "H"
        $iReturn -= 4
    EndIf
    If BitAND($iReturn, 8) Then
        $iHide_HS += 4
        $sHide_HS &= "S"
        $iReturn -= 8
    EndIf

    Local $iHide_Link = 0
    ; Check for link/junction omitted
    If BitAND($iReturn, 16) Then
        $iHide_Link = 0x400
        $iReturn -= 16
    EndIf

    Local $iMaxLevel = 0
    ; If required, determine \ count for max recursive level setting
    If $iRecur < 0 Then
        StringReplace($sFilePath, "\", "", 0, $STR_NOCASESENSEBASIC)
        $iMaxLevel = @extended - $iRecur
    EndIf

    Local $sExclude_List = "", $sExclude_List_Folder = "", $sInclude_List = "*"
    ; Check mask parameter
    Local $aMaskSplit = StringSplit($sMask, "|")
    ; Check for multiple sections and set values
    Switch $aMaskSplit[0]
        Case 3
            $sExclude_List_Folder = $aMaskSplit[3]
            ContinueCase
        Case 2
            $sExclude_List = $aMaskSplit[2]
            ContinueCase
        Case 1
            $sInclude_List = $aMaskSplit[1]
    EndSwitch

    Local $sInclude_File_Mask = ".+"
    ; Create Include mask for files
    If $sInclude_List <> "*" Then
        If Not __FLTAR_ListToMask($sInclude_File_Mask, $sInclude_List) Then Return SetError(1, 2, "")
    EndIf

    Local $sInclude_Folder_Mask = ".+"
    ; Set Include mask for folders
    Switch $iReturn
        Case 0
            ; Folders affected by mask if not recursive
            Switch $iRecur
                Case 0
                    ; Folders match mask for compatibility
                    $sInclude_Folder_Mask = $sInclude_File_Mask
            EndSwitch
        Case 2
            ; Folders affected by mask
            $sInclude_Folder_Mask = $sInclude_File_Mask
    EndSwitch

    Local $sExclude_File_Mask = ":"
    ; Create Exclude List mask for files
    If $sExclude_List <> "" Then
        If Not __FLTAR_ListToMask($sExclude_File_Mask, $sExclude_List) Then Return SetError(1, 3, "")
    EndIf

    Local $sExclude_Folder_Mask = ":"
    ; Create Exclude mask for folders
    If $iRecur Then
        If $sExclude_List_Folder Then
            If Not __FLTAR_ListToMask($sExclude_Folder_Mask, $sExclude_List_Folder) Then Return SetError(1, 4, "")
            _Log("exclude list folder " & $sExclude_List_Folder)
            _Log("exclude list mask " & $sExclude_Folder_Mask)
        EndIf
        ; If folders only
        If $iReturn = 2 Then
            ; Folders affected by normal mask
            $sExclude_Folder_Mask = $sExclude_File_Mask
        EndIf
    Else
        ; Folders affected by normal mask
        $sExclude_Folder_Mask = $sExclude_File_Mask
    EndIf

    ; Verify other parameters
    If Not ($iReturn = 0 Or $iReturn = 1 Or $iReturn = 2) Then Return SetError(1, 5, "")
    If Not ($iSort = 0 Or $iSort = 1 Or $iSort = 2) Then Return SetError(1, 7, "")
    If Not ($iReturnPath = 0 Or $iReturnPath = 1 Or $iReturnPath = 2) Then Return SetError(1, 8, "")

    ; Prepare for DllCall if required
    If $iHide_Link Then
        Local $tFile_Data = DllStructCreate("struct;align 4;dword FileAttributes;uint64 CreationTime;uint64 LastAccessTime;uint64 LastWriteTime;" & _
                "dword FileSizeHigh;dword FileSizeLow;dword Reserved0;dword Reserved1;wchar FileName[260];wchar AlternateFileName[14];endstruct")
        Local $hDLL = DllOpen('kernel32.dll'), $aDLL_Ret
    EndIf

    Local $asReturnList[100] = [0]
    Local $asFileMatchList = $asReturnList, $asRootFileMatchList = $asReturnList, $asFolderMatchList = $asReturnList
    Local $bFolder = False, _
            $hSearch = 0, _
            $sCurrentPath = "", $sName = "", $sRetPath = ""
    Local $iAttribs = 0, _
            $sAttribs = ''
    Local $asFolderFileSectionList[100][2] = [[0, 0]]
    ; Search within listed folders
    While $asFolderSearchList[0] > 0
        _Log("While no folders")
        Sleep(100)
        ; Set path to search
        $sCurrentPath = $asFolderSearchList[$asFolderSearchList[0]]
        ; Reduce folder search list count
        $asFolderSearchList[0] -= 1
        ; Determine return path to add to file/folder name
        Switch $iReturnPath
            ; Case 0 ; Name only
            ; Leave as ""
            Case 1 ;Relative to initial path
                $sRetPath = StringReplace($sCurrentPath, $sFilePath, "")
            Case 2 ; Full path
                If $bLongPath Then
                    $sRetPath = StringTrimLeft($sCurrentPath, 4)
                Else
                    $sRetPath = $sCurrentPath
                EndIf
        EndSwitch

        ; Get search handle - use code matched to required listing
        If $iHide_Link Then
            ; Use DLL code
            $aDLL_Ret = DllCall($hDLL, 'handle', 'FindFirstFileW', 'wstr', $sCurrentPath & "*", 'struct*', $tFile_Data)
            If @error Or Not $aDLL_Ret[0] Then
                ContinueLoop
            EndIf
            $hSearch = $aDLL_Ret[0]
        Else
            ; Use native code
            $hSearch = FileFindFirstFile($sCurrentPath & "*")
            ; If folder empty move to next in list
            If $hSearch = -1 Then
                ContinueLoop
            EndIf
        EndIf

        ; If sorting files and folders with paths then store folder name and position of associated files in list
        If $iReturn = 0 And $iSort And $iReturnPath Then
            __FLTAR_AddToList($asFolderFileSectionList, $sRetPath, $asFileMatchList[0] + 1)
        EndIf
        $sAttribs = ''

        ; Search folder - use code matched to required listing
        While 1
            _Log("While 1 start")
            Sleep(100)
            ; Use DLL code
            If $iHide_Link Then
                _Log("DLL call")
                Sleep(100)
                ; Use DLL code
                $aDLL_Ret = DllCall($hDLL, 'int', 'FindNextFileW', 'handle', $hSearch, 'struct*', $tFile_Data)
                ; Check for end of folder
                If @error Or Not $aDLL_Ret[0] Then
                    ExitLoop
                EndIf
                ; Extract data
                $sName = DllStructGetData($tFile_Data, "FileName")
                ; Check for .. return - only returned by the DllCall
                If $sName = ".." Then
                    ContinueLoop
                EndIf
                $iAttribs = DllStructGetData($tFile_Data, "FileAttributes")
                ; Check for hidden/system attributes and skip if found
                If $iHide_HS And BitAND($iAttribs, $iHide_HS) Then
                    ContinueLoop
                EndIf
                ; Check for link attribute and skip if found
                If BitAND($iAttribs, $iHide_Link) Then
                    ContinueLoop
                EndIf
                ; Set subfolder flag
                $bFolder = False
                If BitAND($iAttribs, 16) Then
                    $bFolder = True
                EndIf
            Else
                _Log("No DLL call")
                Sleep(100)
                ; Reset folder flag
                $bFolder = False
                ; Use native code
                $sName = FileFindNextFile($hSearch, 1)
                ; Check for end of folder
                If @error Then
                    _Log("error find next file")
                    Sleep(100)
                    ExitLoop
                EndIf
                ;- ADDED CODE
                ;- ADDED CODE
                ;- ADDED CODE
                If $sName = ".." Then
                    ContinueLoop
                EndIf
                If $sName = "." Then
                    ContinueLoop
                EndIf
                ;- ADDED CODE
                ;- ADDED CODE
                ;- ADDED CODE
                $sAttribs = @extended
                ; Check for folder
                If StringInStr($sAttribs, "D") Then
                    _Log("folder " & $sName)
                    Sleep(100)
                    $bFolder = True
                EndIf
                ; Check for Hidden/System
                If StringRegExp($sAttribs, "[" & $sHide_HS & "]") Then
                    _Log("hidden/system")
                    Sleep(100)
                    ContinueLoop
                EndIf
            EndIf

            ; If folder then check whether to add to search list
            If $bFolder Then
                Select
                    Case $iRecur < 0 ; Check recur depth
                        _Log("recur < 0")
                        StringReplace($sCurrentPath, "\", "", 0, $STR_NOCASESENSEBASIC)
                        If @extended < $iMaxLevel Then
                            _Log("max level ")
                            ContinueCase ; Check if matched to masks
                        EndIf
                    Case $iRecur = 1 ; Full recur
                        _Log("recur = 1")
                        If Not StringRegExp($sName, $sExclude_Folder_Mask) Then ; Add folder unless excluded
                            _Log("aded folder " & $sName & " to list ")
                            __FLTAR_AddToList($asFolderSearchList, $sCurrentPath & $sName & "\")
                        EndIf
                        ; Case $iRecur = 0 ; Never add
                        ; Do nothing
                EndSelect
            EndIf

            If $iSort Then ; Save in relevant folders for later sorting
                If $bFolder Then
                    If StringRegExp($sName, $sInclude_Folder_Mask) And Not StringRegExp($sName, $sExclude_Folder_Mask) Then
                        __FLTAR_AddToList($asFolderMatchList, $sRetPath & $sName & $sFolderSlash)
                    EndIf
                Else
                    If StringRegExp($sName, $sInclude_File_Mask) And Not StringRegExp($sName, $sExclude_File_Mask) Then
                        ; Select required list for files
                        If $sCurrentPath = $sFilePath Then
                            __FLTAR_AddToList($asRootFileMatchList, $sRetPath & $sName)
                        Else
                            __FLTAR_AddToList($asFileMatchList, $sRetPath & $sName)
                        EndIf
                    EndIf
                EndIf
            Else ; Save directly in return list
                If $bFolder Then
                    If $iReturn <> 1 And StringRegExp($sName, $sInclude_Folder_Mask) And Not StringRegExp($sName, $sExclude_Folder_Mask) Then
                        __FLTAR_AddToList($asReturnList, $sRetPath & $sName & $sFolderSlash)
                    EndIf
                Else
                    _Log("Checking file add to list")
                    If $iReturn <> 2 And StringRegExp($sName, $sInclude_File_Mask) And Not StringRegExp($sName, $sExclude_File_Mask) Then
                        _Log("added file " & $sName & " to list ")
                        __FLTAR_AddToList($asReturnList, $sRetPath & $sName)
                    EndIf
                EndIf
            EndIf

        WEnd

        ; Close current search
        If $iHide_Link Then
            DllCall($hDLL, 'int', 'FindClose', 'ptr', $hSearch)
        Else
            FileClose($hSearch)
        EndIf

    WEnd

    ; Close the DLL if needed
    If $iHide_Link Then
        DllClose($hDLL)
    EndIf

    ; Sort results if required
    If $iSort Then
        Switch $iReturn
            Case 2 ; Folders only
                ; Check if any folders found
                If $asFolderMatchList[0] = 0 Then Return SetError(1, 9, "")
                ; Correctly size folder match list
                ReDim $asFolderMatchList[$asFolderMatchList[0] + 1]
                ; Copy size folder match array
                $asReturnList = $asFolderMatchList
                ; Simple sort list
                __ArrayDualPivotSort($asReturnList, 1, $asReturnList[0])
            Case 1 ; Files only
                ; Check if any files found
                If $asRootFileMatchList[0] = 0 And $asFileMatchList[0] = 0 Then Return SetError(1, 9, "")
                If $iReturnPath = 0 Then ; names only so simple sort suffices
                    ; Combine file match lists
                    __FLTAR_AddFileLists($asReturnList, $asRootFileMatchList, $asFileMatchList)
                    ; Simple sort combined file list
                    __ArrayDualPivotSort($asReturnList, 1, $asReturnList[0])
                Else
                    ; Combine sorted file match lists
                    __FLTAR_AddFileLists($asReturnList, $asRootFileMatchList, $asFileMatchList, 1)
                EndIf
            Case 0 ; Both files and folders
                ; Check if any root files or folders found
                If $asRootFileMatchList[0] = 0 And $asFolderMatchList[0] = 0 Then Return SetError(1, 9, "")
                If $iReturnPath = 0 Then ; names only so simple sort suffices
                    ; Combine file match lists
                    __FLTAR_AddFileLists($asReturnList, $asRootFileMatchList, $asFileMatchList)
                    ; Set correct count for folder add
                    $asReturnList[0] += $asFolderMatchList[0]
                    ; Resize and add file match array
                    ReDim $asFolderMatchList[$asFolderMatchList[0] + 1]
                    _ArrayConcatenate($asReturnList, $asFolderMatchList, 1)
                    ; Simple sort final list
                    __ArrayDualPivotSort($asReturnList, 1, $asReturnList[0])
                Else
                    ; Size return list
                    Local $asReturnList[$asFileMatchList[0] + $asRootFileMatchList[0] + $asFolderMatchList[0] + 1]
                    $asReturnList[0] = $asFileMatchList[0] + $asRootFileMatchList[0] + $asFolderMatchList[0]
                    ; Sort root file list
                    __ArrayDualPivotSort($asRootFileMatchList, 1, $asRootFileMatchList[0])
                    ; Add the sorted root files at the top
                    For $i = 1 To $asRootFileMatchList[0]
                        $asReturnList[$i] = $asRootFileMatchList[$i]
                    Next
                    ; Set next insertion index
                    Local $iNextInsertionIndex = $asRootFileMatchList[0] + 1
                    ; Sort folder list
                    __ArrayDualPivotSort($asFolderMatchList, 1, $asFolderMatchList[0])
                    Local $sFolderToFind = ""
                    ; Work through folder list
                    For $i = 1 To $asFolderMatchList[0]
                        ; Add folder to return list
                        $asReturnList[$iNextInsertionIndex] = $asFolderMatchList[$i]
                        $iNextInsertionIndex += 1
                        ; Format folder name for search
                        If $sFolderSlash Then
                            $sFolderToFind = $asFolderMatchList[$i]
                        Else
                            $sFolderToFind = $asFolderMatchList[$i] & "\"
                        EndIf
                        Local $iFileSectionEndIndex = 0, $iFileSectionStartIndex = 0
                        ; Find folder in FolderFileSectionList
                        For $j = 1 To $asFolderFileSectionList[0][0]
                            ; If found then deal with files
                            If $sFolderToFind = $asFolderFileSectionList[$j][0] Then
                                ; Set file list indexes
                                $iFileSectionStartIndex = $asFolderFileSectionList[$j][1]
                                If $j = $asFolderFileSectionList[0][0] Then
                                    $iFileSectionEndIndex = $asFileMatchList[0]
                                Else
                                    $iFileSectionEndIndex = $asFolderFileSectionList[$j + 1][1] - 1
                                EndIf
                                ; Sort files if required
                                If $iSort = 1 Then
                                    __ArrayDualPivotSort($asFileMatchList, $iFileSectionStartIndex, $iFileSectionEndIndex)
                                EndIf
                                ; Add files to return list
                                For $k = $iFileSectionStartIndex To $iFileSectionEndIndex
                                    $asReturnList[$iNextInsertionIndex] = $asFileMatchList[$k]
                                    $iNextInsertionIndex += 1
                                Next
                                ExitLoop
                            EndIf
                        Next
                    Next
                EndIf
        EndSwitch
    Else ; No sort
        ; Check if any file/folders have been added
        If $asReturnList[0] = 0 Then Return SetError(1, 9, "")
        ; Remove any unused return list elements from last ReDim
        ReDim $asReturnList[$asReturnList[0] + 1]

    EndIf

    Return $asReturnList
EndFunc   ;==>_FileListToArrayRec

 

Link to comment
Share on other sites

  • Moderators

DStark,

We have run into problems with the UDF returning "." and ".." before and we thought we had fixed it - obviously not!

I will take a look at the code (and your suggested fixes) to see if we can put this to bed for once and for all. Thanks for letting us know about the problem.

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Hi Melba,

Thanks for the reply!  FYI you may enjoy seeing this - during testing I tried to put "." for the folder exclude filter and it gives me this... Note there is only  P:\test\sync\-test.txt.  This is probably a different issue worth investigating while you're at it 🤣
image.thumb.png.77b61108874571aa612d5a1fd2df6891.png

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