更大的目录
Dialogex 与 Listbox,用于在 Windows 中操作长路径
引言
越来越多的程序正在使用 32k Unicode 字符限制的路径 字符串
,但 Explorer Shell 受到 MAX_PATH
限制的阻碍。只有在尝试使用资源管理器手动复制或删除目录中的文件时,你才会知道这一点。
因此,这就是“更大的目录”发挥作用的地方。
背景
MAX_PATH
的早期提及出现在 Tanenbaum 的 操作系统:设计与实现(1987 年)(我还记得他的 1984 年的 结构化计算机组织作为大学教材!)当时 FAT 文件系统很流行。 真正来自 DOS 的 8 位时代。
Using the Code
代码本身并不十分精美,但其功能在 GITHUB 上进行了概述。
最初的意图是用纯 C 编译它,但随着对 BOOL 的需求增加,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
}
//
该例程已针对相当简单的结构进行了测试(请注意注释)。我不敢创建过于复杂的结构,以免破坏此计算机上的文件系统!
该程序本身已在 Windows 7 (VS10) 和 Windows 8/10 (VS 2015 Community) 上进行了测试。
注释
这个程序是我进入 C 和 C++ 的入口点。(本应在 Tanenbaum 时代获得的。:P)进一步的 测试和编译 在 VM 的 MinGW 下使用 G++,感谢 VM。
- 首次发布
- 版本 1.1:支持所有驱动器
- 版本 1.11
- 修复了向上移动目录时的错误
- 修复了灰色数字框
- 版本 1.12
- 修复了创建和删除后的刷新问题
- 解决了小错误
- 版本 1.13
- 添加了版本信息
- 修复了创建和删除后的刷新问题(再次)
- 次要 bug 修复
- 版本 1.14
- 修复了 Kleenup 中的句柄错误
- 修复了 Userinit 密钥重命名
- 对代码进行了小幅改进
- 版本 1.2
- 表单可见性加载问题
- 更好的路径检查和错误捕获
- 在清单中支持长路径
- 支持 DPI 感知
- 改进了目录导航状态
- 解决了稳定性问题
- 现在可以在 Windows XP (SP3) 上运行
- 版本 1.2.1
- 修复了(又一个)关键删除错误
- 版本 1.2.2
- 修复了拖放隐藏文件夹的问题