win32 API question: listing files in subdirectories

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?

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

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.



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.

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

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

And last before I go to bed, the error returned is ERROR_PATH_NOT_FOUND.

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:


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

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

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,



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


is the same thing as:



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


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



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


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.