RemoveDirectory() function in win32 api doesn't remove parent directory after removing subdirectories [duplicate]

StackOverflow https://stackoverflow.com/questions/21865085

  •  13-10-2022
  •  | 
  •  

Question

I'm having a problem removing a directory after it's subfolders / files have been removed. I'm using FindFirstFile, FindNextFile, RemoveDirectory, etc. For instance I have this directory:

C:\Users\user\Desktop\SearchFile\ipch\searchfile-e3798fd4\some-files-here.ipch

After my program runs, it's left with this

C:\Users\user\Desktop\SearchFile\ipch

As you can see it deletes all files in searchfile-e3798fd4 and removes the directory, but leaves the parent directory 'ipch', which i want deleted as well. This is my full current code:

#include <Windows.h>
#include <wchar.h>
#include <stdio.h>

bool DeleteDirectory( const wchar_t *sDir )
{
    WIN32_FIND_DATA fdFile;
    HANDLE hFind;
    wchar_t sPath[ MAX_PATH * 10 ];

    wsprintf( sPath, L"%s\\*.*", sDir );

    if( ( hFind = FindFirstFile( sPath, &fdFile ) ) == INVALID_HANDLE_VALUE )
    {
        return false;
    }

    do
    {
        if( wcscmp( fdFile.cFileName, L"." ) != 0 &&
            wcscmp( fdFile.cFileName, L".." ) != 0 )
        {
            wsprintf( sPath, L"%s\\%s", sDir, fdFile.cFileName );

            if( fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
            {
                // Is Directory
                RemoveDirectory( sPath );
                DeleteDirectory( sPath );
            }
        }
    } while( FindNextFile( hFind, &fdFile ) );

    FindClose( hFind );
    return true;
}
bool DeleteFiles( const wchar_t *sDir, WIN32_FIND_DATA fdFile, HANDLE hFind )
{
    wchar_t sPath[ MAX_PATH * 10 ];

    wsprintf( sPath, L"%s\\*.*", sDir );

    if( ( hFind = FindFirstFile( sPath, &fdFile ) ) == INVALID_HANDLE_VALUE )
    {
        MessageBox( NULL, L"123", L"123", MB_OK );
        return false;
    }

    do
    {
        if( wcscmp( fdFile.cFileName, L"." ) != 0 &&
            wcscmp( fdFile.cFileName, L".." ) != 0 )
        {
            wsprintf( sPath, L"%s\\%s", sDir, fdFile.cFileName );

            if( fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
            {
                // Is Directory
                DeleteFiles( sPath, fdFile, hFind );
            }
            else
            {
                // Is File
                DeleteFile( sPath );
            }
        }
    } while( FindNextFile( hFind, &fdFile ) );


    FindClose( hFind );
    return true;
}
bool DeleteFolderContents( const wchar_t *sDir )
{
    WIN32_FIND_DATA fdFile;
    HANDLE hFind = NULL;
    wchar_t sPath[ MAX_PATH * 10 ];

    wsprintf( sPath, L"%s\\*.*", sDir );

    if( ( hFind = FindFirstFile( sPath, &fdFile ) ) == INVALID_HANDLE_VALUE )
    {
        MessageBox( NULL, L"", L"", MB_OK );
        return false;
    }

    do
    {
        if( wcscmp( fdFile.cFileName, L"." ) != 0 &&
            wcscmp( fdFile.cFileName, L".." ) != 0 )
        {
            wsprintf( sPath, L"%s\\%s", sDir, fdFile.cFileName );

            if( fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
            {
                // Is Directory
                if( wcscmp( fdFile.cFileName, L"Debug" ) == 0 ||
                    wcscmp( fdFile.cFileName, L"Release" ) == 0 ||
                    wcscmp( fdFile.cFileName, L"ipch" ) == 0 )
                {
                    DeleteFiles( sPath, fdFile, hFind );
                }
                DeleteFolderContents( sPath );
            }
        }
    } while( FindNextFile( hFind, &fdFile ) );

    FindClose( hFind );
    return true;
}
bool ListDirectoryContents( const wchar_t *sDir )
{
    WIN32_FIND_DATA fdFile;
    HANDLE hFind = NULL;
    wchar_t sPath[ MAX_PATH * 10 ];

    wsprintf( sPath, L"%s\\*.*", sDir );

    if( ( hFind = FindFirstFile( sPath, &fdFile ) ) == INVALID_HANDLE_VALUE )
    {
        MessageBox( NULL, L"Path not found", L"Error", MB_OK | MB_ICONERROR );
        return false;
    }

    do
    {
        if( wcscmp( fdFile.cFileName, L"." ) != 0 &&
            wcscmp( fdFile.cFileName, L".." ) != 0 )
        {
            wsprintf( sPath, L"%s\\%s", sDir, fdFile.cFileName );

            if( fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
            {
                // Is Directory
                if( wcscmp( fdFile.cFileName, L"Debug" ) == 0 ||
                    wcscmp( fdFile.cFileName, L"Release" ) == 0 ||
                    wcscmp( fdFile.cFileName, L"ipch" ) == 0 )
                {
                    // Working in debug folder
                    wprintf( L"[+] %s\n", sPath );
                }
                ListDirectoryContents( sPath );
            }
            else
            {
                // Is File
                wprintf( L"[-] %s\n", sPath );
            }
        }
    } while( FindNextFile( hFind, &fdFile ) );

    FindClose( hFind );
    return true;
}
int main()
{
    wchar_t pathName[] = L"C:\\Users\\user\\Desktop\\SearcFile\\";

    // List Directory Contents
    ListDirectoryContents( pathName );
    wprintf( L"\n" );
    system("pause");

    // Delete Folder Contents
    DeleteFolderContents( pathName );
    DeleteDirectory( pathName );
    wprintf( L"\n" );
    system("pause");

    ListDirectoryContents( pathName );
    wprintf( L"\n" );
    system("pause");

    return 0;
}

I'm aware that the problem exists where I actually RemoveDirectory( sPath ); Because that function is called it sees that ipch isn't empty, therefore doesn't delete it. then recursives and continues on.

Was it helpful?

Solution

You have three problems with your recursion, making it not match the algorithm Tim describes:

  1. You are trying to delete the directory before the contents. But RemoveDirectory only deletes empty directories.
  2. You (attempt to) delete subdirectories, but leave files in place. This also will prevent removal of the directory.
  3. You never delete the original directory.

Moving the RemoveDirectory call from inside the loop to the end of the function will solve these problems.

OTHER TIPS

I didn't look at all of your code, but I would imagine that, just like @BenVoigt and @TimBergel said, you need something like this:

} while( FindNextFile( hFind, &fdFile ) );

::RemoveDirectory (sDir) ; // Add this here.

FindClose( hFind );
return true;

Here's a fully working example just to give you an idea:

#include <string>

#include <Windows.h>

#define DIR L"C:\\Users\\user\\Desktop\\SearchFile\\ipch"

BOOL RmDir (const std::wstring &strDir) ;
BOOL IsDots (const std::wstring &strName) ;
BOOL IsDir (const WIN32_FIND_DATA &fdFile) ;

int main (void)
{
    if (RmDir (DIR) == FALSE) {
        return 1 ;
    }

    return 0 ;
}

BOOL RmDir (const std::wstring &strDir)
{
    WIN32_FIND_DATA fdFile ;
    ::memset (&fdFile, 0, sizeof (fdFile)) ;

    HANDLE hFind = INVALID_HANDLE_VALUE ;

    std::wstring strSearch = strDir + L"\\*.*" ;

    hFind = ::FindFirstFile (strSearch.data (), &fdFile) ;

    if (hFind == INVALID_HANDLE_VALUE) {
        return FALSE ;
    }

    do {    
        std::wstring strDelete = strDir + L"\\" + fdFile.cFileName ;

        if (IsDir (fdFile) == TRUE) {
            if (IsDots (fdFile.cFileName) == TRUE) {
                continue ;
            }

            RmDir (strDelete) ;
        }

        else {

            ::DeleteFile (strDelete.data ()) ;
        }

    } while (::FindNextFile (hFind, &fdFile) == TRUE) ;

    ::FindClose (hFind) ;
    ::RemoveDirectory (strDir.data ()) ;

    return TRUE ;
}

BOOL IsDots (const std::wstring &strName)
{
    return strName == L"." || strName == L".." ;
}

BOOL IsDir (const WIN32_FIND_DATA &fdFile)
{
    return (fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 ;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top