Ben
Ben

Reputation: 1349

How can I obtain all of the file names in a directory?

I am writing a program in C++. I am trying to obtain all of the files in the folder where the program executable is located and store them in a vector. I have been told that the following code should work, but the FindFirstFile operation only finds one file (the name of the folder that it should be searching through). How can I change the code so that it looks through the folder properly?

std::vector<char*> fileArray;

//Get location of program executable
HMODULE hModule = GetModuleHandleW(NULL);
WCHAR path[MAX_PATH];
GetModuleFileNameW(hModule, path, MAX_PATH);

//Remove the executable file name from 'path' so that it refers to the folder instead
PathCchRemoveFileSpec(path, sizeof(path));

//This code should find the first file in the executable folder, but it fails
//Instead, it obtains the name of the folder that it is searching
WIN32_FIND_DATA ffd;
HANDLE hFind = INVALID_HANDLE_VALUE;
hFind = FindFirstFile(path, &ffd);

do
{
    //The name of the folder is pushed onto the array because of the previous code's mistake
    //e.g. If the folder is "C:\\MyFolder", it stores "MyFolder"
    fileArray.push_back(ffd.cFileName); //Disclaimer: This line of code won't add the file name properly (I'll get to fixing it later), but that's not relevant to the question
} while (FindNextFile(hFind, &ffd) != 0); //This line fails to find anymore files

Upvotes: 3

Views: 1558

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 595295

I have been told that the following code should work

You were told wrong, because the code you have presented is severely broken.

the FindFirstFile operation only finds one file (the name of the folder that it should be searching through).

You are passing just the folder path by itself to FindFirstFile(), so only one entry will be reported, describing the folder itself. What you need to do is append a * or *.* wildcard to the end of the path, then FindFirstFile()/FindNextFile() will enumerate the files and subfolders inside the folder.

Aside from that, there are several other problems with the code.

Even if the enumeration were working, you are not differentiating between files and subfolders.

You are passing a bad value to the second parameter of PathCchRemoveFileSpec(). You are passing in a byte count, but it expects a character count instead.

You are not checking FindFirstFile() for failure before entering your loop, and you are not calling FindClose() after the loop is finished.

And lastly, your code won't even compile as-is. Your vector is storing char* values, but in order to pass a WCHAR[] to FindFirstFile(), UNICODE has to be defined, which means FindFirstFile() will map to FindFirstFileW() and WIN32_FIND_DATA will map to WIN32_FIND_DATAW, and thus the cFileName field will be a WCHAR[]. The compiler will not allow a WCHAR[] (or WCHAR*) to be assigned to a char*.

Try something more like this instead:

std::vector<std::wstring> fileArray;

//Get location of program executable
WCHAR path[MAX_PATH+1] = {0};
GetModuleFileNameW(NULL, path, MAX_PATH);

//Remove the executable file name from 'path' so that it refers to the folder instead
PathCchRemoveFileSpec(path, MAX_PATH);

// append a wildcard to the path
PathCchAppend(path, MAX_PATH, L"*.*");

WIN32_FIND_DATAW ffd;
HANDLE hFind = FindFirstFileW(path, &ffd);
if (hFile != INVALID_HANDLE_VALUE)
{
    do
    {
        if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
            fileArray.push_back(ffd.cFileName);
    }
    while (FindNextFileW(hFind, &ffd));
    FindClose(hFind);
}

Upvotes: 4

Related Questions