Pergunta

Dada uma pasta, como posso dizer que é uma lixeira? Eu encontrei um responda para C ++, mas não para C#.

Minha primeira idéia foi verificar se há FileAttributes.System (que seria uma aproximação aceitável no meu caso), mas na verdade esse sinalizador é limpo na pasta de reciclagem.

As soluções brutas usando nomes de pastas codificadas estão fora de questão (afinal, estamos em 2009).

Foi útil?

Solução

Há um pequeno problema aqui. A lixeira do Windows é uma pasta virtual e realmente não existe. Os arquivos que você vê não estão realmente nessa pasta, eles são a representação dos arquivos existentes no disco que foram renomeados para um nome especial, que "os remove" do sistema de arquivos visíveis, mas não o físico.

Você pode "prova" isso por si mesmo solicitando o local da pasta usando a API Win32. Ele voltará E_FAIL para a lixeira, mas não para outras pastas (veja ShgetknownFolderpath em pinvoke.net (e no msdn) Para todas as constantes que você pode usar e as declarações necessárias para que este código seja executado):

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
}

O nome falso de dobra "$ Reciclo.bin" é repetido para cada unidade. O nome oculto não é armazenado no registro e não é acessível pela API como tal. O conhecido anteriormente sugeridoFolderHelper também não recuperará essas informações (o mesmo Lib tem um método nomeado para obter a lixeira, ele também tem um GetPath, vai aparecer vazio).

Mas tudo não está perdido. Este "nome de arquivo" ou "Nome da pasta" inexistente inexistente contém um arquivo oculto que se parece com algo como "S-1-5-21-2703390745-3900912742-210389625-1000" (o seu será diferente). É uma das duas maneiras "confiáveis" de descobrir se um determinado nome do arquivo é realmente um diretório virtual da lixeira (o contrário: excluir um arquivo através SHFileOperation, explicado aqui, e verifique se aparece na pasta que você tem):

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

Nota: Não sei quais são as pastas ocultas em outras versões do Win32, você precisa experimentar um pouco. Todos eles têm o sistema e a bandeira oculta e parecem um GUID mutilado.

Os documentos da API não estão muito claros sobre isso, mas se você precisar de confirmação, Esta página explica que realmente não há caminho que possa ser recuperado (o Página relacionada ao CSIDL mais antiga é muito menos claro sobre isso).

Atualizar: abordagens alternativas com SHGetSpecialFolderPath, SHGetSpecialFolderLocation, ShellAPI.SHGetFolderLocation e SHGetPathFromIDList Tudo falha com o mesmo: um resultado vazio ou um erro. Testei todas as funções tanto para a lixeira quanto para o AppData (para ter certeza de que usei os parâmetros corretos).

Somente a documentação sobre ShGetPathFromIDListEx disse isso explicitamente, citação: "Exceto para nomes de impressoras UNC, se o local especificado pelo parâmetro PIDL não fizer parte do sistema de arquivos, essa função falhar.".

Outras dicas

Microsoft's Pacote de código da API Windows contém essa funcionalidade.

Para obter a pasta da lixeira, use

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

Não faço ideia do que essa string significa, mas foi incluída nos documentos como referência à lixeira.

Espero que isto ajude :)

A maioria dos métodos relacionados à lixeira foi escrita em C ++, como você mencionou. Você pode criar uma classe de wrapper em seu aplicativo usando o Extensões gerenciadas para C ++, então você terá que usar o dllimport assim:

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

Também existem artigos por aí que fazem isso de outra maneira com C#, a maioria deles usa Pinvoke ou confia na pasta com $ reciclando em seu nome. A seguir, estão alguns links que encontrei para este assunto

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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top