MurderFish612
MurderFish612

Reputation: 65

C++ folder wont delete until I close program

In a game I'm making, folders with text files inside represent world saves, In the load menu of this game I want to have an option to delete a save. I'm using currently this code to try to delete the saves:

hFind = FindFirstFile((dir+"/*").c_str(), &FindFileData);
if (hFind){
    do{
        string s = FindFileData.cFileName;
        if(s.find('.')){//prevents prossesing of "." and ".."
            DeleteFile((dir+"/"+s).c_str());
        }
    }while(FindNextFile(hFind,&FindFileData));
    CloseHandle(hFind);
}
rmdir(dir.c_str());

The only things in these folders are 3 text files so this code should be sufficient, however it isn't. What happens is all the file in the directory are deleted but not the folder, and if I try to delete this folder manually, or edit it in any way while the program is running, windows denies me access. But as soon as I close the game the folder is deleted.

I know the files inside are deleted because I tried the above code with out "rmdir(dir.c_str());" and opened the folder and all the files were gone, also with the above code if I "Delete" the save and then try to load it I there is no world and no inventory, indicating the files have been deleted.

I've tried it with removeDirectory and the same thing happens, It also says it was deleted successfully without any errors.

Why does this happen? How can I avoid this, and get it to work properly?

Any help would be greatly appreciated.


The problem was fixxed with the following code:

hFind = FindFirstFile((dir+"/*").c_str(), &FindFileData);
if (hFind){
    do{
        string s = FindFileData.cFileName;
        if(s.find('.')){//prevents prossesing of "." and ".."
            DeleteFile((dir+"/"+s).c_str());
        }
    }while(FindNextFile(hFind,&FindFileData));
    CloseHandle(hFind);
}
findClose(hFind);
rmdir(dir.c_str());

Upvotes: 3

Views: 1947

Answers (2)

Adrian McCarthy
Adrian McCarthy

Reputation: 47954

The root problem is that the code called CloseHandle instead of FindClose on the handle returned by FindFirstFile.

But the code has several more bugs. In the interest of helping future visitors here, this is the corrected code.

HANDLE hFind = FindFirstFile((dir + "\\*").c_str(), &FindFileData);  // See 1 below
if (hFind != INVALID_HANDLE_VALUE) {  // 2
    do {
        if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {  // 3
            const std::string s = dir + "\\" + FindFileData.cFileName;
            DeleteFile(s.c_str());
        }
    } while (FindNextFile(hFind, &FindFileData));
    // 4
    FindClose(hFind);  // 5
}
RemoveDirectory(dir.c_str());  // 6
  1. Windows paths use \ rather than / as separators. Many of the APIs will accept either, but eventually you'll encounter one that doesn't, so it's best to use the correct one consistently.

  2. FindFirstFile returns INVALID_HANDLE_VALUE (not NULL) upon failure. Since INVALID_HANDLE_VALUE is non-zero, you cannot simply test if (hFile) { ... }.

  3. The API enumerates files and directories. The old code was trying to filter out the . and .. directories incorrectly, which could have caused it to skip some files and to attempt to use DeleteFile on other directories. It's simpler (and easier-to-understand) to skip all directories.

  4. Don't call CloseHandle on the handle returned by FindFirstFile.

  5. Do call FindClose on the handle returned by FindFirstFile, but do so only in the case you got a valid handle from FindFirstFile.

  6. As long as you're using Windows-specific APIs, you may as well use them consistently and not mix with library wrappers like rmdir. The library wrappers sometimes introduce surprising limitations or behavior, though I think rmdir would work correctly in this instance.

This still leaves a significant problem: It doesn't handle Unicode in the paths (and it requires you to compile for ANSI which limits Unicode handling in other parts of the project).

Upvotes: 1

harmic
harmic

Reputation: 30577

According to the RemoveDirectory documentation:

RemoveDirectory function marks a directory for deletion on close. Therefore, the directory is not removed until the last handle to the directory is closed.

Probably your program has the directory as its current working directory, or perhaps otherwise still has a handle to it open.

In windows, rmdir is a comparability function that calls the native windows functions, so it will behave the same.

Upvotes: 4

Related Questions