如何使用C#从recyclebin中删除多项目?

时间:2017-03-16 07:38:00

标签: c# windows shell32

enter image description here

如何通过C#或windows api删除多项目,我已经搜索了很长时间没有解决方案。我在Shell32.dll中使用FolderItemVerb逐个删除文件,但它会同时弹出一个对话框。如果您知道如何解决这个问题,我将不胜感激。谢谢。

2 个答案:

答案 0 :(得分:0)

首先将 System.Runtime.InteropService 添加到您的项目中。我们将使用SHEmptyRecycleBin方法,该方法接受3个参数。 之后,使用DllImport

在您的班级中导入 Shell32.dll
[DllImport("Shell32.dll")]
static extern int SHEmptyRecycleBin(IntPtr hwnd, string pszRootPath, RecycleFlag dwFlags);

然后为RecycleBin标志(dwFlags)定义一个枚举。值以十六进制表示。

enum RecycleFlag : int
{
    SHERB_NOCONFIRMATION = 0x00000001, // No confirmation
    SHERB_NOPROGRESSUI = 0x00000001, // No progress tracking window 
    SHERB_NOSOUND = 0x00000004 // No sound played
}

将以下代码放在空的回收站按钮中,该按钮将Shell32.dll中的系统方法调用为:

SHEmptyRecycleBin(IntPtr.Zero, null, RecycleFlag.SHERB_NOSOUND | RecycleFlag.SHERB_NOCONFIRMATION);

参考:here

答案 1 :(得分:0)

这不适合胆小的人!

与Windows兼容的代码> = Vista,没有XP! XP代码在最后

这是我第一次看看Shell32接口......哇......即使是最简单的东西也很复杂:-)但是,COM总是很复杂......现在......有2.5用于在Shell中操作文件的竞争数据结构/接口... IShellFolder(旧的COM接口,此示例中未使用),IShellItem(此示例中使用的新COM接口),{{ 1}}(此处用作IDLIST,用于“收集”多个文件。我将其视为0.5)。我希望任何地方都没有内存泄漏(总是很复杂)。请注意,.NET将自动释放COM对象。我甚至添加了一些我编写的代码来帮助我调试(比如获得动词列表的代码)。

现在,这里有COM接口和一些 Shell32.dll PInvoke方法。

PIDLIST_ABSOLUTE

最后是一个使用它的小示例程序...它是一个小型控制台方法,它将列出回收站中存在的所有文件,将其中10个放入一个数组中并在一次操作中删除它们(动词)。 [StructLayout(LayoutKind.Sequential)] public struct PIDLIST_ABSOLUTE { public IntPtr Ptr; } [ComImport] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")] public interface IShellItem { void BindToHandler( IntPtr pbc, [In, MarshalAs(UnmanagedType.LPStruct)] Guid bhid, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppv); void GetParent(out IShellItem ppsi); void GetDisplayName(int sigdnName, out IntPtr ppszName); void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs); [PreserveSig] int Compare(IShellItem psi, uint hint, out int piOrder); } [ComImport] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("70629033-e363-4a28-a567-0db78006e6d7")] public interface IEnumShellItems { void Next(int celt, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] IShellItem[] rgelt, out int pceltFetched); void Skip(int celt); void Reset(); void Clone(out IEnumShellItems ppenum); } [ComImport] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("b63ea76d-1f85-456f-a19c-48159efa858b")] public interface IShellItemArray { void BindToHandler( IntPtr pbc, [In, MarshalAs(UnmanagedType.LPStruct)] Guid bhid, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppvOut); void GetPropertyStore( uint flags, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppv); void GetPropertyDescriptionList( IntPtr keyType, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppv); void GetAttributes(uint AttribFlags, uint sfgaoMask, out uint psfgaoAttribs); void GetCount(out int pdwNumItems); void GetItemAt(int dwIndex, out IShellItem ppsi); void EnumItems(out IEnumShellItems ppenumShellItems); } [ComImport] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("000214e4-0000-0000-c000-000000000046")] public interface IContextMenu { [PreserveSig] int QueryContextMenu(IntPtr hMenu, uint indexMenu, int idCmdFirst, int idCmdLast, uint uFlags); void InvokeCommand([In] ref CMINVOKECOMMANDINFOEX pici); [PreserveSig] int GetCommandString(UIntPtr idCmd, uint uType, IntPtr pReserved, IntPtr pszName, int cchMax); } [StructLayout(LayoutKind.Sequential)] public struct CMINVOKECOMMANDINFOEX { public int cbSize; public uint fMask; public IntPtr hwnd; // Non-unicode verbs (are there unicode verbs?) [MarshalAs(UnmanagedType.LPStr)] public string lpVerb; [MarshalAs(UnmanagedType.LPStr)] public string lpParameters; [MarshalAs(UnmanagedType.LPStr)] public string lpDirectory; public int nShow; public uint dwHotKey; public IntPtr hIcon; [MarshalAs(UnmanagedType.LPStr)] public string lpTitle; // Use CMIC_MASK_UNICODE [MarshalAs(UnmanagedType.LPWStr)] public string lpVerbW; [MarshalAs(UnmanagedType.LPWStr)] public string lpParametersW; [MarshalAs(UnmanagedType.LPWStr)] public string lpDirectoryW; [MarshalAs(UnmanagedType.LPWStr)] public string lpTitleW; public int ptInvokeX; public int ptInvokeY; } // Windows >= Vista public static class ShellItemUtilities { public static readonly Guid FOLDERID_RecycleBinFolder = new Guid("b7534046-3ecb-4c18-be4e-64cd4cb7d6ac"); public static readonly Guid BHID_EnumItems = new Guid("94f60519-2850-4924-aa5a-d15e84868039"); public static readonly Guid BHID_SFUIObject = new Guid("3981e225-f559-11d3-8e3a-00c04f6837d5"); // From Windows 7 [DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)] public static extern int SHGetKnownFolderItem( [In, MarshalAs(UnmanagedType.LPStruct)] Guid rfid, uint dwFlags, IntPtr hToken, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IShellItem ppv); // For Windows Vista [DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)] public static extern int SHCreateItemFromIDList(PIDLIST_ABSOLUTE pidl, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IShellItem ppv); // For Windows Vista [DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)] public static extern int SHGetKnownFolderIDList( [In, MarshalAs(UnmanagedType.LPStruct)] Guid rfid, uint dwFlags, IntPtr hToken, out PIDLIST_ABSOLUTE ppidl); // From Windows Vista [DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)] public static extern int SHGetIDListFromObject([MarshalAs(UnmanagedType.Interface)] object punk, out PIDLIST_ABSOLUTE ppidl); [DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)] public static extern int SHCreateShellItemArrayFromIDLists(int cidl, [In] PIDLIST_ABSOLUTE[] rgpidl, out IShellItemArray ppsiItemArray); public static IEnumerable<IShellItem> Enumerate(this IShellItem si) { object pesiTemp; si.BindToHandler(IntPtr.Zero, BHID_EnumItems, typeof(IEnumShellItems).GUID, out pesiTemp); var pesi = (IEnumShellItems)pesiTemp; var items = new IShellItem[10]; while (true) { int fetched; pesi.Next(1, items, out fetched); if (fetched == 0) { break; } yield return items[0]; } } } public static class ContextMenuUtilities { [DllImport("User32.dll", ExactSpelling = true, SetLastError = true)] public static extern IntPtr CreateMenu(); [DllImport("User32.dll", ExactSpelling = true, SetLastError = true)] public static extern bool DestroyMenu(IntPtr hMenu); [DllImport("User32.dll", ExactSpelling = true, SetLastError = true)] public static extern int GetMenuItemCount(IntPtr hMenu); [DllImport("User32.dll", ExactSpelling = true, SetLastError = true)] public static extern uint GetMenuItemID(IntPtr hMenu, int nPos); [DllImport("User32.dll", CharSet = CharSet.Unicode, EntryPoint = "GetMenuStringW", ExactSpelling = true, SetLastError = true)] public static extern int GetMenuString(IntPtr hMenu, uint uIDItem, [Out] StringBuilder lpString, int nMaxCount, uint uFlag); public static string[] GetVerbs(IContextMenu cm, bool ansi = true) { IntPtr menu = IntPtr.Zero; try { menu = CreateMenu(); // It isn't clear why short.MaxValue, but 0x7FFF is very used around the .NET! int res = cm.QueryContextMenu(menu, 0, 0, short.MaxValue, 0); if (res < 0) { Marshal.ThrowExceptionForHR(res); } //var sb = new StringBuilder(128); int count = GetMenuItemCount(menu); var verbs = new List<string>(count); var handle = default(GCHandle); try { var bytes = new byte[ansi ? 128 : 256]; handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); IntPtr ptr = handle.AddrOfPinnedObject(); for (int i = 0; i < count; i++) { uint id = GetMenuItemID(menu, i); if (id == uint.MaxValue) { continue; } //GetMenuString(menu, (uint)i, sb, sb.Capacity, 0x00000400 /* MF_BYPOSITION */); //string description = sb.ToString(); //sb.Clear(); res = cm.GetCommandString((UIntPtr)id, ansi ? (uint)0x00000002 /* GCS_VALIDATEA */ : 0x00000006 /* GCS_VALIDATEW */, IntPtr.Zero, ptr, bytes.Length); if (res < 0) { continue; } if (res == 0) { res = cm.GetCommandString((UIntPtr)id, ansi ? (uint)0x00000000 /* GCS_VERBA */ : 0x00000004 /* GCS_VERBW */, IntPtr.Zero, ptr, bytes.Length); if (res < 0) { Marshal.ThrowExceptionForHR(res); } verbs.Add(ansi ? Marshal.PtrToStringAnsi(ptr) : Marshal.PtrToStringUni(ptr)); } } } finally { if (handle.IsAllocated) { handle.Free(); } } return verbs.ToArray(); } finally { if (menu != IntPtr.Zero) { DestroyMenu(menu); } } } } 来自Windows 7,因此我使用的是来自Windows Vista的SHGetKnownFolderItem + SHGetKnownFolderIDList

此处的代码列举了回收站中包含的SHCreateItemFromIDList个文件,将IShellItem保存在PIDL_ABSOLUTE中,List<>创建了List<>,在IShellItemArray上绑定IShellItemArray,因为IContextMenu执行IContextMenu动词。显然,通过添加/不添加delete所有PIDL_ABSOLUTE,您可以控制哪些文件将被删除。

List<>

Windows XP代码,使用其他版本的代码,您必须采取所需的

它使用private static void TestShellItem() { IShellItem recyleBin; string str; IntPtr ptr = IntPtr.Zero; int res; //// From Windows 7 //res = ShellItemUtilities.SHGetKnownFolderItem(ShellItemUtilities.FOLDERID_RecycleBinFolder, 0, IntPtr.Zero, typeof(IShellItem).GUID, out recyleBin); //if (res < 0) //{ // Marshal.ThrowExceptionForHR(res); //} // Windows >= Vista equivalent var pidl = default(PIDLIST_ABSOLUTE); try { res = ShellItemUtilities.SHGetKnownFolderIDList(ShellItemUtilities.FOLDERID_RecycleBinFolder, 0, IntPtr.Zero, out pidl); if (res < 0) { Marshal.ThrowExceptionForHR(res); } res = ShellItemUtilities.SHCreateItemFromIDList(pidl, typeof(IShellItem).GUID, out recyleBin); if (res < 0) { Marshal.ThrowExceptionForHR(res); } } finally { Marshal.FreeCoTaskMem(pidl.Ptr); } //// Example of use of GetDisplayName //try //{ // recyleBin.GetDisplayName(2, out ptr); // str = Marshal.PtrToStringUni(ptr); //} //finally //{ // if (ptr != IntPtr.Zero) // { // Marshal.FreeCoTaskMem(ptr); // ptr = IntPtr.Zero; // } //} var pids = new List<PIDLIST_ABSOLUTE>(); try { foreach (IShellItem si in recyleBin.Enumerate()) { try { si.GetDisplayName(0, out ptr); str = Marshal.PtrToStringUni(ptr); // Some condition to include/exclude... if (pids.Count < 10) { Console.WriteLine(str); // Remember to free the pidl! res = ShellItemUtilities.SHGetIDListFromObject(si, out pidl); if (res < 0) { Marshal.ThrowExceptionForHR(res); } pids.Add(pidl); } } finally { if (ptr != IntPtr.Zero) { Marshal.FreeCoTaskMem(ptr); ptr = IntPtr.Zero; } } } var pids2 = pids.ToArray(); IShellItemArray sia; res = ShellItemUtilities.SHCreateShellItemArrayFromIDLists(pids2.Length, pids2, out sia); if (res < 0) { Marshal.ThrowExceptionForHR(res); } object cmTemp; sia.BindToHandler(IntPtr.Zero, ShellItemUtilities.BHID_SFUIObject, typeof(IContextMenu).GUID, out cmTemp); var cm = (IContextMenu)cmTemp; // To see verbs //var verbsAnsi = ContextMenuUtilities.GetVerbs(cm, true); //var verbsUnicode = ContextMenuUtilities.GetVerbs(cm, false); var cmd = new CMINVOKECOMMANDINFOEX { cbSize = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFOEX)), fMask = 0x00000400 /* CMIC_MASK_FLAG_NO_UI */, lpVerb = "delete", }; cm.InvokeCommand(ref cmd); } finally { foreach (var pid in pids) { Marshal.FreeCoTaskMem(pid.Ptr); } } //// Verb executed one by one //foreach (var item in recyleBin.Enumerate()) //{ // object cmTemp; // item.BindToHandler(IntPtr.Zero, ShellItemUtilities.BHID_SFUIObject, typeof(IContextMenu).GUID, out cmTemp); // var cm = (IContextMenu)cmTemp; ////// To see verbs //// var verbsAnsi = ContextMenuUtilities.GetVerbs(cm, true); //// var verbsUnicode = ContextMenuUtilities.GetVerbs(cm, false); // var cmd = new CMINVOKECOMMANDINFOEX // { // cbSize = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFOEX)), // fMask = 0x00000400 /* CMIC_MASK_FLAG_NO_UI */, // lpVerb = "delete", // }; // cm.InvokeCommand(ref cmd); //} } 接口。请注意,IShellFolder处理完全相同。

IContextMenu

最后是一个使用它的小例子程序......

[StructLayout(LayoutKind.Sequential)]
public struct PIDLIST_RELATIVE
{
    public IntPtr Ptr;
}

[StructLayout(LayoutKind.Sequential)]
public struct LPITEMIDLIST
{
    public IntPtr Ptr;
}

[StructLayout(LayoutKind.Sequential)]
public struct PITEMID_CHILD
{
    public IntPtr Ptr;
}

public enum STRRET_TYPE
{
    WSTR = 0,
    OFFSET = 0x1,
    CSTR = 0x2
};

[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 268)]
public sealed class STRRET : IDisposable
{
    public STRRET_TYPE uType;
    public IntPtr pOleStr;

    [DllImport("Shlwapi.dll", ExactSpelling = true, SetLastError = false)]
    private static extern int StrRetToBSTR(STRRET pstr, PITEMID_CHILD pidl, [MarshalAs(UnmanagedType.BStr)] out string pbstr);

    ~STRRET()
    {
        Dispose(false);
    }

    public override string ToString()
    {
        return ToString(default(PITEMID_CHILD));
    }

    public string ToString(PITEMID_CHILD pidl)
    {
        if (uType == STRRET_TYPE.WSTR)
        {
            if (pOleStr == IntPtr.Zero)
            {
                return null;
            }

            string str = Marshal.PtrToStringUni(pOleStr);
            return str;
        }
        else
        {
            string str;

            int res = StrRetToBSTR(this, pidl, out str);

            if (res < 0)
            {
                Marshal.ThrowExceptionForHR(res);
            }

            return str;
        }
    }


    #region IDisposable Support

    // This code added to correctly implement the disposable pattern.
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    #endregion

    private void Dispose(bool disposing)
    {
        Marshal.FreeCoTaskMem(pOleStr);
        pOleStr = IntPtr.Zero;
    }
}

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214e6-0000-0000-c000-000000000046")]
public interface IShellFolder
{
    void ParseDisplayName(
        IntPtr hwnd,
        IntPtr pbc,
        [MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName,
        out int pchEaten,
        out PIDLIST_RELATIVE ppidl,
        ref uint pdwAttributes);

    void EnumObjects(IntPtr hwnd, uint grfFlags, out IEnumIDList ppenumIDList);

    void BindToObject(
        PIDLIST_RELATIVE pidl,
        IntPtr pbc,
        [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
        [MarshalAs(UnmanagedType.IUnknown)] out object ppv);

    void BindToStorage(
        PIDLIST_RELATIVE pidl,
        IntPtr pbc,
        [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
        [MarshalAs(UnmanagedType.IUnknown)] out object ppv);

    [PreserveSig]
    int CompareIDs(IntPtr lParam, PIDLIST_RELATIVE pidl1, PIDLIST_RELATIVE pidl2);

    void CreateViewObject(
        IntPtr hwndOwner,
        [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
        [MarshalAs(UnmanagedType.IUnknown)] out object ppv);

    void GetAttributesOf(
        int cidl,
        [In, MarshalAs(UnmanagedType.LPArray)] LPITEMIDLIST[] apidl,
        ref uint rgfInOut);

    void GetUIObjectOf(
        IntPtr hwndOwner,
        int cidl,
        [In, MarshalAs(UnmanagedType.LPArray)] PITEMID_CHILD[] apidl,
        [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
        IntPtr rgfReserved,
        [MarshalAs(UnmanagedType.IUnknown)] out object ppv);

    void GetDisplayNameOf(
        PITEMID_CHILD pidl,
        uint uFlags,
        STRRET pName);

    void SetNameOf(
        IntPtr hwnd,
        PITEMID_CHILD pidl,
        [MarshalAs(UnmanagedType.LPWStr)] string pszName,
        uint uFlags,
        out PITEMID_CHILD ppidlOut);
}

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214f2-0000-0000-c000-000000000046")]
public interface IEnumIDList
{
    void Next(int celt, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] PITEMID_CHILD[] rgelt, out int pceltFetched);

    void Skip(int celt);

    void Reset();

    void Clone(out IEnumIDList ppenum);
}

// Windows >= XP
public static class ShellFolderUtilities
{
    [DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
    public static extern int SHGetSpecialFolderLocation(IntPtr hwnd, int csidl, out PIDLIST_ABSOLUTE ppidl);

    [DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
    public static extern int SHGetDesktopFolder(out IShellFolder ppshf);

    public static readonly int CSIDL_DESKTOP = 0x0000;

    public static readonly int CSIDL_BITBUCKET = 0x000a;

    // https://blogs.msdn.microsoft.com/oldnewthing/20110830-00/?p=9773
    public static void BindToCsidl(int csidl, Guid riid, out object ppv)
    {
        var pidl = default(PIDLIST_ABSOLUTE);

        try
        {
            int res;

            if (csidl != CSIDL_DESKTOP)
            {
                res = SHGetSpecialFolderLocation(IntPtr.Zero, csidl, out pidl);

                if (res < 0)
                {
                    Marshal.ThrowExceptionForHR(res);
                }
            }

            IShellFolder psfDesktop;
            res = SHGetDesktopFolder(out psfDesktop);

            if (res < 0)
            {
                Marshal.ThrowExceptionForHR(res);
            }

            if (csidl == CSIDL_DESKTOP)
            {
                ppv = psfDesktop;
                return;
            }

            psfDesktop.BindToObject(new PIDLIST_RELATIVE { Ptr = pidl.Ptr }, IntPtr.Zero, riid, out ppv);
        }
        finally
        {
            Marshal.FreeCoTaskMem(pidl.Ptr);
        }
    }

    public static IEnumerable<PITEMID_CHILD> Enumerate(this IShellFolder sf)
    {
        IEnumIDList ppenumIDList;
        sf.EnumObjects(IntPtr.Zero, 0x00020 /* SHCONTF_FOLDERS */ | 0x00040 /* SHCONTF_NONFOLDERS */, out ppenumIDList);

        if (ppenumIDList == null)
        {
            yield break;
        }

        var items = new PITEMID_CHILD[1];

        while (true)
        {
            int fetched;

            ppenumIDList.Next(items.Length, items, out fetched);

            if (fetched == 0)
            {
                break;
            }

            yield return items[0];
        }
    }
}