Editor's note:  
COTD Entry:  File Enumeration by Andrew Grant [AndrewGrant@hothouse.org]

#include <windows.h>
#include <stdio.h>


// Function name	: EnumerateFiles
// Description	    : Takes an initial directory and calls the provided function pointers for each file or directory
//						which it contains and which matches the specified wildcard search. Replace dirCallback or 
//						fileCallback with NULL to ignore these types. To enumerate all files and directories use *.*
//
//
// Argument         : const char *pDirectory			- directory to begin searching. do NOT specify a trailing slash!
// Argument         : const char* pWildCard			- wildcard to specify files, e.g *.txt. use *.* for all fiels/directories
// Argument         : bool recurse					- check sub folders?
// Argument         : void(*fileCallback)			- callback for each directory which matches the wildcard
// Argument         : void* pFileParam				- param to be provided to the directory callback functon
// Argument         : void(*dirCallback)			- callback for each directory which matches the wildcard
// Argument         : void* pDirParam				- param to be provided to the directory callback functon
void EnumerateFiles(const char *pDirectory, const char* pWildCard, bool recurse,
       void(*fileCallback)(const char *pFilename, const char *pFilePath, void* pFileParam), void* pFileParam,
	   void(*dirCallback)(const char *pDirname, const char *pDirPath, void* pDirParam), void* pDirParam)
{

	WIN32_FIND_DATA finddata;
	HANDLE handle;
	char searchPath[256];


	// first search for files matching the wildcard value
	sprintf(searchPath, "%s\\%s", pDirectory, pWildCard);

	handle = FindFirstFile(searchPath, &finddata);

	if (handle != INVALID_HANDLE_VALUE)
	{
		// check all files and directories
		do
		{
			if (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
			{
				// ignore directories with "." and ".."
				if (strcmp(finddata.cFileName, ".") 
						&& strcmp(finddata.cFileName, ".."))
				{
					if (dirCallback)
					{
						dirCallback(finddata.cFileName, pDirectory, pDirParam);
					}
				}
			}
			else
			{
				if (fileCallback)
				{
					fileCallback(finddata.cFileName, pDirectory, pFileParam);
				}
			}

		} while (FindNextFile(handle, &finddata));

		FindClose(handle);
	}


	// now repeat for all directories if the recurse flag was specified
	if (recurse)
	{
		sprintf(searchPath, "%s\\*.*", pDirectory);

		handle = FindFirstFile(searchPath, &finddata);

		if (INVALID_HANDLE_VALUE == handle) return;

		do
		{
			// only interested in proper directories...
			if (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
			{
				if (strcmp(finddata.cFileName, ".") && strcmp(finddata.cFileName, ".."))
				{
					// call ourself on this dir
					sprintf(searchPath, "%s\\%s", pDirectory, finddata.cFileName);

					EnumerateFiles(searchPath, pWildCard, true, fileCallback, pFileParam, dirCallback, pDirParam);
				}
			}

		} while (FindNextFile(handle, &finddata));

		FindClose(handle);
	}

	return;
}