|
6 | 6 | using Windows.Win32;
|
7 | 7 | using Windows.Win32.Foundation;
|
8 | 8 | using Windows.Win32.UI.Shell;
|
| 9 | +using static Vanara.PInvoke.Ole32; |
9 | 10 |
|
10 | 11 | namespace Files.App.Services
|
11 | 12 | {
|
@@ -68,68 +69,76 @@ public async Task<bool> CanGoTrashBin(string? path)
|
68 | 69 | }
|
69 | 70 |
|
70 | 71 | /// <inheritdoc/>
|
71 |
| - public async Task<bool> EmptyTrashBin() |
| 72 | + public bool EmptyTrashBin() |
72 | 73 | {
|
73 |
| - return await Win32Helper.StartSTATask(async () => |
| 74 | + // TODO: Use IFileOperation instead of its wrapper for the operation status to be reported. |
| 75 | + var fRes = PInvoke.SHEmptyRecycleBin( |
| 76 | + new(), |
| 77 | + string.Empty, |
| 78 | + 0x00000001 | 0x00000002 /* SHERB_NOCONFIRMATION | SHERB_NOPROGRESSUI */) |
| 79 | + .Succeeded; |
| 80 | + |
| 81 | + return fRes; |
| 82 | + } |
| 83 | + |
| 84 | + /// <inheritdoc/> |
| 85 | + public async Task<bool> RestoreAllTrashesAsync() |
| 86 | + { |
| 87 | + return await Win32Helper.StartSTATask(() => |
74 | 88 | {
|
75 | 89 | try
|
76 | 90 | {
|
77 |
| - HRESULT hr = default; |
78 |
| - IChildFolder recycleBinFolder = new WindowsFolder(PInvoke.FOLDERID_RecycleBinFolder); |
79 |
| - using var bulkOperations = new WindowsBulkOperations(new(MainWindow.Instance.WindowHandle), FILEOPERATION_FLAGS.FOF_NO_UI); |
80 |
| - |
81 |
| - await foreach (WindowsStorable item in recycleBinFolder.GetItemsAsync()) |
82 |
| - hr = bulkOperations.QueueDeleteOperation(item).ThrowIfFailedOnDebug(); |
83 |
| - |
84 |
| - // Perform the operations queued |
85 |
| - hr = bulkOperations.PerformAllOperations().ThrowIfFailedOnDebug(); |
86 |
| - |
87 |
| - // Update the RecycleBin folder icon |
88 |
| - PInvoke.SHUpdateRecycleBinIcon(); |
| 91 | + RestoreAllTrashesInternal(); |
89 | 92 |
|
90 | 93 | return true;
|
91 | 94 | }
|
92 |
| - catch (COMException ex) |
| 95 | + catch |
93 | 96 | {
|
94 |
| - App.Logger.LogWarning(ex, ex.Message); |
95 | 97 | return false;
|
96 | 98 | }
|
97 | 99 | });
|
98 | 100 | }
|
99 | 101 |
|
100 |
| - /// <inheritdoc/> |
101 |
| - public async Task<bool> RestoreAllTrashesAsync() |
| 102 | + private unsafe bool RestoreAllTrashesInternal() |
102 | 103 | {
|
103 |
| - return await Win32Helper.StartSTATask(async () => |
| 104 | + // Get IShellItem for Recycle Bin folder |
| 105 | + using ComPtr<IShellItem> pRecycleBinFolderShellItem = default; |
| 106 | + HRESULT hr = PInvoke.SHGetKnownFolderItem(FOLDERID.FOLDERID_RecycleBinFolder, KNOWN_FOLDER_FLAG.KF_FLAG_DEFAULT, HANDLE.Null, IID.IID_IShellItem, (void**)pRecycleBinFolderShellItem.GetAddressOf()); |
| 107 | + |
| 108 | + // Get IEnumShellItems for Recycle Bin folder |
| 109 | + using ComPtr<IEnumShellItems> pEnumShellItems = default; |
| 110 | + hr = pRecycleBinFolderShellItem.Get()->BindToHandler(null, BHID.BHID_EnumItems, IID.IID_IEnumShellItems, (void**)pEnumShellItems.GetAddressOf()); |
| 111 | + |
| 112 | + // Initialize how to perform the operation |
| 113 | + using ComPtr<IFileOperation> pFileOperation = default; |
| 114 | + hr = PInvoke.CoCreateInstance(CLSID.CLSID_FileOperation, null, CLSCTX.CLSCTX_LOCAL_SERVER, IID.IID_IFileOperation, (void**)pFileOperation.GetAddressOf()); |
| 115 | + hr = pFileOperation.Get()->SetOperationFlags(FILEOPERATION_FLAGS.FOF_NO_UI); |
| 116 | + hr = pFileOperation.Get()->SetOwnerWindow(new(MainWindow.Instance.WindowHandle)); |
| 117 | + |
| 118 | + using ComPtr<IShellItem> pShellItem = default; |
| 119 | + while (pEnumShellItems.Get()->Next(1, pShellItem.GetAddressOf()) == HRESULT.S_OK) |
104 | 120 | {
|
105 |
| - try |
106 |
| - { |
107 |
| - HRESULT hr = default; |
108 |
| - IChildFolder recycleBinFolder = new WindowsFolder(PInvoke.FOLDERID_RecycleBinFolder); |
109 |
| - using var bulkOperations = new WindowsBulkOperations(new(MainWindow.Instance.WindowHandle), FILEOPERATION_FLAGS.FOF_NO_UI); |
| 121 | + // Get the original path |
| 122 | + using ComPtr<IShellItem2> pShellItem2 = default; |
| 123 | + hr = pShellItem.Get()->QueryInterface(IID.IID_IShellItem2, (void**)pShellItem2.GetAddressOf()); |
| 124 | + hr = PInvoke.PSGetPropertyKeyFromName("System.Recycle.DeletedFrom", out var originalPathPropertyKey); |
| 125 | + hr = pShellItem2.Get()->GetString(originalPathPropertyKey, out var szOriginalPath); |
110 | 126 |
|
111 |
| - await foreach (WindowsStorable item in recycleBinFolder.GetItemsAsync()) |
112 |
| - { |
113 |
| - item.GetPropertyValue("System.Recycle.DeletedFrom", out string originalLocationFolderPath); |
| 127 | + // Get IShellItem of the original path |
| 128 | + hr = PInvoke.SHCreateItemFromParsingName(szOriginalPath.ToString(), null, typeof(IShellItem).GUID, out var pOriginalPathShellItemPtr); |
| 129 | + var pOriginalPathShellItem = (IShellItem*)pOriginalPathShellItemPtr; |
114 | 130 |
|
115 |
| - if (WindowsStorable.TryParse(originalLocationFolderPath) is WindowsFolder originalLocationFolder) |
116 |
| - hr = bulkOperations.QueueMoveOperation(item, originalLocationFolder, null).ThrowIfFailedOnDebug(); |
117 |
| - } |
| 131 | + // Define the shell item to restore |
| 132 | + hr = pFileOperation.Get()->MoveItem(pShellItem.Get(), pOriginalPathShellItem, default(PCWSTR), null); |
| 133 | + } |
118 | 134 |
|
119 |
| - // Perform the operations queued |
120 |
| - hr = bulkOperations.PerformAllOperations().ThrowIfFailedOnDebug(); |
| 135 | + // Perform |
| 136 | + hr = pFileOperation.Get()->PerformOperations(); |
121 | 137 |
|
122 |
| - // Update the RecycleBin folder icon |
123 |
| - PInvoke.SHUpdateRecycleBinIcon(); |
| 138 | + // Reset the icon |
| 139 | + Win32PInvoke.SHUpdateRecycleBinIcon(); |
124 | 140 |
|
125 |
| - return true; |
126 |
| - } |
127 |
| - catch (COMException ex) |
128 |
| - { |
129 |
| - App.Logger.LogWarning(ex, ex.Message); |
130 |
| - return false; |
131 |
| - } |
132 |
| - }); |
| 141 | + return true; |
133 | 142 | }
|
134 | 143 | }
|
135 | 144 | }
|
0 commit comments