1616using System . Threading ;
1717using System . Threading . Tasks ;
1818using Windows . ApplicationModel . Core ;
19+ using Windows . Foundation ;
1920using Windows . Foundation . Collections ;
2021using Windows . Storage ;
2122using Windows . Storage . FileProperties ;
@@ -34,8 +35,10 @@ namespace Files.Filesystem
3435{
3536 public class ItemViewModel : INotifyPropertyChanged , IDisposable
3637 {
37- private volatile bool IsWatching = false ;
38+ private volatile bool MustTryToWatchAgain = false ;
39+ private static SemaphoreSlim semaphoreSlim = new SemaphoreSlim ( 1 , 1 ) ;
3840 private IntPtr hWatchDir ;
41+ private IAsyncAction aWatcherAction ;
3942 public ReadOnlyObservableCollection < ListedItem > FilesAndFolders { get ; }
4043 public ListedItem CurrentFolder { get ; private set ; }
4144 public CollectionViewSource viewSource ;
@@ -364,11 +367,16 @@ private void WorkingDirectoryChanged()
364367
365368 public void CancelLoadAndClearFiles ( )
366369 {
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 ;
370+ if ( aWatcherAction != null )
371+ {
372+ aWatcherAction ? . Cancel ( ) ;
373+
374+ if ( aWatcherAction . Status != AsyncStatus . Started )
375+ {
376+ CloseWatcher ( ) ;
377+ }
378+ }
379+
372380 App . CurrentInstance . NavigationToolbar . CanRefresh = true ;
373381 if ( IsLoadingItems == false ) { return ; }
374382
@@ -383,12 +391,6 @@ public void CancelLoadAndClearFiles()
383391 }
384392 }
385393
386- public void CancelChangeWatcher ( )
387- {
388- var x = CancelIo ( hWatchDir ) ;
389- Debug . WriteLine ( "\n \n Watcher task aborted...\n \n " ) ;
390- }
391-
392394 public void OrderFiles ( )
393395 {
394396 if ( _filesAndFolders . Count == 0 )
@@ -632,10 +634,8 @@ public async void RapidAddItemsToCollectionAsync(string path)
632634 {
633635
634636 await EnumerateItemsFromStandardFolder ( path ) ;
635- if ( ! IsWatching )
636- {
637- WatchForDirectoryChanges ( path ) ;
638- }
637+ WatchForDirectoryChanges ( path ) ;
638+
639639 }
640640
641641 if ( FilesAndFolders . Count == 0 )
@@ -667,7 +667,11 @@ public async void RapidAddItemsToCollectionAsync(string path)
667667 }
668668 }
669669
670- private static SemaphoreSlim semaphoreSlim = new SemaphoreSlim ( 1 , 1 ) ;
670+ public void CloseWatcher ( )
671+ {
672+ CancelIo ( hWatchDir ) ;
673+ //CloseHandle(hWatchDir);
674+ }
671675
672676 public async Task EnumerateItemsFromSpecialFolder ( string path )
673677 {
@@ -851,113 +855,108 @@ public async Task EnumerateItemsFromStandardFolder(string path)
851855
852856 }
853857
854- private async void WatchForDirectoryChanges ( string path )
858+ private void WatchForDirectoryChanges ( string path )
855859 {
856- var uiThreadScheduler = TaskScheduler . FromCurrentSynchronizationContext ( ) ;
857- Task thrItem = null ;
858- IsWatching = true ;
860+
859861 hWatchDir = CreateFileFromApp ( path , 1 , 1 | 2 | 4 ,
860862 IntPtr . Zero , 3 , ( uint ) File_Attributes . BackupSemantics | ( uint ) File_Attributes . Overlapped , IntPtr . Zero ) ;
861863
862864 byte [ ] buff = new byte [ 4096 ] ;
863865
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 ;
866+ aWatcherAction = Windows . System . Threading . ThreadPool . RunAsync ( ( x ) =>
867+ {
868868
869- OVERLAPPED overlapped = new OVERLAPPED ( ) ;
870- overlapped . hEvent = CreateEvent ( IntPtr . Zero , false , false , null ) ;
871- const uint INFINITE = 0xFFFFFFFF ;
869+ buff = new byte [ 4096 ] ;
870+ int notifyFilters = FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_FILE_NAME ;
872871
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- if ( hWatchDir . ToInt64 ( ) != - 1 )
872+ OVERLAPPED overlapped = new OVERLAPPED ( ) ;
873+ overlapped . hEvent = CreateEvent ( IntPtr . Zero , false , false , null ) ;
874+ const uint INFINITE = 0xFFFFFFFF ;
875+
876+ while ( x . Status != AsyncStatus . Canceled )
877+ {
878+ unsafe
879+ {
880+ fixed ( byte * pBuff = buff )
881+ {
882+ ref var notifyInformation = ref Unsafe . As < byte , FILE_NOTIFY_INFORMATION > ( ref buff [ 0 ] ) ;
883+ if ( x . Status != AsyncStatus . Canceled )
882884 {
883885 NativeDirectoryChangesHelper . ReadDirectoryChangesW ( hWatchDir , pBuff ,
884886 4096 , false ,
885887 notifyFilters , null ,
886888 ref overlapped , null ) ;
887- }
888- else
889- {
890- IsWatching = false ;
891- return ;
892- }
893-
894- var rc = WaitForSingleObjectEx ( overlapped . hEvent , INFINITE , true ) ;
895-
896- const uint FILE_ACTION_ADDED = 0x00000001 ;
897- const uint FILE_ACTION_REMOVED = 0x00000002 ;
898- const uint FILE_ACTION_MODIFIED = 0x00000003 ;
899- const uint FILE_ACTION_RENAMED_OLD_NAME = 0x00000004 ;
900- const uint FILE_ACTION_RENAMED_NEW_NAME = 0x00000005 ;
901-
902- uint offset = 0 ;
903- ref var notifyInfo = ref Unsafe . As < byte , FILE_NOTIFY_INFORMATION > ( ref buff [ offset ] ) ;
904- if ( hWatchDir . ToInt64 ( ) == - 1 ) { IsWatching = false ; return ; }
905-
906- do
907- {
908- notifyInfo = ref Unsafe . As < byte , FILE_NOTIFY_INFORMATION > ( ref buff [ offset ] ) ;
909- string FileName = null ;
910- unsafe
911- {
912- fixed ( char * name = notifyInfo . FileName )
913- {
914- FileName = Path . Combine ( path , new string ( name , 0 , ( int ) notifyInfo . FileNameLength / 2 ) ) ;
915- }
916- }
917-
918- uint action = notifyInfo . Action ;
919-
920- switch ( action )
921- {
922- case FILE_ACTION_ADDED :
923- AddFileOrFolder ( FileName ) ;
924- Debug . WriteLine ( "File " + FileName + " added to working directory." ) ;
925- break ;
926- case FILE_ACTION_REMOVED :
927- RemoveFileOrFolder ( FilesAndFolders . ToList ( ) . First ( x => x . ItemPath . Equals ( FileName ) ) ) ;
928- Debug . WriteLine ( "File " + FileName + " removed from working directory." ) ;
929- break ;
930- case FILE_ACTION_MODIFIED :
931- Debug . WriteLine ( "File " + FileName + " had attributes modified in the working directory." ) ;
932- break ;
933- case FILE_ACTION_RENAMED_OLD_NAME :
934- RemoveFileOrFolder ( FilesAndFolders . ToList ( ) . First ( x => x . ItemPath . Equals ( FileName ) ) ) ;
935- Debug . WriteLine ( "File " + FileName + " will be renamed in the working directory." ) ;
936- break ;
937- case FILE_ACTION_RENAMED_NEW_NAME :
938- AddFileOrFolder ( FileName ) ;
939- Debug . WriteLine ( "File " + FileName + " was renamed in the working directory." ) ;
940- break ;
941- default :
942- Debug . WriteLine ( "File " + FileName + " performed an action in the working directory." ) ;
943- break ;
944- }
945-
946- offset += notifyInfo . NextEntryOffset ;
947-
948- } while ( notifyInfo . NextEntryOffset != 0 && hWatchDir . ToInt64 ( ) != - 1 ) ;
889+ }
890+ else
891+ {
892+ return ;
893+ }
894+
895+ if ( x . Status == AsyncStatus . Canceled ) { return ; }
896+ var rc = WaitForSingleObjectEx ( overlapped . hEvent , INFINITE , true ) ;
897+
898+ const uint FILE_ACTION_ADDED = 0x00000001 ;
899+ const uint FILE_ACTION_REMOVED = 0x00000002 ;
900+ const uint FILE_ACTION_MODIFIED = 0x00000003 ;
901+ const uint FILE_ACTION_RENAMED_OLD_NAME = 0x00000004 ;
902+ const uint FILE_ACTION_RENAMED_NEW_NAME = 0x00000005 ;
903+
904+ uint offset = 0 ;
905+ ref var notifyInfo = ref Unsafe . As < byte , FILE_NOTIFY_INFORMATION > ( ref buff [ offset ] ) ;
906+ if ( x . Status == AsyncStatus . Canceled ) { return ; }
907+
908+ do
909+ {
910+ notifyInfo = ref Unsafe . As < byte , FILE_NOTIFY_INFORMATION > ( ref buff [ offset ] ) ;
911+ string FileName = null ;
912+ unsafe
913+ {
914+ fixed ( char * name = notifyInfo . FileName )
915+ {
916+ FileName = Path . Combine ( path , new string ( name , 0 , ( int ) notifyInfo . FileNameLength / 2 ) ) ;
917+ }
918+ }
919+
920+ uint action = notifyInfo . Action ;
921+
922+ switch ( action )
923+ {
924+ case FILE_ACTION_ADDED :
925+ AddFileOrFolder ( FileName ) ;
926+ Debug . WriteLine ( "File " + FileName + " added to working directory." ) ;
927+ break ;
928+ case FILE_ACTION_REMOVED :
929+ RemoveFileOrFolder ( FilesAndFolders . ToList ( ) . First ( x => x . ItemPath . Equals ( FileName ) ) ) ;
930+ Debug . WriteLine ( "File " + FileName + " removed from working directory." ) ;
931+ break ;
932+ case FILE_ACTION_MODIFIED :
933+ Debug . WriteLine ( "File " + FileName + " had attributes modified in the working directory." ) ;
934+ break ;
935+ case FILE_ACTION_RENAMED_OLD_NAME :
936+ RemoveFileOrFolder ( FilesAndFolders . ToList ( ) . First ( x => x . ItemPath . Equals ( FileName ) ) ) ;
937+ Debug . WriteLine ( "File " + FileName + " will be renamed in the working directory." ) ;
938+ break ;
939+ case FILE_ACTION_RENAMED_NEW_NAME :
940+ AddFileOrFolder ( FileName ) ;
941+ Debug . WriteLine ( "File " + FileName + " was renamed in the working directory." ) ;
942+ break ;
943+ default :
944+ Debug . WriteLine ( "File " + FileName + " performed an action in the working directory." ) ;
945+ break ;
946+ }
947+
948+ offset += notifyInfo . NextEntryOffset ;
949+
950+ } while ( notifyInfo . NextEntryOffset != 0 && x . Status != AsyncStatus . Canceled ) ;
949951
950952 //ResetEvent(overlapped.hEvent);
951953 Debug . WriteLine ( "\n \n Task running...\n \n " ) ;
952- }
953- }
954- }
955- } ) ;
954+ }
955+ }
956+ }
957+ } ) ;
956958
957959 Debug . WriteLine ( "\n \n Task exiting...\n \n " ) ;
958-
959- IsWatching = false ;
960-
961960 }
962961
963962 public void AddFileOrFolder ( ListedItem item )
0 commit comments