windows - Find papirkurven på et lokalt NTFS-drev

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg forsøger at skrive en simpel kode, der returnerer biblioteket til papirkurven på et lokalt drev. Det lader til, at det ville være enkelt - skal være tusind svar på Google. Haven har ikke fundet en endnu :(


Jeg har fundet, at FAT og NTFS drev har forskellige basenavne (RECYCLED og RECYCLER). Jeg har fundet ud af, at 'papirkurven' er en virtuel mappe, der kombinerer papirkurven på alle drev på maskinen.


Hvad jeg ikke har fundet er en måde at finde C: drevs papirkurvkatalog - selv på en vietnamesisk (eller en anden ikke-engelsk) maskine. (Ingen indlæg, jeg kan finde, angiver, om 'RECYCLER' bliver internationaliseret eller ej)


Kan nogen pege på mig til et definitivt svar?


Tak


UPDATE: Aware of CSIDL\_BITBUCKET og de funktioner, der bruger det. Fra alt jeg har læst, peger det på en virtuel -mappe, som er foreningen af ​​alle slettede filer af den bruger på alle drev. Leder du efter den fysiske papirkurv-mappe (på min Vista ser det ud til at vær C: \ $ Recycle.Bin så vidt jeg kan fortælle)

Bedste reference


Ved hjælp af Raymond Chens råd og en andres teknik (kan ikke huske hvor jeg fandt det), præsenterer jeg en funktion, der finder papirkurv-mappen på et drev. Funktionen cykler gennem katalogerne i rodkatalogen og ser på skjulte og/eller systemmapper. Når den finder en, kontrollerer den underkatalogerne under barnet efter en, der har CLSID\_Recycle Bin.


Bemærk, at jeg har inkluderet to GetFolderCLSID funktioner nedenfor. Raymond Chen er den enklere, men det virker ikke på Windows 2000. Den anden implementering er længere, men synes at fungere overalt.


Ring som: 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;
//}

Andre referencer 1


Raymond Chen har svaret - Hvordan kan jeg fortælle, at en mappe virkelig er en papirkurv? [4]

Andre referencer 2


Lidt sent, men måske bedre sent end aldrig ...


Efter debugging shell32.dll har jeg fundet ud af, at for hver version af Windows er genbrugsstien hardcoded og afhænger også af filsystemet til det pågældende drev. Jeg har testet dette på Windows XP, Vista og Windows7:


Lad X: være det drev, vi ønsker at få stien til papirkurven, og lad SID være SID for den aktuelle bruger, så:



    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\");
            }
        }
    }



En wikiartikel præsenterer de samme fakta:
http://en.wikipedia.org/wiki/Recycle\_Bin\_\%28Windows\%29[5]

Andre referencer 3


I Win32 skal du bruge SHGetSpecialFolderLocation. Send CSIDL\_BITBUCKET som CDIL-parameter. [6] [7]