Vanara/Windows.Shell.Common/RecycleBin.cs

119 lines
6.4 KiB
C#

using System.Collections.Generic;
using System.IO;
using System.Linq;
using Vanara.PInvoke;
using static Vanara.PInvoke.Shell32;
namespace Vanara.Windows.Shell;
/// <summary>A static object that represents the system Recycle Bin.</summary>
public static class RecycleBin
{
private static ShellFolder? recycleBin;
/// <summary>Gets the count of the items in the Recycle Bin. Depending on the number of items, this can take some time.</summary>
/// <value>The number of items.</value>
public static long Count => GetInfo().i64NumItems;
/// <summary>Gets the underlying <see cref="ShellFolder"/> instance.</summary>
/// <value>The <see cref="ShellFolder"/> instance.</value>
public static ShellFolder ShellFolderInstance => recycleBin ??= new ShellFolder(KNOWNFOLDERID.FOLDERID_RecycleBinFolder);
/// <summary>Gets the total size of all items in the Recycle Bin.</summary>
/// <value>The total size of all items in the Recycle Bin.</value>
public static long Size => GetInfo().i64Size;
/// <summary>Deletes the specified file or directory to the Recycle Bin.</summary>
/// <param name="path">The full path of the file or directory.</param>
/// <param name="hideUI"><see langword="true"/> to hide all user interface interactions; <see langword="false"/> to allow them.</param>
public static void DeleteToRecycleBin(string path, bool hideUI = false) => ShellFileOperations.Delete(path, GetDeleteOpFlags(hideUI));
/// <summary>Deletes the specified files or directories to the Recycle Bin.</summary>
/// <param name="paths">The full paths of the file or directory.</param>
/// <param name="hideUI"><see langword="true"/> to hide all user interface interactions; <see langword="false"/> to allow them.</param>
public static void DeleteToRecycleBin(IEnumerable<string> paths, bool hideUI = false) => ShellFileOperations.Delete(paths.Select(p => new ShellItem(p)), GetDeleteOpFlags(hideUI));
/// <summary>Empties the Recycle Bin.</summary>
/// <param name="hideUI"><see langword="true"/> to hide all user interface interactions; <see langword="false"/> to allow them.</param>
/// <param name="noConfirmation">
/// <see langword="true"/> to indicate that no dialog box confirming the deletion of the objects will be displayed; <see
/// langword="false"/> otherwise.
/// </param>
/// <param name="noSound">if set to <see langword="true"/> no sound will be played when the operation is complete.</param>
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();
}
/// <summary>Gets the <see cref="ShellItem"/> in the Recycle Bin from the path of originally deleted file or directory.</summary>
/// <param name="itemPath">The deleted items full original path.</param>
/// <returns>
/// The <see cref="ShellItem"/> matching the item specified in <paramref name="itemPath"/> or <see langword="null"/> if not found.
/// </returns>
public static ShellItem? GetItemFromOriginalPath(string itemPath) => GetItems().FirstOrDefault(i => string.Equals(i.Name, itemPath, StringComparison.OrdinalIgnoreCase));
/// <summary>Gets all the <see cref="ShellItem"/> references at the top level of the Recycle Bin.</summary>
/// <returns>A sequence of <see cref="ShellItem"/> objects at the top level of the Recycle Bin.</returns>
public static IEnumerable<ShellItem> GetItems() => ShellFolderInstance;
/// <summary>Restores the specified deleted item to it's original location.</summary>
/// <param name="deletedItem">
/// The <see cref="ShellItem"/> of the deleted item in the Recycle Bin. This cannot be a reference to an undeleted shell item.
/// </param>
/// <param name="hideUI"><see langword="true"/> to hide all user interface interactions; <see langword="false"/> to allow them.</param>
public static void Restore(ShellItem deletedItem, bool hideUI = false) => Restore(new[] { deletedItem }, hideUI);
/// <summary>Restores the specified deleted items to their original location.</summary>
/// <param name="deletedItems">
/// A sequence of <see cref="ShellItem"/> objects in the Recycle Bin. These cannot be a references to undeleted shell items.
/// </param>
/// <param name="hideUI"><see langword="true"/> to hide all user interface interactions; <see langword="false"/> to allow them.</param>
public static void Restore(IEnumerable<ShellItem> 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.");
// Manually create a ShellFolder instance to the original location.
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;
}
/// <summary>Restores all items in the Recycle Bin to their original location.</summary>
/// <param name="hideUI"><see langword="true"/> to hide all user interface interactions; <see langword="false"/> to allow them.</param>
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 (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;
}
}