Introduction
More and more programs are using the 32k Unicode character limit for path string
s, 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:
int RecurseRemovePath(int trackFTA[branchLimit][2],
wchar_t folderTreeArray[branchLimit + 1][treeLevelLimit + 1][maxPathFolder])
{
if (trackFTA [treeLevel][1] > 0) {
if (trackFTA [treeLevel][0] == trackFTA [treeLevel][1]) {
trackFTA [treeLevel][1] = 0; treeLevel -=1;
wcscpy_s(currPathW, maxPathFolder,
folderTreeArray[trackFTA [treeLevel][0]-1][treeLevel]);
if (treeLevel == 0) {
if (dblclkLevel)
{
if (!SetCurrentDirectoryW (dblclkString)) {
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; }
}
else
{
if (!SetCurrentDirectoryW (driveIDBaseW)) {
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; }
}
}
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; }
}
}
else
{
if (trackFTA[treeLevel][0] <= 999)
{
trackFTA[treeLevel][0] +=1;
wcscpy_s(findPathW, maxPathFolder, folderTreeArray[trackFTA[treeLevel][0]-1][treeLevel]);
if (!SetCurrentDirectoryW (findPathW))
{
ErrorExit (L"SetCurrentDirectoryW: Non zero", 0);
return 1;
}
treeLevel +=1; 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 {
memset(&dw, 0, sizeof(WIN32_FIND_DATAW));
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) {
FindClose(ds);
ErrorExit (L"FindFirstFileW: Should never get here. No can do!", 0);
return 1; }
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"..")))
{
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);
trackFTA [treeLevel][0] = 0;
if (j == 0)
{
if (treeLevel == 1) {
if (dblclkLevel)
{
if (!SetCurrentDirectoryW (dblclkString)) {
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; }
}
else
{
if (!SetCurrentDirectoryW (driveIDBaseW)) {
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;
if (RemoveDirectoryW (currPathWtmp))
{
return 0;
}
else
{
ErrorExit (L"RemoveDirectoryW: Cannot remove Folder.
It may contain files.", 0);
return 1; }
}
}
else
{
if (!SetCurrentDirectoryW (L".."))
{
ErrorExit (L"SetCurrentDirectoryW: Non zero", 0);
return 1;
}
}
if (RemoveDirectoryW (folderTreeArray[trackFTA[treeLevel-1][0]-1][treeLevel-1]))
{
trackFTA [treeLevel][1] = 0; 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; }
}
else {
ErrorExit("SetCurrentDirectoryW: Non zero", 0);
trackFTA [treeLevel][1] = j;
if (RecurseRemovePath(trackFTA, folderTreeArray))
{
return 1;
}
else
{
return 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