Skip to content

Commit c810e41

Browse files
authored
Fix: Fixed issue with dragging files to extract from archive (#10925)
1 parent 9d9b0d5 commit c810e41

File tree

1 file changed

+54
-4
lines changed

1 file changed

+54
-4
lines changed

src/Files.App/Filesystem/FilesystemOperations/Helpers/FilesystemHelpers.cs

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,15 @@
1414
using System.Diagnostics;
1515
using System.IO;
1616
using System.Linq;
17+
using System.Runtime.InteropServices;
1718
using System.Threading;
1819
using System.Threading.Tasks;
20+
using Vanara.PInvoke;
1921
using Windows.ApplicationModel.DataTransfer;
2022
using Windows.Graphics.Imaging;
2123
using Windows.Storage;
24+
using Windows.Storage.Streams;
25+
using FileAttributes = System.IO.FileAttributes;
2226

2327
namespace Files.App.Filesystem
2428
{
@@ -733,7 +737,7 @@ public async Task<ReturnResult> RecycleItemsFromClipboard(DataPackageView packag
733737

734738
public static bool HasDraggedStorageItems(DataPackageView packageView)
735739
{
736-
return packageView is not null && (packageView.Contains(StandardDataFormats.StorageItems) || (packageView.Properties.TryGetValue("FileDrop", out _)));
740+
return packageView is not null && packageView.Contains(StandardDataFormats.StorageItems);
737741
}
738742

739743
public static async Task<bool> CheckDragNeedsFulltrust(DataPackageView packageView)
@@ -761,6 +765,7 @@ public static async Task<bool> CheckDragNeedsFulltrust(DataPackageView packageVi
761765
public static async Task<IEnumerable<IStorageItemWithPath>> GetDraggedStorageItems(DataPackageView packageView)
762766
{
763767
var itemsList = new List<IStorageItemWithPath>();
768+
764769
if (packageView.Contains(StandardDataFormats.StorageItems))
765770
{
766771
try
@@ -778,13 +783,58 @@ public static async Task<IEnumerable<IStorageItemWithPath>> GetDraggedStorageIte
778783
return itemsList;
779784
}
780785
}
781-
if (packageView.Properties.TryGetValue("FileDrop", out var data))
786+
787+
// workaround for GetStorageItemsAsync() bug that only yields 16 items at most
788+
// https://learn.microsoft.com/en-us/windows/win32/shell/clipboard#cf_hdrop
789+
if (packageView.Contains("FileDrop"))
782790
{
783-
if (data is List<IStorageItemWithPath> source)
791+
var fileDropData = await packageView.GetDataAsync("FileDrop");
792+
if (fileDropData is IRandomAccessStream stream)
784793
{
785-
itemsList.AddRange(source);
794+
stream.Seek(0);
795+
796+
byte[] dropBytes = new byte[stream.Size];
797+
int bytesRead = await stream.AsStreamForRead().ReadAsync(dropBytes);
798+
799+
if (bytesRead > 0)
800+
{
801+
IntPtr dropStructPointer = Marshal.AllocHGlobal(dropBytes.Length);
802+
803+
try
804+
{
805+
Marshal.Copy(dropBytes, 0, dropStructPointer, dropBytes.Length);
806+
HDROP dropStructHandle = new(dropStructPointer);
807+
808+
var itemPaths = new List<string>();
809+
uint filesCount = Shell32.DragQueryFile(dropStructHandle, 0xffffffff, null, 0);
810+
for (uint i = 0; i < filesCount; i++)
811+
{
812+
uint charsNeeded = Shell32.DragQueryFile(dropStructHandle, i, null, 0);
813+
uint bufferSpaceRequired = charsNeeded + 1; // include space for terminating null character
814+
string buffer = new('\0', (int)bufferSpaceRequired);
815+
uint charsCopied = Shell32.DragQueryFile(dropStructHandle, i, buffer, bufferSpaceRequired);
816+
817+
if (charsCopied > 0)
818+
{
819+
string path = buffer[..(int)charsCopied];
820+
itemPaths.Add(path);
821+
}
822+
}
823+
824+
foreach (var path in itemPaths)
825+
{
826+
var isDirectory = NativeFileOperationsHelper.HasFileAttribute(path, FileAttributes.Directory);
827+
itemsList.Add(StorageHelpers.FromPathAndType(path, isDirectory ? FilesystemItemType.Directory : FilesystemItemType.File));
828+
}
829+
}
830+
finally
831+
{
832+
Marshal.FreeHGlobal(dropStructPointer);
833+
}
834+
}
786835
}
787836
}
837+
788838
itemsList = itemsList.DistinctBy(x => string.IsNullOrEmpty(x.Path) ? x.Item.Name : x.Path).ToList();
789839
return itemsList;
790840
}

0 commit comments

Comments
 (0)