From 1e1fdd57361730aa4e7092a300c1bc65aee240de Mon Sep 17 00:00:00 2001 From: Lamparter <71598437+Lamparter@users.noreply.github.com> Date: Thu, 1 May 2025 18:19:49 +0100 Subject: [PATCH 1/2] Init --- src/Files.App.CsWin32/NativeMethods.txt | 1 + src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs | 11 ----------- src/Files.App/ViewModels/ShellViewModel.cs | 12 +++++++----- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/Files.App.CsWin32/NativeMethods.txt b/src/Files.App.CsWin32/NativeMethods.txt index aee2e82f99b3..ffbf0c1319df 100644 --- a/src/Files.App.CsWin32/NativeMethods.txt +++ b/src/Files.App.CsWin32/NativeMethods.txt @@ -226,3 +226,4 @@ _SICHINTF RoGetAgileReference IQueryInfo QITIPF_FLAGS +CancelIoEx diff --git a/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs b/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs index 9af7345111ec..41120863b440 100644 --- a/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs +++ b/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs @@ -115,17 +115,6 @@ public static extern bool GetOverlappedResult( bool bWait ); - [DllImport("api-ms-win-core-io-l1-1-1.dll")] - public static extern bool CancelIo( - IntPtr hFile - ); - - [DllImport("api-ms-win-core-io-l1-1-1.dll")] - public static extern bool CancelIoEx( - IntPtr hFile, - IntPtr lpOverlapped - ); - [DllImport("api-ms-win-core-synch-l1-2-0.dll")] public static extern uint WaitForMultipleObjectsEx( uint nCount, diff --git a/src/Files.App/ViewModels/ShellViewModel.cs b/src/Files.App/ViewModels/ShellViewModel.cs index 68472561dc36..5e08921972e6 100644 --- a/src/Files.App/ViewModels/ShellViewModel.cs +++ b/src/Files.App/ViewModels/ShellViewModel.cs @@ -14,6 +14,8 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Vanara.Windows.Shell; +using Windows.Win32; +using Windows.Win32.Foundation; using Windows.Foundation; using Windows.Storage; using Windows.Storage.FileProperties; @@ -2101,7 +2103,7 @@ await dispatcherQueue.EnqueueOrInvokeAsync(() => }); } - private void WatchForDirectoryChanges(string path, CloudDriveSyncStatus syncStatus) + private unsafe void WatchForDirectoryChanges(string path, CloudDriveSyncStatus syncStatus) { Debug.WriteLine($"WatchForDirectoryChanges: {path}"); var hWatchDir = Win32PInvoke.CreateFileFromApp(path, 1, 1 | 2 | 4, @@ -2206,12 +2208,12 @@ private void WatchForDirectoryChanges(string path, CloudDriveSyncStatus syncStat Debug.WriteLine("watcher canceled"); } - CancelIoEx(hWatchDir, IntPtr.Zero); - CloseHandle(hWatchDir); + PInvoke.CancelIoEx((HANDLE)hWatchDir); + PInvoke.CloseHandle((HANDLE)hWatchDir); }); } - private void WatchForGitChanges() + private unsafe void WatchForGitChanges() { var hWatchDir = Win32PInvoke.CreateFileFromApp( GitDirectory!, @@ -2294,7 +2296,7 @@ private void WatchForGitChanges() gitWatcherAction = null; } - CancelIoEx(hWatchDir, IntPtr.Zero); + PInvoke.CancelIoEx((HANDLE)hWatchDir); CloseHandle(hWatchDir); }); } From 2c36c4f79ae82303f0572cd98b3199eb8b994e66 Mon Sep 17 00:00:00 2001 From: Lamparter <71598437+Lamparter@users.noreply.github.com> Date: Fri, 2 May 2025 07:46:35 +0100 Subject: [PATCH 2/2] Improve `WatchForGitChanges` method with CsWin32 [wip] --- src/Files.App.CsWin32/NativeMethods.txt | 3 ++ src/Files.App/ViewModels/ShellViewModel.cs | 44 +++++++++++++--------- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/Files.App.CsWin32/NativeMethods.txt b/src/Files.App.CsWin32/NativeMethods.txt index ffbf0c1319df..729798e9ee8b 100644 --- a/src/Files.App.CsWin32/NativeMethods.txt +++ b/src/Files.App.CsWin32/NativeMethods.txt @@ -227,3 +227,6 @@ RoGetAgileReference IQueryInfo QITIPF_FLAGS CancelIoEx +OVERLAPPED +CreateEvent +ReadDirectoryChangesW diff --git a/src/Files.App/ViewModels/ShellViewModel.cs b/src/Files.App/ViewModels/ShellViewModel.cs index 5e08921972e6..6e3212e6a6dd 100644 --- a/src/Files.App/ViewModels/ShellViewModel.cs +++ b/src/Files.App/ViewModels/ShellViewModel.cs @@ -16,6 +16,7 @@ using Vanara.Windows.Shell; using Windows.Win32; using Windows.Win32.Foundation; +using Windows.Win32.Storage.FileSystem; using Windows.Foundation; using Windows.Storage; using Windows.Storage.FileProperties; @@ -25,6 +26,8 @@ using FileAttributes = System.IO.FileAttributes; using ByteSize = ByteSizeLib.ByteSize; using Windows.Win32.System.SystemServices; +using FINDEX_SEARCH_OPS = Windows.Win32.Storage.FileSystem.FINDEX_SEARCH_OPS; +using FINDEX_INFO_LEVELS = Windows.Win32.Storage.FileSystem.FINDEX_INFO_LEVELS; namespace Files.App.ViewModels { @@ -1750,7 +1753,7 @@ await DialogDisplayHelper.ShowDialogAsync( var findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic; var additionalFlags = FIND_FIRST_EX_LARGE_FETCH; - IntPtr hFileTsk = FindFirstFileExFromApp( + IntPtr hFileTsk = PInvoke.FindFirstFileEx( path + "\\*.*", findInfoLevel, out WIN32_FIND_DATA findDataTsk, @@ -2215,16 +2218,20 @@ private unsafe void WatchForDirectoryChanges(string path, CloudDriveSyncStatus s private unsafe void WatchForGitChanges() { - var hWatchDir = Win32PInvoke.CreateFileFromApp( - GitDirectory!, - 1, - 1 | 2 | 4, - IntPtr.Zero, - 3, - (uint)Win32PInvoke.File_Attributes.BackupSemantics | (uint)Win32PInvoke.File_Attributes.Overlapped, - IntPtr.Zero); + HANDLE hWatchDir; - if (hWatchDir.ToInt64() == -1) + fixed (char* gitDir = GitDirectory) + { + hWatchDir = PInvoke.CreateFile( + gitDir!, + 1, + FILE_SHARE_MODE.FILE_SHARE_READ | FILE_SHARE_MODE.FILE_SHARE_WRITE | FILE_SHARE_MODE.FILE_SHARE_DELETE, + dwCreationDisposition: FILE_CREATION_DISPOSITION.OPEN_EXISTING, + dwFlagsAndAttributes: FILE_FLAGS_AND_ATTRIBUTES.FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAGS_AND_ATTRIBUTES.FILE_FLAG_OVERLAPPED, + hTemplateFile: (HANDLE)null); + } + + if (hWatchDir.IsNull) return; gitProcessQueueAction ??= Task.Factory.StartNew(() => ProcessGitChangesQueueAsync(watcherCTS.Token), default, @@ -2236,8 +2243,8 @@ private unsafe void WatchForGitChanges() var rand = Guid.NewGuid(); var notifyFilters = FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_CREATION; - var overlapped = new OVERLAPPED(); - overlapped.hEvent = CreateEvent(IntPtr.Zero, false, false, null); + var overlapped = new Overlapped(); + overlapped.EventHandleIntPtr = PInvoke.CreateEvent((bManualReset: false, bInitialState: false, lpName: null); const uint INFINITE = 0xFFFFFFFF; while (x.Status != AsyncStatus.Canceled) @@ -2250,15 +2257,16 @@ private unsafe void WatchForGitChanges() if (x.Status == AsyncStatus.Canceled) break; - ReadDirectoryChangesW(hWatchDir, pBuff, + PInvoke.ReadDirectoryChanges(hWatchDir, pBuff, 4096, true, - notifyFilters, null, - ref overlapped, null); + notifyFilters, + lpOverlapped: ref overlapped, + lpCompletionRoutine: null); if (x.Status == AsyncStatus.Canceled) break; - var rc = WaitForSingleObjectEx(overlapped.hEvent, INFINITE, true); + var rc = WaitForSingleObjectEx(overlapped.EventHandleIntPtr, INFINITE, true); uint offset = 0; ref var notifyInfo = ref Unsafe.As(ref buff[offset]); @@ -2282,7 +2290,7 @@ private unsafe void WatchForGitChanges() } } - CloseHandle(overlapped.hEvent); + PInvoke.CloseHandle((HANDLE)overlapped.EventHandleIntPtr); gitChangesQueue.Clear(); }); @@ -2296,7 +2304,7 @@ private unsafe void WatchForGitChanges() gitWatcherAction = null; } - PInvoke.CancelIoEx((HANDLE)hWatchDir); + PInvoke.CancelIoEx(hWatchDir); CloseHandle(hWatchDir); }); }