# win32 API question: listing files in subdirectories

**URL:** <https://boards.straightdope.com/t/win32-api-question-listing-files-in-subdirectories/218520>\
**Category:** Factual Questions\
**Created:** [December 12, 2003, 4:17am UTC](https://boards.straightdope.com/t/win32-api-question-listing-files-in-subdirectories/218520 "2003-12-12T04:17:09Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![ultrafilter](https://avatars.discourse-cdn.com/v4/letter/u/3d9bf3/32.png) [@ultrafilter](https://boards.straightdope.com/u/ultrafilter)\
**Post date:** [December 12, 2003, 4:17am UTC](https://boards.straightdope.com/t/win32-api-question-listing-files-in-subdirectories/218520/1 "2003-12-12T04:17:09Z")

</div>

So for a little educational project, I’m trying to take the directory tree starting in a given directory and list all the files in it, which just happen to be found only in the bottom-level directories. Seems simple enough, but this is Windows, so it can’t be all that easy.

I’ve been trying to use FindFirstFile and FindNextFile, and was getting along rather well until I started finding directories with spaces in their long names. Those functions won’t find a directory with a space in its long name, and it doesn’t seem to work with the 8.3 name either.

I’m frustrated now, so I turn to the doper community. Is there an easy trick that I’m missing here?

---

<div class="post-metadata">

**Author:** ![Ms2001](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/ms2001/32/18463_2.png) [@Ms2001](https://boards.straightdope.com/u/Ms2001)\
**Post date:** [December 12, 2003, 5:05am UTC](https://boards.straightdope.com/t/win32-api-question-listing-files-in-subdirectories/218520/2 "2003-12-12T05:05:48Z")

</div>

Can you post the code that doesn’t work? Those API functions should work fine with names that contain spaces.

---

<div class="post-metadata">

**Author:** ![ultrafilter](https://avatars.discourse-cdn.com/v4/letter/u/3d9bf3/32.png) [@ultrafilter](https://boards.straightdope.com/u/ultrafilter)\
**Post date:** [December 12, 2003, 5:11am UTC](https://boards.straightdope.com/t/win32-api-question-listing-files-in-subdirectories/218520/3 "2003-12-12T05:11:12Z")

</div>

This is a pretty early version, and is a lot longer than it needs to be, so I’ll just post the particular function where the error occurs.

```auto

inline bool ProcessArtist(char* Artist)
{
	bool retVal = true;
	WIN32_FIND_DATA AlbumData;

	char ArtistTop[4096];
	strncpy(ArtistTop, Artist, strlen(Artist));
	ArtistTop[strlen(Artist)] = '\\';
	ArtistTop[strlen(Artist) + 1] = '*';
	ArtistTop[strlen(Artist) + 2] = 0;

	HANDLE File = FindFirstFile(ArtistTop, &AlbumData);
	if (File != INVALID_HANDLE_VALUE)
	{
		FindNextFile(File, &AlbumData);
		
		while (FindNextFile(File, &AlbumData) != 0)
		{
			printf("	Found %s
", AlbumData.cFileName);

			char Album[4096];
			strncpy(Album, TOP, gLength);
			Album[gLength - 1] = 0;
			strncat(Album, AlbumData.cFileName, strlen(AlbumData.cFileName));
			ProcessAlbum(Album);
		}
		if (GetLastError() != ERROR_NO_MORE_FILES)
		{
			// Something went wrong
			retVal = false;
		}

		FindClose(File);
	}

	return retVal;
}

```

When this is called, Artist is “D:\Media\Music\Ace Of Base\*”.

FYI, this is for processing an mp3 collection–eventually, I’m going to muck around with the tags and whatnot.

---

<div class="post-metadata">

**Author:** ![ultrafilter](https://avatars.discourse-cdn.com/v4/letter/u/3d9bf3/32.png) [@ultrafilter](https://boards.straightdope.com/u/ultrafilter)\
**Post date:** [December 12, 2003, 5:20am UTC](https://boards.straightdope.com/t/win32-api-question-listing-files-in-subdirectories/218520/4 "2003-12-12T05:20:13Z")

</div>

Well, it’s definitely not the space. Funny thing is, the code I use to get the folder name corresponding to the artist is identical except for a few names (told you this was an early version).

---

<div class="post-metadata">

**Author:** ![ultrafilter](https://avatars.discourse-cdn.com/v4/letter/u/3d9bf3/32.png) [@ultrafilter](https://boards.straightdope.com/u/ultrafilter)\
**Post date:** [December 12, 2003, 5:29am UTC](https://boards.straightdope.com/t/win32-api-question-listing-files-in-subdirectories/218520/5 "2003-12-12T05:29:16Z")

</div>

> [@](#):
>
> \*Originally posted by ultrafilter \*  
> \*\*When this is called, Artist is “D:\Media\Music\Ace Of Base\*”.  
> \*\*

Sorry, I forgot that the trailing \* is added in the function. The actual parameter is “D:\Media\Music\Ace Of Base”.

---

<div class="post-metadata">

**Author:** ![ultrafilter](https://avatars.discourse-cdn.com/v4/letter/u/3d9bf3/32.png) [@ultrafilter](https://boards.straightdope.com/u/ultrafilter)\
**Post date:** [December 12, 2003, 5:34am UTC](https://boards.straightdope.com/t/win32-api-question-listing-files-in-subdirectories/218520/6 "2003-12-12T05:34:56Z")

</div>

And last before I go to bed, the error returned is ERROR\_PATH\_NOT\_FOUND.

---

<div class="post-metadata">

**Author:** ![Ms2001](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/ms2001/32/18463_2.png) [@Ms2001](https://boards.straightdope.com/u/Ms2001)\
**Post date:** [December 12, 2003, 6:16am UTC](https://boards.straightdope.com/t/win32-api-question-listing-files-in-subdirectories/218520/7 "2003-12-12T06:16:13Z")

</div>

Well, the first thing I see is you’re calling FindNextFile immediately after FindFirstFile, skipping the first two files. (How many files are in the Ace of Base folder?)

Typically you’d use the functions like so:

```auto

if ((handle = FindFirstFile(path, &data)) != INVALID_HANDLE_VALUE) {
  do {
    // do something with data
  } while (FindNextFile(handle, &data) != 0);
  FindClose(handle);
}

```

---

<div class="post-metadata">

**Author:** ![ultrafilter](https://avatars.discourse-cdn.com/v4/letter/u/3d9bf3/32.png) [@ultrafilter](https://boards.straightdope.com/u/ultrafilter)\
**Post date:** [December 12, 2003, 4:55pm UTC](https://boards.straightdope.com/t/win32-api-question-listing-files-in-subdirectories/218520/8 "2003-12-12T16:55:07Z")

</div>

The first two files that show up are . and …, which are of no interest to me.

---

<div class="post-metadata">

**Author:** ![ForbiddenFruitsalad](https://avatars.discourse-cdn.com/v4/letter/f/ccd318/32.png) [@ForbiddenFruitsalad](https://boards.straightdope.com/u/ForbiddenFruitsalad)\
**Post date:** [December 12, 2003, 7:52pm UTC](https://boards.straightdope.com/t/win32-api-question-listing-files-in-subdirectories/218520/9 "2003-12-12T19:52:26Z")

</div>

You are NOT guaranteed that “.” and “…” are always the first names returned. The correct procedure is to go through all of them, testing for “.” and “…” explicitly.

By the way,

```auto

char ArtistTop[4096];
strncpy(ArtistTop,Artist,strlen(Artist));

```

is the same thing as:

```auto

char ArtistTop[4096];
strcpy(ArtistTop,Artist);

```

…except that you needlessly calculate the length of Artist. You meant

```auto

char ArtistTop[4096];
strncpy(ArtistTop,Artist,sizeof(ArtistTop));

```

---

<div class="post-metadata">

**Author:** ![ForbiddenFruitsalad](https://avatars.discourse-cdn.com/v4/letter/f/ccd318/32.png) [@ForbiddenFruitsalad](https://boards.straightdope.com/u/ForbiddenFruitsalad)\
**Post date:** [December 12, 2003, 8:04pm UTC](https://boards.straightdope.com/t/win32-api-question-listing-files-in-subdirectories/218520/10 "2003-12-12T20:04:05Z")

</div>

I just realized my mistake about that strncpy code :smack:

They’re not exactly the same, because my strcpy statement will copy the final NULL character. Still, it’s always a good idea to take the destination buffer size into account.
