14
14
using System . Diagnostics ;
15
15
using System . IO ;
16
16
using System . Linq ;
17
+ using System . Runtime . InteropServices ;
17
18
using System . Threading ;
18
19
using System . Threading . Tasks ;
20
+ using Vanara . PInvoke ;
19
21
using Windows . ApplicationModel . DataTransfer ;
20
22
using Windows . Graphics . Imaging ;
21
23
using Windows . Storage ;
24
+ using Windows . Storage . Streams ;
25
+ using FileAttributes = System . IO . FileAttributes ;
22
26
23
27
namespace Files . App . Filesystem
24
28
{
@@ -733,7 +737,7 @@ public async Task<ReturnResult> RecycleItemsFromClipboard(DataPackageView packag
733
737
734
738
public static bool HasDraggedStorageItems ( DataPackageView packageView )
735
739
{
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 ) ;
737
741
}
738
742
739
743
public static async Task < bool > CheckDragNeedsFulltrust ( DataPackageView packageView )
@@ -761,6 +765,7 @@ public static async Task<bool> CheckDragNeedsFulltrust(DataPackageView packageVi
761
765
public static async Task < IEnumerable < IStorageItemWithPath > > GetDraggedStorageItems ( DataPackageView packageView )
762
766
{
763
767
var itemsList = new List < IStorageItemWithPath > ( ) ;
768
+
764
769
if ( packageView . Contains ( StandardDataFormats . StorageItems ) )
765
770
{
766
771
try
@@ -778,13 +783,58 @@ public static async Task<IEnumerable<IStorageItemWithPath>> GetDraggedStorageIte
778
783
return itemsList ;
779
784
}
780
785
}
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" ) )
782
790
{
783
- if ( data is List < IStorageItemWithPath > source )
791
+ var fileDropData = await packageView . GetDataAsync ( "FileDrop" ) ;
792
+ if ( fileDropData is IRandomAccessStream stream )
784
793
{
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
+ }
786
835
}
787
836
}
837
+
788
838
itemsList = itemsList . DistinctBy ( x => string . IsNullOrEmpty ( x . Path ) ? x . Item . Name : x . Path ) . ToList ( ) ;
789
839
return itemsList ;
790
840
}
0 commit comments