using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; using Vanara.Extensions; using Vanara.PInvoke; using static Vanara.PInvoke.Shell32; namespace Vanara.Windows.Shell { /// A static object that represents the system Recycle Bin. public static class RecycleBin { private static ShellFolder recycleBin; /// Gets the count of the items in the Recycle Bin. Depending on the number of items, this can take some time. /// The number of items. public static long Count => GetInfo().i64NumItems; /// Gets the underlying instance. /// The instance. public static ShellFolder ShellFolderInstance => recycleBin ??= new ShellFolder(KNOWNFOLDERID.FOLDERID_RecycleBinFolder); /// Gets the total size of all items in the Recycle Bin. /// The total size of all items in the Recycle Bin. public static long Size => GetInfo().i64Size; /// Deletes the specified file or directory to the Recycle Bin. /// The full path of the file or directory. /// to hide all user interface interactions; to allow them. public static void DeleteToRecycleBin(string path, bool hideUI = false) => ShellFileOperations.Delete(path, GetDeleteOpFlags(hideUI)); /// Deletes the specified files or directories to the Recycle Bin. /// The full paths of the file or directory. /// to hide all user interface interactions; to allow them. public static void DeleteToRecycleBin(IEnumerable paths, bool hideUI = false) => ShellFileOperations.Delete(paths.Select(p => new ShellItem(p)), GetDeleteOpFlags(hideUI)); /// Empties the Recycle Bin. /// to hide all user interface interactions; to allow them. /// /// to indicate that no dialog box confirming the deletion of the objects will be displayed; otherwise. /// /// if set to no sound will be played when the operation is complete. public static void Empty(bool hideUI = true, bool noConfirmation = true, bool noSound = true) { var flags = (hideUI ? SHERB.SHERB_NOPROGRESSUI : 0) | (noConfirmation ? SHERB.SHERB_NOCONFIRMATION : 0) | (noSound ? SHERB.SHERB_NOSOUND : 0); SHEmptyRecycleBin(default, null, flags).ThrowIfFailed(); } /// Gets the in the Recycle Bin from the path of originally deleted file or directory. /// The deleted items full original path. /// /// The matching the item specified in or if not found. /// public static ShellItem GetItemFromOriginalPath(string itemPath) => GetItems().FirstOrDefault(i => string.Equals(i.Name, itemPath, StringComparison.OrdinalIgnoreCase)); /// Gets all the references at the top level of the Recycle Bin. /// A sequence of objects at the top level of the Recycle Bin. public static IEnumerable GetItems() => ShellFolderInstance; /// Restores the specified deleted item to it's original location. /// /// The of the deleted item in the Recycle Bin. This cannot be a reference to an undeleted shell item. /// /// to hide all user interface interactions; to allow them. public static void Restore(ShellItem deletedItem, bool hideUI = false) => Restore(new[] { deletedItem }, hideUI); /// Restores the specified deleted items to their original location. /// /// A sequence of objects in the Recycle Bin. These cannot be a references to undeleted shell items. /// /// to hide all user interface interactions; to allow them. public static void Restore(IEnumerable deletedItems, bool hideUI = false) { using var sop = new ShellFileOperations { Options = GetDeleteOpFlags(hideUI) }; HRESULT hr = HRESULT.S_OK; sop.PostMoveItem += OnPost; try { foreach (var item in deletedItems) { if (item.Parent != ShellFolderInstance) throw new InvalidOperationException("Unable to restore a ShellItem that is not in the Recycle Bin."); using var sf = new ShellFolder(Path.GetDirectoryName(item.Name)); sop.QueueMoveOperation(item, sf, Path.GetFileName(item.Name)); } sop.PerformOperations(); hr.ThrowIfFailed(); } finally { sop.PostMoveItem -= OnPost; // Call the undocumented function to reset the icon. On Win10, it won't do it on its own. try { SHUpdateRecycleBinIcon(); } catch { } } void OnPost(object sender, ShellFileOperations.ShellFileOpEventArgs e) => hr = e.Result; } /// Restores all items in the Recycle Bin to their original location. /// to hide all user interface interactions; to allow them. public static void RestoreAll(bool hideUI = false) => Restore(GetItems(), hideUI); private static ShellFileOperations.OperationFlags GetDeleteOpFlags(bool hideUI) { var flags = ShellFileOperations.OperationFlags.NoConfirmMkDir | ShellFileOperations.OperationFlags.AllowUndo; if (Vanara.PInvoke.PInvokeClient.Windows8.IsPlatformSupported()) flags |= ShellFileOperations.OperationFlags.AddUndoRecord | ShellFileOperations.OperationFlags.RecycleOnDelete; if (hideUI) flags |= ShellFileOperations.OperationFlags.Silent | ShellFileOperations.OperationFlags.NoErrorUI | ShellFileOperations.OperationFlags.NoConfirmation; return flags; } private static SHQUERYRBINFO GetInfo() { var qi = new SHQUERYRBINFO { cbSize = (uint)Marshal.SizeOf(typeof(SHQUERYRBINFO)) }; SHQueryRecycleBin(null, ref qi).ThrowIfFailed(); return qi; } } }