12

给定一个文件夹,我怎么知道它是一个回收站?我找到了C++ 的答案,但没有找到 C# 的答案。

我的第一个想法是检查 FileAttributes.System (在我的情况下这是一个可接受的近似值),但实际上该标志已在回收文件夹中清除。

使用硬编码文件夹名称的粗略解决方案是不可能的(毕竟我们是在 2009 年)。

4

3 回答 3

7

这里有个小问题。Windows 回收站是一个虚拟文件夹,实际上并不存在。您看到的文件实际上并不在该文件夹中,它们是磁盘上已重命名为特殊名称的现有文件的表示,这会将它们从可见文件系统中“删除”,而不是物理文件系统。

您可以通过使用 win32 API 询问文件夹位置来为自己“证明”这一点。它将返回E_FAIL回收站,但不会返回其他文件夹(请参阅pinvoke.net和 MSDN 上)上的 SHGetKnownFolderPath,了解您可以使用的所有常量以及运行此代码所需的声明):

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 也不会检索此信息(同一个库有一个命名的方法来获取回收站,它也有一个GetPath,它将变为空)。

但一切都没有丢失。这个虚假的不存在的“文件名”或“文件夹名”包含一个隐藏文件,看起来像“S-1-5-21-2703390745-3900912742-210389625-1000”(你的会有所不同)。这是找出某个文件名是否实际上是回收站的虚拟目录的两种“可靠”方法之一(另一种方法是:通过删除文件SHFileOperation解释here,并检查它是否出现在您拥有的文件夹中):

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带有,SHGetSpecialFolderLocationShellAPI.SHGetFolderLocation的替代方法SHGetPathFromIDList都以相同的方式失败:空结果或错误。我测试了回收站和 AppData 的所有功能(以确保我使用了正确的参数)。

只有文档上ShGetPathFromIDListEx明确表示,引用:“除了 UNC 打印机名称,如果 pidl 参数指定的位置不是文件系统的一部分,则此功能失败。” .

于 2009-10-18T23:00:26.460 回答
3

Microsoft 的Windows API 代码包包含此功能。

要获取回收站的文件夹,请使用

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

我不知道那个字符串是什么意思,但它被包含在文档中作为对回收站的引用。

希望这可以帮助 :)

于 2009-10-18T19:48:06.360 回答
2

正如你提到的,大多数回收站相关的方法都是用 C++ 编写的。您可以使用C++ 的托管扩展在您的应用程序中创建一个包装类,然后您必须像这样使用 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 );
}
}

还有一些文章使用 C# 以其他方式执行此操作,其中大多数使用 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

于 2009-10-18T18:09:29.670 回答