0

enter image description here

how to delete multi-items via C# or windows api, I have search for this for a long time and no solution. I used FolderItemVerb in Shell32.dll to delete file one by one, but it would pop a dialog at same time. I will be appreciated if you know how to solve this problem. Thank you.

M. Adeel Khalid
  • 1,786
  • 2
  • 21
  • 24
roy
  • 11
  • 2
  • maybe [this](http://www.c-sharpcorner.com/UploadFile/167ad2/empty-recycle-bin-using-C-Sharp/) can help you... – Nino Mar 16 '17 at 08:01
  • There is an example here in C: https://blogs.msdn.microsoft.com/oldnewthing/20110901-00/?p=9753/ The example you'll need is the one starting with: *// in a real program you wouldn't hard-code a fixed limit* – xanatos Mar 16 '17 at 08:41
  • I use "Shell32.dll" to export function. – roy Mar 16 '17 at 09:41

2 Answers2

1

It isn't for the faint of heart!

Code compatible with Windows >= Vista, no XP! The XP code is at the end

This is the first time I take a look at the Shell32 interfaces... Wow... Even the most simple things are complex :-) But then, COM is always complex... Now... There are 2.5 competing data structures/interfaces for manipulating files in Shell... IShellFolder (the old COM interface, not used in this sample), IShellItem (the new COM interface, used in this sample), IDLIST (here used as a PIDLIST_ABSOLUTE, used for "collecting" multiple files together. I count it as 0.5 ). I hope there is no memory leak anywhere (always complex). Note that .NET will free COM objects automatically. I've even added some code that I've written to help me debug (like the code to get the list of verbs supported).

Now, here there are the COM interfaces plus some Shell32.dll PInvoke methods.

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

And then finally a small example program that uses it... It is a small console method that will list all the files that are present in the recycle bin, put 10 of them in an array and delete them in a single operation (verb). The SHGetKnownFolderItem is from Windows 7 on, so I'm using SHGetKnownFolderIDList + SHCreateItemFromIDList that are from Windows Vista.

The code here enumerates the IShellItem files contained in the recycle bin, saves their PIDL_ABSOLUTE in a List<>, from that List<> creates a IShellItemArray, on that IShellItemArray binds a IContextMenu, for that IContextMenu executes the delete verb. Clearly by adding/not adding all the PIDL_ABSOLUTE to the List<> you can control which files will be deleted.

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

Code for Windows XP, uses some code from the other version, you have to take what is needed

It uses the IShellFolder interface. Note that the IContextMenu handling is exactly the same.

[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];
        }
    }
}

And then finally a small example program that uses it...

private static void TestShellFolder()
{
    object recycleBinTemp;
    ShellFolderUtilities.BindToCsidl(ShellFolderUtilities.CSIDL_BITBUCKET, typeof(IShellFolder).GUID, out recycleBinTemp);
    var recycleBin = (IShellFolder)recycleBinTemp;

    var pids = new List<PITEMID_CHILD>();

    try
    {
        foreach (PITEMID_CHILD pidl in recycleBin.Enumerate())
        {
            // Remember to free the pidl!

            string str;

            using (var ret = new STRRET { uType = STRRET_TYPE.CSTR })
            {

                recycleBin.GetDisplayNameOf(pidl, 0, ret);
                str = ret.ToString(pidl);
            }


            // Some condition to include/exclude...
            if (pids.Count < 10)
            {
                Console.WriteLine(str);
                pids.Add(pidl);
            }
            else
            {
                Marshal.FreeCoTaskMem(pidl.Ptr);
            }
        }

        var pids2 = pids.ToArray();

        object cmTemp;
        recycleBin.GetUIObjectOf(IntPtr.Zero, pids2.Length, pids2, typeof(IContextMenu).GUID, IntPtr.Zero, 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);
        }
    }
}
xanatos
  • 109,618
  • 12
  • 197
  • 280
0

First of all add System.Runtime.InteropService to your project. We will use SHEmptyRecycleBin method, which accepts 3 parameters. After that import the Shell32.dll in your class by using DllImport.

[DllImport("Shell32.dll")]
static extern int SHEmptyRecycleBin(IntPtr hwnd, string pszRootPath, RecycleFlag dwFlags);

Then define an enum for the RecycleBin flags(dwFlags). The values are in Hexadecimal.

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

Place the following code in empty recycle bin button which calls the system method in Shell32.dll as:

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

reference: here

Shaminder Singh
  • 1,283
  • 2
  • 18
  • 31
  • thank you for your answer,but I don't want to empty the recyclebin,I just want to delete files selected. – roy Mar 16 '17 at 08:24