Read contents of directory

Strangely it seems to be crashing at this line:

dim t as Int32


Fixed that by putting dim at top.

Now it crashes (sometimes) at the files.append(path + Result.WString(44))

I tried changing to:

        temp = path + Result.WString(44)

But it’s crashing at the append.

It’s always crashing when appending the last file from the subfolder. Hmm… strange.

Do you know that Xojo have a debugger ?

Yeah but occasionally (while using the Xojo debugger) the app will crash without throwing any exceptions (’…exe’ has stopped working’). If VS is install you have the option to debug the compiled app in VS. Usually not much information of value is available there, but you can see the stack and often the name of the dll where the exception occurred. Pretty low level stuff. Ugh

Notice I’m using counters and label.refresh so I can monitor where in the code the crash is occurring.

You are increasing the size limit of MAX_PATH by prepending “\\?” so your memory block isn’t big enough.

Change the MemoryBlock(328) to MemoryBlock(100000) as a hack, you will need to figure out this size though (I’ve not read much into it)

PS. I dont know why you are using the / instead of \ and you dont need to escape \ so I see no need for \\

Also, change Return files to Return files() at the bottom of GetFiles just to be sure.

Works here 100% now with that MemoryBlock correction.

Thank you very much that fixed the issue. Learning is painful.

No problemo.

Oh there you go…

MAX_PATH is 32,767 if using “\\?” I’ll let you do the math with the rest of the struct :slight_smile:

Thanks to everyone. This is about 4 times faster than the VB Net method GetFiles(path)

Here is the working code:

dim files() as string = GetFiles("C:\\Users\\Server Computer\\OneDrive\\Job Proposals")

Function GetFiles(Path As String) As String()
  dim files(), Dir() as String
  if path.Right(1) <> "\" Then Path = path + "\"
  Declare Function FindFirstFile Lib "Kernel32" Alias "FindFirstFileW" (FileName As WString, FindData As Ptr) As Integer
  Declare Function FindNextFile Lib "Kernel32" Alias "FindNextFileW" (FindHandle As Integer, FindData As Ptr) As Boolean
  Declare Function FindClose Lib "Kernel32" (FindHandle As Integer) As Boolean
  Dim Result As New MemoryBlock(40000)  //A WIN32_FIND_DATA structure
  Dim FindHandle As Integer = FindFirstFile("\\\\?\" + path + "*" + Chr(0), Result)
  'walk through folder and get list of directories and files
  If FindHandle > 0 Then
      if result.int32value(0) = 16 Then
        'if this is a directory then resurse through the directory to get all files
        if Result.WString(44) <> ".." and Result.WString(44) <> "." Then
          dim d() as String
          d = GetFiles(path  + Result.WString(44) + "\")
          if d.Ubound > -1 Then
            for j as integer = 0 to d.Ubound
              Files.Append d(j)
          end if
        end if
        files.Append(path + Result.WString(44))
      end if
    Loop Until Not FindNextFile(FindHandle, Result)
    Call FindClose(FindHandle)
  End If
  Return files()
End Function

Use 10000 if you want some future random crash / memory corruption :slight_smile:

I’d personally go with 40000 just to be safe if you dont want to work out the struct size yourself :slight_smile:

32,767 is an approximation as it can be expanded at runtime.

That whole section seems a little vague.

And put the \\?\ the right way round :wink: you’re triggering my ocd :wink: its only working because luckily one of those calls changes / to \

Thanks for the explanations. I never would have figured it out on my own. I edited the code in my last post.

:slight_smile: Nice to see it working.

Oh, shameless self promotion :wink: if you play around with Declares in the future


Glad to see you could get it working.

A few comments:

if d.Ubound > -1 Then

That code is unnecessary because the for loop would go from 0 to -1, which means it won’t run anyway.

And this:

Return files()

That’s syntactical nonsense. That’s almost like writing:

if valueHasBeenSet = true then

instead of:

if valueHasBeenSet then

An even sillier version of that would be:

if not ((valueHasBeenSet = true) = false) and true and not false then

So, you may write “files()” but it has no different effect than “files”.

I need much the same thing…but specifically for Mac OS – so Windows Declares won 't cut it :slight_smile: – I would just recurse through folder items…but I will be collecting way over a million file paths…so I was looking for a speedy route. I do have Christian’s MBS Plugin…and I briefly looked at that before I slept on the problem. Then I thought…hey…how about I just shell out and run something like “ls -d -1 $PWD/**/*” and collect the result (probably in a file I could open and read through PDQ…but perhaps it could all be done in memory).

I’m surprised no one ran into this before…if the file attributes returned include a set bit other than the Directory bit, the directory test fails and it won’t go down that directory. The test needs to change to look at just the Directory bit, like this:

If FindHandle > 0 Then Do if (result.int32value(0) And 16) = 16 Then 'if this is a directory then resurse through the directory to get all files

I ran into the issue when I tried this on a OneDrive directory. The FILE_ATTRIBUTE_REPARSE_POINT bit was set as well.

That is super cool, thanks Neil , Is there a way to have same thing for Mac as well, no idea why but folder item seems super slow and with each XOJO release the customers complain that the app is more and more slow so I guess I’ll have to look on other optimizations on this part .

Thanks again.

For other reasons, I fill an array with FolderItems (a directory contents), then I use that array to load small images and apply to cloned Canvas in a Window.

Works nicely (vs skip some Canvas Clone without image) and fast (but tested on only < 20 images).

As I was looking for getting all filenames from a directory I stumbled over this forum chat. I was wondering why so much code is needed for such a “simple” task. I then found this in documentation. The key is to iterate through the children:

Var desktopFolder As FolderItem = SpecialFolder.Desktop For Each file As Folderitem In DesktopFolder.Children If file <> Nil Then ListBox1.AddRow(file.Name) End If Next

This sample can easily adapted for someones needs.

The issue wasn’t how to iterate through the children, it was how to do it quickly. Folderitem methods are notoriously slow. Also the Children function did not exist at the time of the discussion. I do not know how it performs in comparison.

Agree and can imagine it didn’t exist at that time. The point is I was googling several times and always landed here. So I thought that any other person may have the same problem may find a solution here.

1 Like