Click here to Skip to main content
15,074,377 members
Articles / Desktop Programming / Win32
Tip/Trick
Posted 3 Apr 2016

Stats

36.1K views
15 bookmarked

Bigger Directories

Rate me:
Please Sign up or sign in to vote.
4.96/5 (14 votes)
15 Dec 2017CPOL2 min read
Dialogex with Listbox to manipulate long paths in Windows

Introduction

More and more programs are using the 32k Unicode character limit for path strings, but the Explorer Shell is hampered by the MAX_PATH limitation. You only get to know this when attempting to manually copy or delete files from directories using explorer.

So this is where Bigger Directories comes in.

Background

An early mention of MAX_PATH is in Tanenbaum's Operating systems: design and implementation, 1987 (I recall his 1984 Structured Computer Organization as a University Text!) when FAT file systems were popular. Truly from the 8 bit days of DOS.

Using the Code

The code itself is no thing of great beauty, but the functionality is outlined at GITHUB.

The original intention was to compile it in pure C, but then as the appetite for BOOL increased, C++ was the preference and finally everything got squinched into a single module.

The only thing worth noting is the alternative recursive folder delete procedure:

C++
//
int RecurseRemovePath(int trackFTA[branchLimit][2], 
wchar_t folderTreeArray[branchLimit + 1][treeLevelLimit + 1][maxPathFolder])

     //first element of trackFTA is LAST_VISIT, second is number of folders found
{  
    if (trackFTA [treeLevel][1] > 0) //Have we done a search on this level yet? if yes then here
    {
            //move along the branch

            //wcscpy_s(currPathW, maxPathFolder, folderTreeArray[treeLevel][trackFTA[treeLevel][0]-1]);

            //FINISH coding this
            if (trackFTA [treeLevel][0] == trackFTA [treeLevel][1]) //end of the branch?
            {
            //Must go down but we have already found the files of directory below
            trackFTA [treeLevel][1] = 0;  //important
            treeLevel -=1;
            wcscpy_s(currPathW, maxPathFolder, 
            folderTreeArray[trackFTA [treeLevel][0]-1][treeLevel]);

                    if (treeLevel == 0) //Last folder to do!! 
                    {
                        if (dblclkLevel)

                        {
                            if (!SetCurrentDirectoryW (dblclkString)) //objects to L".."
                            {
                            ErrorExit (L"SetCurrentDirectoryW: Non zero", 0);
                            return 1;
                            }
                            if (RemoveDirectoryW (currPathW))
                            {
                                return 0;
                            }
                            else
                            {
                                ErrorExit (L"RemoveDirectoryW: 
                                Cannot remove Folder. It may contain files.", 0);

                                return 1; //Need more than this
                            }
                        }                        
                        else
                        {
                            if (!SetCurrentDirectoryW (driveIDBaseW)) //objects to L".."
                            {
                            ErrorExit (L"SetCurrentDirectoryW: Non zero", 0);
                            return 1;
                            }
                            wchar_t * currPathWtmp;
                            currPathWtmp = currPathW + 4;

                            if (RemoveDirectoryW (currPathWtmp))
                            {
                                return 0;
                            }
                            else
                            {
                                ErrorExit (L"RemoveDirectoryW: 
                                Cannot remove Folder. It may contain files.", 0);

                                return 1; //Need more than this
                            }
                        }
                    }
                    else
                    {
                        if (!SetCurrentDirectoryW (L".."))
                        {
                            ErrorExit (L"SetCurrentDirectoryW: Non zero", 0);
                            return 1;
                        }

                        if (RemoveDirectoryW (currPathW))
                        {

                        if (RecurseRemovePath(trackFTA, folderTreeArray))
                            {
                            return 1;
                            }
                            else
                            {
                            return 0;
                            }
                        }
                        else
                            {
                                ErrorExit (L"RemoveDirectoryW: 
                                Cannot remove Folder. It may contain files.", 0);
                                return 1; //Need more than this
                            }
                    }            
            }
            else
            {
                //folderTreeArray[treeLevel][j+1]
                if (trackFTA[treeLevel][0] <= 999)
                {
                trackFTA[treeLevel][0] +=1;

                // set inits for this branch
                wcscpy_s(findPathW, maxPathFolder, folderTreeArray[trackFTA[treeLevel][0]-1][treeLevel]);
                //
                if (!SetCurrentDirectoryW (findPathW))
                {
                    ErrorExit (L"SetCurrentDirectoryW: Non zero", 0);
                    return 1;
                }

                treeLevel +=1; // up next tree
                    if (RecurseRemovePath(trackFTA, folderTreeArray))
                        {
                        return 1;
                        }
                        else
                        {
                        return 0;
                        }
                }
                else
                {
                trackFTA[treeLevel][0] = 0;
                trackFTA[treeLevel][1] = 0;
                treeLevel -=1;
                ErrorExit (L"Too many folders in the tree: 
                If folder was created by this program, a warning 
                should have been issued on folder creation.", 0);
                return 1; 
                }
            }
    }
    else //search yet to be done on branch
    {
    //Do find folders in new branch, findPathW already set           
                
        memset(&dw, 0, sizeof(WIN32_FIND_DATAW));
        //Find first file
        //Get fulqualpath
        if (!GetCurrentDirectoryW (maxPathFolder, findPathW))
            {
                ErrorExit (L"GetCurrentDirectoryW: Zero", 0);
                return 1;
            }
        wcscat_s(findPathW, maxPathFolder, L"\\*");
        ds = FindFirstFileW(findPathW, &dw);
            if (ds == INVALID_HANDLE_VALUE) //redundant as first 2 pickups are "." and ".."
            {
                // No Folders so this must be top level
                FindClose(ds);
                ErrorExit (L"FindFirstFileW: Should never get here. No can do!", 0);
                return 1; //Need more than this                            
            }
                        
            BOOL findhandle = TRUE;
            j = 0;
                            
            while (ds != INVALID_HANDLE_VALUE && findhandle)
            {
            if ((dw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && 
            !(dw.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM || 
            dw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ||
                dw.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE || 
                dw.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN || 
                !wcscmp(dw.cFileName, L".") || !wcscmp(dw.cFileName, L"..")))
                                        
                //"." is just an alias for "this" directory
                //".." is just an alias for the parent directory.
            {
                wcscpy_s(currPathW, maxPathFolder, dw.cFileName);
                wcscat_s(currPathW, maxPathFolder, &separatorFTA);


                wcscpy_s(folderTreeArray[j][treeLevel], maxPathFolder, (wchar_t *)currPathW);
                j +=1;
            }
                findhandle = FindNextFileW(ds, &dw);
            }

            if (!FindClose(ds)) ErrorExit (L"FindClose: Non zero", 0);
            //wcscpy_s(currPathW, maxPathFolder, folderTreeArray[treeLevel][j-1]);
            trackFTA [treeLevel][0] = 0; //check reset counter if necessary here

            if (j == 0)
                {
                // No Folders so this must be top level
                    if (treeLevel == 1) //Last folder to do!! 
                    {
                        if (dblclkLevel)
                        {

                            if (!SetCurrentDirectoryW (dblclkString)) //objects to L".."
                            {
                            ErrorExit (L"SetCurrentDirectoryW: Non zero", 0);
                            return 1;
                            }
                            if (RemoveDirectoryW (currPathW))
                            {
                                return 0;
                            }
                            else
                            {
                                ErrorExit (L"RemoveDirectoryW: Cannot remove Folder. 
                                           It may contain files.", 0);

                                return 1; //Need more than this
                            }
                        }                        
                        else
                        {
                        
                            if (!SetCurrentDirectoryW (driveIDBaseW)) //objects to L".."
                            {
                            ErrorExit (L"SetCurrentDirectoryW: Non zero", 0);
                            return 1;
                            }

                            wchar_t * currPathWtmp = (wchar_t *)calloc(maxPathFolder, sizeof(wchar_t));

                            currPathWtmp = wcsstr (currPathW, L"\\\\?\\C:");
                            
                            (currPathWtmp)? currPathWtmp = currPathW + 4: currPathWtmp = currPathW;
                            //GetCurrentDirectoryW(maxPathFolder, findPathW);
                            if (RemoveDirectoryW (currPathWtmp))
                            {
                                return 0;
                            }
                            else
                            {
                                ErrorExit (L"RemoveDirectoryW: Cannot remove Folder. 
                                           It may contain files.", 0);

                                return 1; //Need more than this
                            }
                        }
                    }
                    else
                    {

                        if (!SetCurrentDirectoryW (L".."))
                        {
                        ErrorExit (L"SetCurrentDirectoryW: Non zero", 0);
                        return 1;
                        }
                    }

                    //GetCurrentDirectoryW(maxPathFolder, findPathW);
                    if (RemoveDirectoryW (folderTreeArray[trackFTA[treeLevel-1][0]-1][treeLevel-1]))
                    {
                        trackFTA [treeLevel][1] = 0;  //important
                        treeLevel -=1;
                        if (RecurseRemovePath(trackFTA, folderTreeArray))
                            {
                            return 1;
                            }
                            else
                            {
                            return 0;
                            }
                    }
                    else
                    {
                        ErrorExit (L"RemoveDirectoryW: Cannot remove Folder. It may contain files.", 0);
                        return 1; //Need more than this
                    }
                }

        else //Do an iteration on this new branch
                {
                    //if (!GetCurrentDirectoryW(maxPathFolder, findPathW)) 
                    ErrorExit("SetCurrentDirectoryW: Non zero", 0);
                    trackFTA [treeLevel][1] = j;

                    if (RecurseRemovePath(trackFTA, folderTreeArray))
                    {
                    return 1;
                    }
                    else
                    {
                    return 0;
                    }
                }
    } //trackFTA[treeLevel][0] = 0
}

//

The routine has been tested for fairly minimal structures (note the comments). I dared not create anything too complex for fear of destroying the filesystem on this computer!

The program itself has been tested on Windows 7 (VS10) and Windows 8/10 (VS 2015 Community).

Notes

This program was my entry point into C and C++. (Something that should have been acquired in the Tanenbaum days. :P) Further testing and compilation in G++ under MinGW, thanks to VM.

  • Initial release
  • Version 1.1: Support for all drives
  • Version 1.11
    • Error moving up directory fixed
    • Greyed out numbers box fixed
  • Version 1.12
    • Fixed refresh on Create & Delete
    • Minor bugs addressed
  • Version 1.13
    • Added Version info
    • Fixed refresh after Create & Delete (again)
    • Minor bug fixes
  • Version 1.14
    • Fixed Handle Bug in Kleenup
    • Fixed Userinit key rename
    • Minor Touch-Up of Code
  • Version 1.2
    • Form visibility load issues
    • Better path checking & error trapping
    • Long path aware in manifest
    • DPI aware
    • Improved directory navigation status
    • Stability Issues addressed
    • Now Runs in Windows XP (SP3)
  • Version 1.2.1
    • Fixed (yet another) critical deletion error
  • Version 1.2.2
    • Fixed issue with Drag & Drop hidden folders

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Laurie Stearn
Retired
Australia Australia
No Biography provided

Comments and Discussions

 
QuestionMy vote of 5 Pin
Farhad Reza24-Oct-16 6:42
MemberFarhad Reza24-Oct-16 6:42 
QuestionGood Article Pin
DumpsterJuice24-May-16 8:05
MemberDumpsterJuice24-May-16 8:05 
GeneralMy vote of 5 Pin
Alexander Navalov7-May-16 0:46
professionalAlexander Navalov7-May-16 0:46 
QuestionAn alternative Pin
feanorgem3-May-16 12:03
Memberfeanorgem3-May-16 12:03 
AnswerRe: An alternative Pin
Laurie Stearn4-May-16 2:18
MemberLaurie Stearn4-May-16 2:18 
GeneralRe: An alternative Pin
feanorgem4-May-16 3:58
Memberfeanorgem4-May-16 3:58 
QuestionCode question Pin
David Crow4-Apr-16 6:08
MemberDavid Crow4-Apr-16 6:08 
AnswerRe: Code question Pin
Laurie Stearn4-Apr-16 17:40
MemberLaurie Stearn4-Apr-16 17:40 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.