Results 1 to 11 of 11

Thread: How to avoid infinite recursion when recursively expanding folders with shotcuts?

  1. #1

    Thread Starter
    Lively Member
    Join Date
    Sep 2022
    Location
    Uruguay
    Posts
    70

    How to avoid infinite recursion when recursively expanding folders with shotcuts?

    I know this is an unlikely problem and not specific to VB6.

    I wrote a procedure to list all the files and folders and their subfolders and so on. I also dereference the shorcuts and list their contents. Some shortcuts point to folders, which in turns can contain shortcuts, perhaps also containing shortcuts and so on that are expanded in the listing.

    If I create a shortcut to a folder and move it into a subfolder of the referenced folder or anywhere down in its path tree, then my procedure never ends.

    Is there an efficient, elegant way to get out of such a recursive loop?

    Here's my code (in case my explanation wasn't clear enough):
    Code:
    Public Sub ExpandDirW(Fil() As String, LastFld As Long)
        'Doesn't return "." and ".." folders. Unicode aware
        'Fil(LastFld) must be a folder and end with a slash
        Dim fd As WIN32_FIND_DATA
        Dim lpStr As Long
        Dim hFind As Long
        Dim FileName As String 'sin path
        Dim LastFil As Long
        Dim ExtMask As String
        Dim Ext As String
        Dim FileType As VbFileAttributeExtended
        
        ExtMask = Replace(";" & PluginExt, ";*", "|") & "|"
        LastFil = LastFld
        hFind = FindFirstFile(StrPtr(Fil(LastFil) & "*.*"), fd)
        If hFind = INVALID_HANDLE_VALUE Then Exit Sub
        Do
            lpStr = VarPtr(fd.lpszFileName(0))
            FileName = String$(lstrlen(lpStr), 0&)
            lstrcpy StrPtr(FileName), lpStr
            FileType = 0
            If fd.dwFileAttributes And vbDirectory Then
                If FileName <> "." And FileName <> ".." Then
                    FileType = vbDirectory
                    FileName = Fil(LastFld) & FileName & "\"
                Else
                    FileName = ""
                End If
            Else
                Ext = LCase(Mid(FileName, InStrRev(FileName, ".")))
                If Ext = ".lnk" Then
                    FileName = DereferenceShortcut(Fil(LastFld) & FileName)
                    If IsFolder(FileName) Then
                        FileType = vbDirectory
                        FileName = FileName & "\"
    '                    Debug.Print FileName
                    End If
                ElseIf InStr(1, ExtMask, "|" & Ext & "|") <> 0 Then
                    FileName = Fil(LastFld) & FileName
                Else
                    FileName = ""
                End If
            End If
            If FileName <> "" Then
                LastFil = LastFil + 1
                If UBound(Fil) < LastFil Then ReDim Preserve Fil(LastFil + 100)
                Fil(LastFil) = FileName
                If FileType = vbDirectory Then ExpandDirW Fil(), LastFil
            End If
        Loop While FindNextFile(hFind, fd)
        If hFind Then FindClose hFind
        LastFld = LastFil
    End Sub

    And here's an example of the file tree triggering the recursive loop:
    Code:
    D:\Audio\eMule>dir /s /b
    D:\Audio\eMule\Incoming
    D:\Audio\eMule\Temp
    D:\Audio\eMule\Incoming\A midsummer night's dream, Op. 61 [Previn] - Felix Mendelssohn - Acceso directo.lnk
    D:\Audio\eMule\Incoming\Incoming - Acceso directo.lnk
    D:\Audio\eMule\Incoming\shrink

  2. #2
    PowerPoster
    Join Date
    Nov 2017
    Posts
    3,630

    Re: How to avoid infinite recursion when recursively expanding folders with shotcuts?

    Expanding lnk files to folders is the root of the problem, but obviously you already know that.

    I can't think of a great fix, but one option would be to add a boolean parameter to your ExpandDirW function that determines if lnk expansion happens or not. And when an lnk triggers a new call to ExpandDirW, pass false so that lnk files found in that first lnk expansion don't also get expanded.

  3. #3

    Thread Starter
    Lively Member
    Join Date
    Sep 2022
    Location
    Uruguay
    Posts
    70

    Re: How to avoid infinite recursion when recursively expanding folders with shotcuts?

    Thanks! I'll explore that option.

    It seems to me that your option may ruin some of the behaviors I want. For instance, I may want to place more than one shortcut to the same destination in a single folder so to achieve repetitions in the listing. This is just a silly example; I have more indirect references in use nowadays.

    For now I'm experimenting with detecting if the target of the lnk is also upstream in the tree hyerarchy, which is mostly similar to the workaround you suggest. Something like this:

    Code:
    If InStr(Fil(LastFld), FileName) Then FileName = ""
    inserted before the commented "Debug.Print FileName" in my code.

    I don't have a clear insight of what can happen if the referencing is more indirect (like many jumps). I suspect my approach may fail.

  4. #4
    Frenzied Member 2kaud's Avatar
    Join Date
    May 2014
    Location
    England
    Posts
    1,169

    Re: How to avoid infinite recursion when recursively expanding folders with shotcuts?

    Not that efficient, but you could maintain a list of already examined folders and don't try to expand an already visited folder.
    All advice is offered in good faith only. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  5. #5

    Thread Starter
    Lively Member
    Join Date
    Sep 2022
    Location
    Uruguay
    Posts
    70

    Re: How to avoid infinite recursion when recursively expanding folders with shotcuts?

    That would invalidate one of my goals: to allow for repetitions. I'll settle for not expanding only when it leads to infinite recursion (and I'd warn the users when this happens so they can move/modify the affected shortcuts).

    The file list is to be used as a playlist, with some of the items being sub-playlists (shortcuts to folders, *.m3u files, *.bat files, etc.). This allows the users to create playlists as file system items. Each sub-playlist can be reused (repeated) as many times as needed and as items in any nested sub-playlist (even inside itself, but this leads to the endless recursion I'd like to avoid).

    My algorhitm works in all the cases I tested it so far but I can't guaranty that it will work in all the possible cases since I lack a general mathematical demonstration. I hoped for a proved standard way to deal with this would already exist, and that smeone here could explain it to me.

  6. #6
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    10,909

    Re: How to avoid infinite recursion when recursively expanding folders with shotcuts?

    Just as a general solution to any procedure that might have infinite recursion, I'd tend to create a static Long inside the procedure, increment every time we came into the procedure, decrement every time we left the procedure, and then, upon initial entry into the procedure check if for some reasonable value. If it was larger than that value, report some kind of overflow error and get out.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  7. #7
    Lively Member anycoder's Avatar
    Join Date
    Jan 2025
    Posts
    67

    Re: How to avoid infinite recursion when recursively expanding folders with shotcuts?

    Try with the non-recursive approach this allows you to put all paths into " to scan" collection that rejects any duplication.

    Code:
      Private Declare Function FindClose Lib "kernel32" (ByVal hFindFile As Long) As Long
    Private Declare Function FindFirstFileW Lib "kernel32" (ByVal lpFileName As Long, ByVal lpFindFileData As Long) As Long
    Private Declare Function FindNextFileW Lib "kernel32" (ByVal hFindFile As Long, ByVal lpFindFileData As Long) As Long
     
    Private Const FILE_ATTRIBUTE_DIRECTORY = &H10
     
    Private Type FILETIME
      dwLowDateTime  As Long
      dwHighDateTime As Long
    End Type
    
    Const MAX_PATH  As Long = 260
    Const ALTERNATE As Long = 14
     
     
    Private Type WIN32_FIND_DATA
      dwFileAttributes As Long
      ftCreationTime   As FILETIME
      ftLastAccessTime As FILETIME
      ftLastWriteTime  As FILETIME
      nFileSizeHigh    As Long
      nFileSizeLow     As Long
      dwReserved0      As Long
      dwReserved1      As Long
      cFileName        As String * MAX_PATH
      cAlternate       As String * ALTERNATE
    End Type
    Private Const INVALID_HANDLE_VALUE As Long = -1
    
    Sub FindFiles(ByVal aFileName As String)
    Dim hFile As Long, Cnt As Long
    Dim Dr As String, fName As String, nKey As String
    Dim wfd As WIN32_FIND_DATA
    Dim mPaths As New Collection
    Dr = Trim(aFileName)
    If Right(Dr, 1) <> "\" Then: Dr = Dr & "\"
    mPaths.Add Dr, UCase(Dr)
    While Cnt < mPaths.Count
      Cnt = Cnt + 1
      Dr = mPaths(Cnt)
      hFile = FindFirstFileW(StrPtr(Dr & "*.*"), VarPtr(wfd))
      If hFile <> INVALID_HANDLE_VALUE Then
         Do
           fName = Left$(wfd.cFileName, InStr(wfd.cFileName, vbNullChar) - 1)
           If (wfd.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY) = 0 Then
            'if ext of fName  = ".lnk" Then
            '  nKey = Dr & fName & "\"
            '  If nKey is folder Then
            '    On Error Resume Next
            '    mPaths.Add nKey, UCase(nKey)
            '  end if
            'Else...
            ElseIf (fName <> ".") And (fName <> "..") Then
              nKey = Dr & fName & "\"
              On Error Resume Next
              mPaths.Add nKey, UCase(nKey)
            End If
         Loop While FindNextFileW(hFile, VarPtr(wfd))
         FindClose hFile
      End If
    Wend
    End Sub

  8. #8

    Thread Starter
    Lively Member
    Join Date
    Sep 2022
    Location
    Uruguay
    Posts
    70

    Re: How to avoid infinite recursion when recursively expanding folders with shotcuts?

    Quote Originally Posted by Elroy View Post
    Just as a general solution to any procedure that might have infinite recursion, I'd tend to create a static Long inside the procedure, increment every time we came into the procedure, decrement every time we left the procedure, and then, upon initial entry into the procedure check if for some reasonable value. If it was larger than that value, report some kind of overflow error and get out.
    Thanks !
    That's a fire-proof emergency break, for sure !
    I'm currently using that trick in a couple of non-recurrent procedures to avoid endless Do-Loops.
    I'll include that trick in my procedure as a final safety measure to avoid endless freezing, but if it ever triggers by then the resulting file list will be useless as a playlist.

  9. #9

    Thread Starter
    Lively Member
    Join Date
    Sep 2022
    Location
    Uruguay
    Posts
    70

    Re: How to avoid infinite recursion when recursively expanding folders with shotcuts?

    Quote Originally Posted by anycoder View Post
    Try with the non-recursive approach this allows you to put all paths into " to scan" collection that rejects any duplication.
    I have been using an almost identical code (just not "Dr" & etc. in my case) to build a list with no repetitions to feed to my pseudo-random playlist option (aditionally I kept the number of times each folder name was repeated), but this is not what I'm after now. I want to allow for intentional repetitions, as explained in my post #5. So this doesn't help at all. Thanks anyway for your concern.

  10. #10
    Hyperactive Member
    Join Date
    Jan 2018
    Posts
    340

    Re: How to avoid infinite recursion when recursively expanding folders with shotcuts?

    Besides your overall array of results, you want to pass down a separate parameter of the direct path of entries that led to your current location. If there is any repetition in this path then you have a loop. The results array doesn't really need to be a parameter at all.

    But I'd use Elroy's method as an overall sanity check as well.

  11. #11

    Thread Starter
    Lively Member
    Join Date
    Sep 2022
    Location
    Uruguay
    Posts
    70

    Re: How to avoid infinite recursion when recursively expanding folders with shotcuts?

    I think that's mostly what I proposed in my post #3 and I'm currently testing but I suspect I'm missing something to take into account multiple jump circular references.
    Detecting a loop solves most of the issue but I also want to avoid it before it happens. On a multiple jump circular reference loop multiple folders would have already been pushed into the file/folder list before the loop is detected. I guess it's possible to track them back and remove them but I didn't get to that part yet.

    This is just what I figured out so far, and it worries me to think that I may be misunderstanding the whole picture. I may eventually get around it with all the help provided here and also spending a little more time on it. So far I spent more time reading and answering this thread than I did on actually coding+debugging+testing my code.

    Edit:
    Sorry, I misunderstood the part of the direct path you suggest. That may make the difference !
    Last edited by jpfa; Mar 5th, 2025 at 06:39 PM.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width