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