65.9K
CodeProject 正在变化。 阅读更多。
Home

更大的目录

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.96/5 (13投票s)

2016年4月3日

CPOL

2分钟阅读

viewsIcon

44849

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
    • 修复了拖放隐藏文件夹的问题
© . All rights reserved.