Поиск корзины на локальном диске NTFS

Я пытаюсь написать простой код, который вернет каталог для корзины на локальном диске. Кажется, это было бы просто — в Google должна быть тысяча ответов. пока не нашел :(

Я обнаружил, что диски FAT и NTFS имеют разные базовые имена (RECYCLED и RECYCLER). Я обнаружил, что корзина — это виртуальная папка, которая объединяет корзины всех дисков на машине.

Чего я не нашел, так это способа найти каталог корзины диска C: даже на вьетнамском (или любом другом неанглоязычном) компьютере. (Я не могу найти сообщений, указывающих, интернационализируется ли «RECYCLER» или нет)

Может ли кто-нибудь указать мне окончательный ответ?

Спасибо

ОБНОВЛЕНИЕ: известно о CSIDL_BITBUCKET и функциях, которые его используют. Однако из всего, что я прочитал, это указывает на виртуальный каталог, который представляет собой объединение всех файлов, удаленных этим пользователем на всех дисках. Ищем физический каталог корзины (на моей Vista это C:\$Recycle.Bin, насколько я могу судить)


person DougN    schedule 01.06.2009    source источник
comment
См. это вопрос и этот тоже.   -  person sean e    schedule 02.06.2009
comment
Посмотрел статью, на которую ссылается ваша первая ссылка. Он просто ссылается на CSIDL_BITBUCKET, который ссылается на каталог виртуальной корзины пользователя для всей машины, а не на каталог для каждого диска. Это проблема всего, что я могу найти в Google - все указывает на этот виртуальный каталог.   -  person DougN    schedule 02.06.2009
comment
О, и второй пост заставляет вас просмотреть все каталоги в поисках того, который будет соответствовать GUID корзины. Разве нет способа получить корзину для каждого диска?   -  person DougN    schedule 02.06.2009


Ответы (4)


У Рэймонда Чена есть ответ: Как узнать, что каталог действительно мусорная корзина?

person John Topley    schedule 02.06.2009
comment
Я начинаю думать, что это может быть единственный способ - прокрутить все каталоги в корне и проверить каждый, используя метод Рэймонда сравнения GUID каталога с GUID корзины. Можно было бы подумать, что есть более прямой путь... - person DougN; 02.06.2009
comment
Microsoft, вероятно, не хочет, чтобы вы напрямую возились с этими папками, потому что они могут быть изменены в будущем. - person John Topley; 02.06.2009

Воспользовавшись советом Рэймонда Чена и чьей-то еще методикой (не помню, где я ее нашел), я представляю функцию, которая найдет папку «Корзина» на диске. Функция циклически перебирает каталоги в корневом каталоге, просматривая скрытые и/или системные каталоги. Когда он находит его, он проверяет дочерние подкаталоги в поисках того, у которого есть CLSID_Recycle Bin.

Обратите внимание, что ниже я включил две функции GetFolderCLSID. Вариант Рэймонда Чена проще, но он не работает в Windows 2000. Другая реализация длиннее, но работает везде.

Вызовите так: 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;
//}
person DougN    schedule 03.06.2009

С опозданием, но, наверное, лучше поздно, чем никогда...

После отладки shell32.dll я обнаружил, что для каждой версии Windows путь перезаписи жестко запрограммирован, а также зависит от файловой системы этого диска. Я тестировал это на Windows XP, Vista и Windows7:

Пусть X: будет диском, на котором мы хотим получить путь к корзине, и пусть SID будет SID текущего пользователя, тогда:


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

В вики-статье представлены те же факты: http://en.wikipedia.org/wiki/Recycle_Bin_%28Windows%29

person botismarius    schedule 09.09.2009
comment
Это интересно. Интересно, работает ли это и в иностранных языковых версиях Windows? - person DougN; 09.04.2010

В Win32 используйте SHGetSpecialFolderLocation. Передайте CSIDL_BITBUCKET в качестве параметра CDIL.

person Michael Petrotta    schedule 01.06.2009
comment
CSIDL_BITBUCKET является виртуальным. Если указана виртуальная папка, эта функция не будет работать. - person sean e; 01.06.2009
comment
Вы правы. SHGetSpecialFolderLocation — это то, что вам нужно для переработчика. Обновил ответ. - person Michael Petrotta; 02.06.2009
comment
Насколько я читал, SHGetSpecialFolderLocation возвращает виртуальную пользовательскую папку — ту, в которой все локальные диски объединены в один. Я ищу физический каталог корзины на диске. - person DougN; 02.06.2009
comment
На диске нет физического каталога корзины. Это виртуальная папка. Корзина просто собирает папки и файлы со специальными именами (переименовываются, когда вы нажимаете «Удалить», поэтому они исчезают из файловой системы), но не имеет физического местоположения. - person Abel; 19.10.2009