-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
Copy pathStorageTrashBinService.cs
143 lines (119 loc) · 4.46 KB
/
StorageTrashBinService.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Copyright (c) Files Community
// Licensed under the MIT License.
using System.Runtime.InteropServices;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.System.Com;
using Windows.Win32.UI.Shell;
namespace Files.App.Services
{
/// <inheritdoc cref="IStorageTrashBinService"/>
public class StorageTrashBinService : IStorageTrashBinService
{
/// <inheritdoc/>
public RecycleBinWatcher Watcher { get; private set; } = new();
/// <inheritdoc/>
public async Task<List<ShellFileItem>> GetAllRecycleBinFoldersAsync()
{
return (await Win32Helper.GetShellFolderAsync(Constants.UserEnvironmentPaths.RecycleBinPath, false, true, 0, int.MaxValue)).Enumerate;
}
/// <inheritdoc/>
public (bool HasRecycleBin, long NumItems, long BinSize) QueryRecycleBin(string drive = "")
{
SHQUERYRBINFO queryBinInfo = default;
queryBinInfo.cbSize = (uint)Marshal.SizeOf(queryBinInfo);
var hRes = PInvoke.SHQueryRecycleBin(drive, ref queryBinInfo);
return hRes == HRESULT.S_OK
? (true, queryBinInfo.i64NumItems, queryBinInfo.i64Size)
: (false, 0, 0);
}
/// <inheritdoc/>
public ulong GetSize()
{
return (ulong)QueryRecycleBin().BinSize;
}
/// <inheritdoc/>
public bool HasItems()
{
return QueryRecycleBin().NumItems > 0;
}
/// <inheritdoc/>
public bool IsUnderTrashBin(string? path)
{
return
!string.IsNullOrWhiteSpace(path) &&
RegexHelpers.RecycleBinPath().IsMatch(path);
}
/// <inheritdoc/>
public async Task<bool> CanGoTrashBin(string? path)
{
if (string.IsNullOrEmpty(path) ||
path.StartsWith(@"\\?\", StringComparison.Ordinal))
return false;
var result = await FileOperationsHelpers.TestRecycleAsync(path.Split('|'));
return
result.Item1 &= result.Item2 is not null &&
result.Item2.Items.All(x => x.Succeeded);
}
/// <inheritdoc/>
public bool EmptyTrashBin()
{
// TODO: Use IFileOperation instead of its wrapper for the operation status to be reported.
var fRes = PInvoke.SHEmptyRecycleBin(
new(),
string.Empty,
0x00000001 | 0x00000002 /* SHERB_NOCONFIRMATION | SHERB_NOPROGRESSUI */)
.Succeeded;
return fRes;
}
/// <inheritdoc/>
public async Task<bool> RestoreAllTrashesAsync()
{
return await Win32Helper.StartSTATask(() =>
{
try
{
RestoreAllTrashesInternal();
return true;
}
catch
{
return false;
}
});
}
private unsafe bool RestoreAllTrashesInternal()
{
// Get IShellItem for Recycle Bin folder
using ComPtr<IShellItem> pRecycleBinFolderShellItem = default;
HRESULT hr = PInvoke.SHGetKnownFolderItem(FOLDERID.FOLDERID_RecycleBinFolder, KNOWN_FOLDER_FLAG.KF_FLAG_DEFAULT, HANDLE.Null, IID.IID_IShellItem, (void**)pRecycleBinFolderShellItem.GetAddressOf());
// Get IEnumShellItems for Recycle Bin folder
using ComPtr<IEnumShellItems> pEnumShellItems = default;
hr = pRecycleBinFolderShellItem.Get()->BindToHandler(null, BHID.BHID_EnumItems, IID.IID_IEnumShellItems, (void**)pEnumShellItems.GetAddressOf());
// Initialize how to perform the operation
using ComPtr<IFileOperation> pFileOperation = default;
hr = PInvoke.CoCreateInstance(CLSID.CLSID_FileOperation, null, CLSCTX.CLSCTX_LOCAL_SERVER, IID.IID_IFileOperation, (void**)pFileOperation.GetAddressOf());
hr = pFileOperation.Get()->SetOperationFlags(FILEOPERATION_FLAGS.FOF_NO_UI);
hr = pFileOperation.Get()->SetOwnerWindow(new(MainWindow.Instance.WindowHandle));
using ComPtr<IShellItem> pShellItem = default;
while (pEnumShellItems.Get()->Next(1, pShellItem.GetAddressOf()) == HRESULT.S_OK)
{
// Get the original path
using ComPtr<IShellItem2> pShellItem2 = default;
hr = pShellItem.Get()->QueryInterface(IID.IID_IShellItem2, (void**)pShellItem2.GetAddressOf());
hr = PInvoke.PSGetPropertyKeyFromName("System.Recycle.DeletedFrom", out var originalPathPropertyKey);
hr = pShellItem2.Get()->GetString(originalPathPropertyKey, out var szOriginalPath);
// Get IShellItem of the original path
hr = PInvoke.SHCreateItemFromParsingName(szOriginalPath.ToString(), null, typeof(IShellItem).GUID, out var pOriginalPathShellItemPtr);
var pOriginalPathShellItem = (IShellItem*)pOriginalPathShellItemPtr;
// Define the shell item to restore
hr = pFileOperation.Get()->MoveItem(pShellItem.Get(), pOriginalPathShellItem, default(PCWSTR), null);
}
// Perform
hr = pFileOperation.Get()->PerformOperations();
// Reset the icon
Win32PInvoke.SHUpdateRecycleBinIcon();
return true;
}
}
}