1414using System . Diagnostics ;
1515using System . IO ;
1616using System . Linq ;
17+ using System . Runtime . InteropServices ;
1718using System . Threading ;
1819using System . Threading . Tasks ;
20+ using Vanara . PInvoke ;
1921using Windows . ApplicationModel . DataTransfer ;
2022using Windows . Graphics . Imaging ;
2123using Windows . Storage ;
24+ using Windows . Storage . Streams ;
25+ using FileAttributes = System . IO . FileAttributes ;
2226
2327namespace 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