2
2
using Files . Common ;
3
3
using Files . Enums ;
4
4
using Files . Helpers ;
5
- using Files . Interacts ;
6
5
using Files . Views . Pages ;
7
6
using Microsoft . Toolkit . Uwp . UI ;
8
7
using System ;
16
15
using System . Threading ;
17
16
using System . Threading . Tasks ;
18
17
using Windows . ApplicationModel . Core ;
18
+ using Windows . Foundation ;
19
19
using Windows . Foundation . Collections ;
20
20
using Windows . Storage ;
21
21
using Windows . Storage . FileProperties ;
22
- using Windows . Storage . Search ;
23
22
using Windows . UI . Core ;
24
23
using Windows . UI . Text ;
25
24
using Windows . UI . Xaml ;
@@ -34,8 +33,10 @@ namespace Files.Filesystem
34
33
{
35
34
public class ItemViewModel : INotifyPropertyChanged , IDisposable
36
35
{
37
- private volatile bool IsWatching = false ;
36
+ private volatile bool MustTryToWatchAgain = false ;
37
+ private static SemaphoreSlim semaphoreSlim = new SemaphoreSlim ( 1 , 1 ) ;
38
38
private IntPtr hWatchDir ;
39
+ private IAsyncAction aWatcherAction ;
39
40
public ReadOnlyObservableCollection < ListedItem > FilesAndFolders { get ; }
40
41
public ListedItem CurrentFolder { get ; private set ; }
41
42
public CollectionViewSource viewSource ;
@@ -364,11 +365,9 @@ private void WorkingDirectoryChanged()
364
365
365
366
public void CancelLoadAndClearFiles ( )
366
367
{
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
+
372
371
App . CurrentInstance . NavigationToolbar . CanRefresh = true ;
373
372
if ( IsLoadingItems == false ) { return ; }
374
373
@@ -383,12 +382,6 @@ public void CancelLoadAndClearFiles()
383
382
}
384
383
}
385
384
386
- public void CancelChangeWatcher ( )
387
- {
388
- var x = CancelIo ( hWatchDir ) ;
389
- Debug . WriteLine ( "\n \n Watcher task aborted...\n \n " ) ;
390
- }
391
-
392
385
public void OrderFiles ( )
393
386
{
394
387
if ( _filesAndFolders . Count == 0 )
@@ -632,10 +625,8 @@ public async void RapidAddItemsToCollectionAsync(string path)
632
625
{
633
626
634
627
await EnumerateItemsFromStandardFolder ( path ) ;
635
- if ( ! IsWatching )
636
- {
637
- WatchForDirectoryChanges ( path ) ;
638
- }
628
+ WatchForDirectoryChanges ( path ) ;
629
+
639
630
}
640
631
641
632
if ( FilesAndFolders . Count == 0 )
@@ -667,7 +658,22 @@ public async void RapidAddItemsToCollectionAsync(string path)
667
658
}
668
659
}
669
660
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
+ }
671
677
672
678
public async Task EnumerateItemsFromSpecialFolder ( string path )
673
679
{
@@ -851,124 +857,113 @@ public async Task EnumerateItemsFromStandardFolder(string path)
851
857
852
858
}
853
859
854
- private async void WatchForDirectoryChanges ( string path )
860
+ private void WatchForDirectoryChanges ( string path )
855
861
{
856
- var uiThreadScheduler = TaskScheduler . FromCurrentSynchronizationContext ( ) ;
857
- Task thrItem = null ;
858
- IsWatching = true ;
862
+ Debug . WriteLine ( "WatchForDirectoryChanges: {0}" , path ) ;
859
863
hWatchDir = CreateFileFromApp ( path , 1 , 1 | 2 | 4 ,
860
864
IntPtr . Zero , 3 , ( uint ) File_Attributes . BackupSemantics | ( uint ) File_Attributes . Overlapped , IntPtr . Zero ) ;
861
865
862
866
byte [ ] buff = new byte [ 4096 ] ;
863
867
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..." ) ;
972
967
}
973
968
974
969
public void AddFileOrFolder ( ListedItem item )
@@ -1166,7 +1161,7 @@ private async Task AddFolder(StorageFolder folder)
1166
1161
IsLoadingItems = false ;
1167
1162
return ;
1168
1163
}
1169
-
1164
+
1170
1165
_filesAndFolders . Add ( new ListedItem ( folder . FolderRelativeId )
1171
1166
{
1172
1167
//FolderTooltipText = tooltipString,
@@ -1290,6 +1285,7 @@ public void Dispose()
1290
1285
{
1291
1286
_addFilesCTS ? . Dispose ( ) ;
1292
1287
_semaphoreCTS ? . Dispose ( ) ;
1288
+ CloseWatcher ( ) ;
1293
1289
}
1294
1290
}
1295
- }
1291
+ }
0 commit comments