22using Files . Common ;
33using Files . Enums ;
44using Files . Helpers ;
5- using Files . Interacts ;
65using Files . Views . Pages ;
76using Microsoft . Toolkit . Uwp . UI ;
87using System ;
1615using System . Threading ;
1716using System . Threading . Tasks ;
1817using Windows . ApplicationModel . Core ;
18+ using Windows . Foundation ;
1919using Windows . Foundation . Collections ;
2020using Windows . Storage ;
2121using Windows . Storage . FileProperties ;
22- using Windows . Storage . Search ;
2322using Windows . UI . Core ;
2423using Windows . UI . Text ;
2524using Windows . UI . Xaml ;
@@ -34,8 +33,10 @@ namespace Files.Filesystem
3433{
3534 public class ItemViewModel : INotifyPropertyChanged , IDisposable
3635 {
37- private volatile bool IsWatching = false ;
36+ private volatile bool MustTryToWatchAgain = false ;
37+ private static SemaphoreSlim semaphoreSlim = new SemaphoreSlim ( 1 , 1 ) ;
3838 private IntPtr hWatchDir ;
39+ private IAsyncAction aWatcherAction ;
3940 public ReadOnlyObservableCollection < ListedItem > FilesAndFolders { get ; }
4041 public ListedItem CurrentFolder { get ; private set ; }
4142 public CollectionViewSource viewSource ;
@@ -364,11 +365,9 @@ private void WorkingDirectoryChanged()
364365
365366 public void CancelLoadAndClearFiles ( )
366367 {
367- var x = CancelIo ( hWatchDir ) ;
368- CloseHandle ( hWatchDir ) ;
369- hWatchDir = new IntPtr ( - 1 ) ;
370- Debug . WriteLine ( "\n \n Watcher task aborted...\n \n " ) ; // Cancel directory item change watcher
371- IsWatching = false ;
368+ Debug . WriteLine ( "CancelLoadAndClearFiles" ) ;
369+ CloseWatcher ( ) ;
370+
372371 App . CurrentInstance . NavigationToolbar . CanRefresh = true ;
373372 if ( IsLoadingItems == false ) { return ; }
374373
@@ -383,12 +382,6 @@ public void CancelLoadAndClearFiles()
383382 }
384383 }
385384
386- public void CancelChangeWatcher ( )
387- {
388- var x = CancelIo ( hWatchDir ) ;
389- Debug . WriteLine ( "\n \n Watcher task aborted...\n \n " ) ;
390- }
391-
392385 public void OrderFiles ( )
393386 {
394387 if ( _filesAndFolders . Count == 0 )
@@ -632,10 +625,8 @@ public async void RapidAddItemsToCollectionAsync(string path)
632625 {
633626
634627 await EnumerateItemsFromStandardFolder ( path ) ;
635- if ( ! IsWatching )
636- {
637- WatchForDirectoryChanges ( path ) ;
638- }
628+ WatchForDirectoryChanges ( path ) ;
629+
639630 }
640631
641632 if ( FilesAndFolders . Count == 0 )
@@ -667,7 +658,22 @@ public async void RapidAddItemsToCollectionAsync(string path)
667658 }
668659 }
669660
670- private static SemaphoreSlim semaphoreSlim = new SemaphoreSlim ( 1 , 1 ) ;
661+ public void CloseWatcher ( )
662+ {
663+ if ( aWatcherAction != null )
664+ {
665+ aWatcherAction ? . Cancel ( ) ;
666+
667+ if ( aWatcherAction . Status != AsyncStatus . Started )
668+ {
669+ aWatcherAction = null ; // Prevent duplicate execution of this block
670+ Debug . WriteLine ( "watcher canceled" ) ;
671+ CancelIoEx ( hWatchDir , IntPtr . Zero ) ;
672+ Debug . WriteLine ( "watcher handle closed" ) ;
673+ CloseHandle ( hWatchDir ) ;
674+ }
675+ }
676+ }
671677
672678 public async Task EnumerateItemsFromSpecialFolder ( string path )
673679 {
@@ -851,124 +857,113 @@ public async Task EnumerateItemsFromStandardFolder(string path)
851857
852858 }
853859
854- private async void WatchForDirectoryChanges ( string path )
860+ private void WatchForDirectoryChanges ( string path )
855861 {
856- var uiThreadScheduler = TaskScheduler . FromCurrentSynchronizationContext ( ) ;
857- Task thrItem = null ;
858- IsWatching = true ;
862+ Debug . WriteLine ( "WatchForDirectoryChanges: {0}" , path ) ;
859863 hWatchDir = CreateFileFromApp ( path , 1 , 1 | 2 | 4 ,
860864 IntPtr . Zero , 3 , ( uint ) File_Attributes . BackupSemantics | ( uint ) File_Attributes . Overlapped , IntPtr . Zero ) ;
861865
862866 byte [ ] buff = new byte [ 4096 ] ;
863867
864- await Windows . System . Threading . ThreadPool . RunAsync ( ( x ) =>
865- {
866- buff = new byte [ 4096 ] ;
867- int notifyFilters = FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_FILE_NAME ;
868-
869- OVERLAPPED overlapped = new OVERLAPPED ( ) ;
870- overlapped . hEvent = CreateEvent ( IntPtr . Zero , false , false , null ) ;
871- const uint INFINITE = 0xFFFFFFFF ;
872-
873- while ( hWatchDir . ToInt64 ( ) != - 1 )
874- {
875-
876- unsafe
877- {
878- fixed ( byte * pBuff = buff )
879- {
880- ref var notifyInformation = ref Unsafe . As < byte , FILE_NOTIFY_INFORMATION > ( ref buff [ 0 ] ) ;
881- try
882- {
883- NativeDirectoryChangesHelper . ReadDirectoryChangesW ( hWatchDir , pBuff ,
884- 4096 , false ,
885- notifyFilters , null ,
886- ref overlapped , null ) ;
887- }
888- catch ( Exception )
889- {
890- return ;
891- }
892-
893- var rc = WaitForSingleObjectEx ( overlapped . hEvent , INFINITE , true ) ;
894-
895- const uint FILE_ACTION_ADDED = 0x00000001 ;
896- const uint FILE_ACTION_REMOVED = 0x00000002 ;
897- const uint FILE_ACTION_MODIFIED = 0x00000003 ;
898- const uint FILE_ACTION_RENAMED_OLD_NAME = 0x00000004 ;
899- const uint FILE_ACTION_RENAMED_NEW_NAME = 0x00000005 ;
900-
901- uint offset = 0 ;
902- ref var notifyInfo = ref Unsafe . As < byte , FILE_NOTIFY_INFORMATION > ( ref buff [ offset ] ) ;
903- do
904- {
905- notifyInfo = ref Unsafe . As < byte , FILE_NOTIFY_INFORMATION > ( ref buff [ offset ] ) ;
906- string FileName = null ;
907- unsafe
908- {
909- fixed ( char * name = notifyInfo . FileName )
910- {
911- FileName = Path . Combine ( path , new string ( name , 0 , ( int ) notifyInfo . FileNameLength / 2 ) ) ;
912- }
913- }
914-
915- uint action = notifyInfo . Action ;
916- //await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
917- // () =>
918- // {
919- switch ( action )
920- {
921- case FILE_ACTION_ADDED :
922- if ( ! FilesAndFolders . Select ( x => x . ItemPath ) . Contains ( FileName ) )
923- {
924- AddFileOrFolder ( FileName ) ;
925- Debug . WriteLine ( "File " + FileName + " added to working directory." ) ;
926- }
927- break ;
928- case FILE_ACTION_REMOVED :
929- if ( FilesAndFolders . Select ( x => x . ItemPath ) . Contains ( FileName ) )
930- {
931- RemoveFileOrFolder ( FilesAndFolders . First ( x => x . ItemPath . Equals ( FileName ) ) ) ;
932- Debug . WriteLine ( "File " + FileName + " removed from working directory." ) ;
933- }
934- break ;
935- case FILE_ACTION_MODIFIED :
936- Debug . WriteLine ( "File " + FileName + " had attributes modified in the working directory." ) ;
937- break ;
938- case FILE_ACTION_RENAMED_OLD_NAME :
939- if ( FilesAndFolders . Select ( x => x . ItemPath ) . Contains ( FileName ) )
940- {
941- RemoveFileOrFolder ( FilesAndFolders . First ( x => x . ItemPath . Equals ( FileName ) ) ) ;
942- Debug . WriteLine ( "File " + FileName + " will be renamed in the working directory." ) ;
943- }
944- break ;
945- case FILE_ACTION_RENAMED_NEW_NAME :
946- if ( ! FilesAndFolders . Select ( x => x . ItemPath ) . Contains ( FileName ) )
947- {
948- AddFileOrFolder ( FileName ) ;
949- Debug . WriteLine ( "File " + FileName + " was renamed in the working directory." ) ;
950- }
951- break ;
952- default :
953- Debug . WriteLine ( "File " + FileName + " performed an action in the working directory." ) ;
954- break ;
955- }
956- //});
957- offset += notifyInfo . NextEntryOffset ;
958-
959- } while ( notifyInfo . NextEntryOffset != 0 ) ;
960-
961- //ResetEvent(overlapped.hEvent);
962- Debug . WriteLine ( "\n \n Task running...\n \n " ) ;
963- }
964- }
965- }
966- } ) ;
967-
968- Debug . WriteLine ( "\n \n Task exiting...\n \n " ) ;
969-
970- IsWatching = false ;
971-
868+ aWatcherAction = Windows . System . Threading . ThreadPool . RunAsync ( ( x ) =>
869+ {
870+ var rand = Guid . NewGuid ( ) ;
871+ buff = new byte [ 4096 ] ;
872+ int notifyFilters = FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_FILE_NAME ;
873+
874+ OVERLAPPED overlapped = new OVERLAPPED ( ) ;
875+ overlapped . hEvent = CreateEvent ( IntPtr . Zero , false , false , null ) ;
876+ const uint INFINITE = 0xFFFFFFFF ;
877+
878+ while ( x . Status != AsyncStatus . Canceled )
879+ {
880+ unsafe
881+ {
882+ fixed ( byte * pBuff = buff )
883+ {
884+ ref var notifyInformation = ref Unsafe . As < byte , FILE_NOTIFY_INFORMATION > ( ref buff [ 0 ] ) ;
885+ if ( x . Status != AsyncStatus . Canceled )
886+ {
887+ NativeDirectoryChangesHelper . ReadDirectoryChangesW ( hWatchDir , pBuff ,
888+ 4096 , false ,
889+ notifyFilters , null ,
890+ ref overlapped , null ) ;
891+ }
892+ else
893+ {
894+ break ;
895+ }
896+
897+ Debug . WriteLine ( "waiting: {0}" , rand ) ;
898+ if ( x . Status == AsyncStatus . Canceled ) { break ; }
899+ var rc = WaitForSingleObjectEx ( overlapped . hEvent , INFINITE , true ) ;
900+ Debug . WriteLine ( "wait done: {0}" , rand ) ;
901+
902+ const uint FILE_ACTION_ADDED = 0x00000001 ;
903+ const uint FILE_ACTION_REMOVED = 0x00000002 ;
904+ const uint FILE_ACTION_MODIFIED = 0x00000003 ;
905+ const uint FILE_ACTION_RENAMED_OLD_NAME = 0x00000004 ;
906+ const uint FILE_ACTION_RENAMED_NEW_NAME = 0x00000005 ;
907+
908+ uint offset = 0 ;
909+ ref var notifyInfo = ref Unsafe . As < byte , FILE_NOTIFY_INFORMATION > ( ref buff [ offset ] ) ;
910+ if ( x . Status == AsyncStatus . Canceled ) { break ; }
911+
912+ do
913+ {
914+ notifyInfo = ref Unsafe . As < byte , FILE_NOTIFY_INFORMATION > ( ref buff [ offset ] ) ;
915+ string FileName = null ;
916+ unsafe
917+ {
918+ fixed ( char * name = notifyInfo . FileName )
919+ {
920+ FileName = Path . Combine ( path , new string ( name , 0 , ( int ) notifyInfo . FileNameLength / 2 ) ) ;
921+ }
922+ }
923+
924+ uint action = notifyInfo . Action ;
925+
926+ Debug . WriteLine ( "action: {0}" , action ) ;
927+ switch ( action )
928+ {
929+ case FILE_ACTION_ADDED :
930+ AddFileOrFolder ( FileName ) ;
931+ Debug . WriteLine ( "File " + FileName + " added to working directory." ) ;
932+ break ;
933+ case FILE_ACTION_REMOVED :
934+ RemoveFileOrFolder ( FilesAndFolders . ToList ( ) . First ( x => x . ItemPath . Equals ( FileName ) ) ) ;
935+ Debug . WriteLine ( "File " + FileName + " removed from working directory." ) ;
936+ break ;
937+ case FILE_ACTION_MODIFIED :
938+ Debug . WriteLine ( "File " + FileName + " had attributes modified in the working directory." ) ;
939+ break ;
940+ case FILE_ACTION_RENAMED_OLD_NAME :
941+ RemoveFileOrFolder ( FilesAndFolders . ToList ( ) . First ( x => x . ItemPath . Equals ( FileName ) ) ) ;
942+ Debug . WriteLine ( "File " + FileName + " will be renamed in the working directory." ) ;
943+ break ;
944+ case FILE_ACTION_RENAMED_NEW_NAME :
945+ AddFileOrFolder ( FileName ) ;
946+ Debug . WriteLine ( "File " + FileName + " was renamed in the working directory." ) ;
947+ break ;
948+ default :
949+ Debug . WriteLine ( "File " + FileName + " performed an action in the working directory." ) ;
950+ break ;
951+ }
952+
953+ offset += notifyInfo . NextEntryOffset ;
954+
955+ } while ( notifyInfo . NextEntryOffset != 0 && x . Status != AsyncStatus . Canceled ) ;
956+
957+ //ResetEvent(overlapped.hEvent);
958+ Debug . WriteLine ( "Task running..." ) ;
959+ }
960+ }
961+ }
962+ CloseHandle ( overlapped . hEvent ) ;
963+ Debug . WriteLine ( "aWatcherAction done: {0}" , rand ) ;
964+ } ) ;
965+
966+ Debug . WriteLine ( "Task exiting..." ) ;
972967 }
973968
974969 public void AddFileOrFolder ( ListedItem item )
@@ -1166,7 +1161,7 @@ private async Task AddFolder(StorageFolder folder)
11661161 IsLoadingItems = false ;
11671162 return ;
11681163 }
1169-
1164+
11701165 _filesAndFolders . Add ( new ListedItem ( folder . FolderRelativeId )
11711166 {
11721167 //FolderTooltipText = tooltipString,
@@ -1290,6 +1285,7 @@ public void Dispose()
12901285 {
12911286 _addFilesCTS ? . Dispose ( ) ;
12921287 _semaphoreCTS ? . Dispose ( ) ;
1288+ CloseWatcher ( ) ;
12931289 }
12941290 }
1295- }
1291+ }
0 commit comments