|
-
Mar 4th, 2025, 06:39 PM
#1
Thread Starter
Lively Member
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
-
Mar 4th, 2025, 08:01 PM
#2
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.
-
Mar 4th, 2025, 09:02 PM
#3
Thread Starter
Lively Member
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.
-
Mar 5th, 2025, 04:23 AM
#4
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)
-
Mar 5th, 2025, 08:16 AM
#5
Thread Starter
Lively Member
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.
-
Mar 5th, 2025, 08:47 AM
#6
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.
-
Mar 5th, 2025, 10:50 AM
#7
Lively Member
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
-
Mar 5th, 2025, 05:06 PM
#8
Thread Starter
Lively Member
Re: How to avoid infinite recursion when recursively expanding folders with shotcuts?
 Originally Posted by Elroy
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.
-
Mar 5th, 2025, 05:21 PM
#9
Thread Starter
Lively Member
Re: How to avoid infinite recursion when recursively expanding folders with shotcuts?
 Originally Posted by anycoder
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.
-
Mar 5th, 2025, 05:22 PM
#10
Hyperactive Member
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.
-
Mar 5th, 2025, 06:34 PM
#11
Thread Starter
Lively Member
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|