Finding the Recycle Bin on a local NTFS drive

前端 未结 4 2053
我寻月下人不归
我寻月下人不归 2021-01-03 09:33

I\'m trying to write some simple code that will return the directory for the recycle bin on a local drive. Seems like it would be simple -- should be a thousand answers on

相关标签:
4条回答
  • 2021-01-03 10:05

    Using Raymond Chen's advice, and someone else's technique (can't remember where I found it) I present a function that will find the Recycle Bin directory on a drive. The function cycles through the directories in the root directory looking at hidden and/or system directories. When it finds one, it checks the child subdirectories looking for one that has CLSID_Recycle Bin.

    Note that I've included two GetFolderCLSID functions below. Raymond Chen's is the simpler one, but it doesn't work on Windows 2000. The other implementation is longer, but appears to work everywhere.

    Call like: CString recycleDir = FindRecycleBinOnDrive(L"C:\");

    CString FindRecycleBinOnDrive(LPCWSTR path)
    {
        CString search;
        search.Format(L"%c:\\*", path[0]);
        WIN32_FIND_DATA fd = {0};
        HANDLE fHandle = FindFirstFile(search, &fd);
        while(INVALID_HANDLE_VALUE != fHandle)
        {
            if(FILE_ATTRIBUTE_DIRECTORY == (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) //only check directories
            {
                if(0 != (fd.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN))) //only check hidden and/or system directories
                {
                    //the recycle bin directory itself won't be marked, but a SID-specific child directory will, so now look at them
                    CString childSearch;
                    childSearch.Format(L"%c:\\%s\\*", path[0], fd.cFileName);
                    WIN32_FIND_DATA childFD = {0};
                    HANDLE childHandle = FindFirstFile(childSearch, &childFD);
                    while(INVALID_HANDLE_VALUE != childHandle)
                    {
                        if((FILE_ATTRIBUTE_DIRECTORY == (childFD.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) && //only check directories
                            (childFD.cFileName[0] != L'.')) //don't check . and .. dirs
                        {
                            CString fullPath;
                            fullPath.Format(L"%c:\\%s\\%s", path[0], fd.cFileName, childFD.cFileName);
                            CLSID id = {0};
                            HRESULT hr = GetFolderCLSID(fullPath, id);
                            if(SUCCEEDED(hr))
                            {
                                if(IsEqualGUID(CLSID_RecycleBin, id))
                                {
                                    FindClose(childHandle);
                                    FindClose(fHandle);
                                    //return the parent (recycle bin) directory
                                    fullPath.Format(L"%c:\\%s", path[0], fd.cFileName);
                                    return fullPath;
                                }
                            }
                            else
                            {
                                Log(logERROR, L"GetFolderCLSID returned %08X for %s", hr, fullPath);
                            }
                        }
    
                        if(FALSE == FindNextFile(childHandle, &childFD))
                        {
                            FindClose(childHandle);
                            childHandle = INVALID_HANDLE_VALUE;
                        }
                    }
                }
            }
            if(FALSE == FindNextFile(fHandle, &fd))
            {
                FindClose(fHandle);
                fHandle = INVALID_HANDLE_VALUE;
            }
        }
        _ASSERT(0);
        return L"";
    }
    
    
    //Works on Windows 2000, and even as Local System account
    HRESULT GetFolderCLSID(LPCWSTR path, CLSID& pathCLSID)
    {
        LPMALLOC pMalloc = NULL;
        HRESULT hr = 0;
        if (SUCCEEDED(hr = SHGetMalloc(&pMalloc))) 
        {
            LPSHELLFOLDER pshfDesktop = NULL;
            if (SUCCEEDED(hr = SHGetDesktopFolder(&pshfDesktop))) 
            {
                LPITEMIDLIST pidl = NULL;
                DWORD dwAttributes = SFGAO_FOLDER;
                if (SUCCEEDED(hr = pshfDesktop->ParseDisplayName(NULL, NULL, (LPWSTR)path, NULL, &pidl, &dwAttributes))) 
                {
                    LPPERSIST pPersist = NULL;
                    if (SUCCEEDED(hr = pshfDesktop->BindToObject(pidl, NULL, IID_IPersist, (LPVOID *) &pPersist))) 
                    {
                        hr = pPersist->GetClassID(&pathCLSID); 
                        pPersist->Release();
                    } 
                    pMalloc->Free(pidl);
                } 
                pshfDesktop->Release();
            } 
            pMalloc->Release();
        }
        return hr;
    }
    
    
    //Not supported on Windows 2000 since SHParseDisplayName wasn't implemented then
    //HRESULT GetFolderCLSID(LPCWSTR pszPath, CLSID& pathCLSID)
    //{
    //  SHDESCRIPTIONID did = {0};
    //  HRESULT hr = 0;
    //  LPITEMIDLIST pidl = NULL;
    //  if (SUCCEEDED(hr = SHParseDisplayName(pszPath, NULL, &pidl, 0, NULL))) //not supported by Windows 2000
    //  {
    //      IShellFolder *psf = NULL;
    //      LPCITEMIDLIST pidlChild = NULL;
    //      if (SUCCEEDED(hr = SHBindToParent(pidl, IID_IShellFolder, (void**)&psf, &pidlChild))) 
    //      {
    //          hr = SHGetDataFromIDList(psf, pidlChild, SHGDFIL_DESCRIPTIONID, &did, sizeof(did));
    //          psf->Release();
    //          pathCLSID = did.clsid;
    //      }
    //      CoTaskMemFree(pidl);
    //  }
    //  return hr;
    //}
    
    0 讨论(0)
  • 2021-01-03 10:08

    A little bit late, but perhaps better late than never...

    After debugging shell32.dll, I have found that for each version of windows the recycle path is hardcoded and, also, depends on the filesystem of that drive. I have tested this on Windows XP, Vista and Windows7:

    Let X: be the drive we want to get the path to the recycle bin and let SID be the SID of the current user, then:

    
        switchif(OsType) {
            case WindowsXP:
            {
                if(PartitionType("X:") == NTFS)
                {
                    printf("Path is: X:\\Recycler\\SID\\");
                }
                else
                {
                    printf("Path is X:\\RECYCLED\\");
                }
            }
    
            case WindowsVista:
            case Windows7:
            {
                if(PartitionType("X:") == NTFS)
                {
                    printf("Path is: X:\\$Recycle.bin\\SID\\");
                }
                else
                {
                    printf("Path is X:\\$RECYCLE.BIN\\");
                }
            }
        }
    
    

    A wiki article presents the same facts: http://en.wikipedia.org/wiki/Recycle_Bin_%28Windows%29

    0 讨论(0)
  • 2021-01-03 10:09

    In Win32, use SHGetSpecialFolderLocation. Pass CSIDL_BITBUCKET as the CDIL parameter.

    0 讨论(0)
  • 2021-01-03 10:27

    Raymond Chen has the answer - How can I tell that a directory is really a recycle bin?

    0 讨论(0)
提交回复
热议问题