Как я могу сказать, что каталог является корзиной в С#?

Учитывая папку, как я могу сказать, что это корзина? Я нашел ответ для С++, но не для С#.

Моя первая идея состояла в том, чтобы проверить FileAttributes.System(что было бы приемлемым приближением в моем случае), но на самом деле этот флаг очищается в корзине.

Неодобные решения с использованием имен жестко закодированных папок не могут быть и речи (мы все-таки в 2009 году).

Ответы

Ответ 1

Здесь есть небольшая проблема. Корзина Windows является виртуальной папкой и фактически не существует. Файлы, которые вы видите, фактически не находятся в этой папке, они представляют собой существующие файлы на диске, которые были переименованы в специальное имя, которое "удаляет" их из видимой файловой системы, но не физическое.

Вы можете "подтвердить" это для себя, запросив местоположение папки, используя API win32. Он вернет E_FAIL для корзины, но не для других папок (см. SHGetKnownFolderPath на pinvoke.net (и в MSDN) для всех констант, которые вы можете использовать, и деклараций, необходимых для запуска этого кода):

IntPtr ptrRecycleBinPath;
// try it with KnownFolder.QuickLaunch to see it working:
HRESULT hr = (HRESULT) SHGetKnownFolderPath(
     KnownFolder.RecycleBinFolder, 
     0, 
     IntPtr.Zero, 
     out ptrRecycleBinPath);

if (hr == HRESULT.E_FAIL)
{
    Console.WriteLine("No folder avaialable, virtual folder");
}
else if (hr == HRESULT.S_OK)
{
    string RecycleBinPath = Marshal.PtrToStringUni(ptrRecycleBinPath);
    Marshal.FreeCoTaskMem(ptrRecycleBinPath);
    Console.WriteLine("path: " + RecycleBinPath);
}

// for convenience, you can use the code above
// directly if you paste the follow declarations in your class:

// get a "known path"
[DllImport("shell32.dll")]
static extern long SHGetKnownFolderPath(
    [MarshalAs(UnmanagedType.LPStruct)] Guid rfid, 
    uint dwFlags, 
    IntPtr hToken, 
    out IntPtr pszPath);

// known folder GUID declarations
public static class KnownFolder
{
    // many more entries exist, left out for clarity here

    public static readonly Guid RecycleBinFolder = 
         new Guid("B7534046-3ECB-4C18-BE4E-64CD4CB7D6AC");

    public static readonly Guid QuickLaunch = 
         new Guid("52a4f021-7b75-48a9-9f6b-4b87a210bc8f");

    //....
}

// results of COM invocations:
enum HRESULT : uint
{
    S_FALSE = 0x0001,
    S_OK = 0x0000,
    E_FAIL = 0x80004005,
    E_INVALIDARG = 0x80070057,
    E_OUTOFMEMORY = 0x8007000E
}

Поддельное имя папки "$ Recycle.bin" повторяется для каждого диска. Скрытое имя не сохраняется в реестре и недоступно API как таковой. Ранее предложенный KnownFolderHelper не получит эту информацию (тот же lib имеет именованный метод для получения Корзины, он также имеет GetPath, он будет пустым).

Но все не потеряно. Это поддельное несуществующее "имя файла" или "имя папки" содержит скрытый файл, который выглядит примерно так: "S-1-5-21-2703390745-3900912742-210389625-1000" (ваш будет другим). Это один из двух "надежных" способов выяснить, является ли определенное имя файла виртуальным каталогом корзины (другим способом является: удаление файла через SHFileOperation, объясняется здесь и проверьте, отображается ли она в вашей папке):

string [] entries = Directory.GetFileSystemEntries(@"c:\$Recycle.bin", "?-?-?-??*");
if(entries.Length > 0)
   // we have a winner
else 
   // no, not the recycle bin

Примечание. Я не знаю, что скрытые папки находятся на других версиях win32, вам придется немного поэкспериментировать. Все они имеют систему и скрытый флаг и выглядят как искаженный GUID.

Документы API не очень понятны, но если вам нужно подтверждение, эта страница объясняет, что на самом деле нет пути, который может быть (более ранняя страница, связанная с CSIDL, на нем гораздо менее понятна).

Обновить: альтернативные подходы с SHGetSpecialFolderPath, SHGetSpecialFolderLocation, ShellAPI.SHGetFolderLocation и SHGetPathFromIDList все сбой: с пустым результатом или с ошибкой, Я протестировал все функции как для корзины, так и для AppData (чтобы убедиться, что я использовал правильные параметры).

Только документация на ShGetPathFromIDListEx явно указала на нее: "За исключением имен принтеров UNC, если местоположение, указанное параметром pidl не является частью файловой системы, эта функция не работает.".

Ответ 2

Большинство методов, связанных с корзинами, были написаны на С++, как вы упомянули. Вы можете создать класс-оболочку в своем приложении с помощью управляемых расширений для С++, тогда вам придется использовать DLLImport следующим образом:

using System;
using System.Runtime.InteropServices;

class MainApp
{
[DllImport("user32.dll", EntryPoint="MessageBox")]
public static extern int MessageBox(int hWnd, String strMessage, String
strCaption, uint uiType);

public static void Main()
{
MessageBox( 0, "Hello, this is PInvoke in operation!", ".NET", 0 );
}
}

Есть также статьи, которые делают это по-другому с С#, большинство из них используют PInvoke или полагаются на папку с $Recycle в ней. Ниже приведены несколько ссылок, которые я нашел для этой темы

http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/05f1476f-a101-4766-847b-0bdf4f6ad397

http://www.codeproject.com/KB/shell/recyclebin.aspx

http://www.pinvoke.net/default.aspx/shell32.SHFileOperation

Ответ 3

Microsoft Код кода Windows API содержит эту функциональность.

Чтобы получить папку корзины, используйте

Microsoft.WindowsAPICodePack.Shell.KnownFolderHelper.FromPath("::{645FF040-5081-101B-9F08-00AA002F954E}");

Я понятия не имею, что означает эта строка, но она была включена в документы в качестве ссылки на Корзину.

Надеюсь, что это поможет:)