From 9b486474f79870a814bdfb6f25e681ffb4de468e Mon Sep 17 00:00:00 2001 From: Lamparter <71598437+Lamparter@users.noreply.github.com> Date: Wed, 30 Apr 2025 18:43:37 +0100 Subject: [PATCH 1/8] Init --- src/Files.App.CsWin32/NativeMethods.txt | 4 ++++ src/Files.App/App.xaml.cs | 8 +++++--- .../Helpers/Win32/Win32PInvoke.Methods.cs | 13 ------------- src/Files.App/Program.cs | 17 ++++++++++------- src/Files.App/ViewModels/ShellViewModel.cs | 5 +++-- 5 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/Files.App.CsWin32/NativeMethods.txt b/src/Files.App.CsWin32/NativeMethods.txt index ce5524f6885e..dbc4961a4565 100644 --- a/src/Files.App.CsWin32/NativeMethods.txt +++ b/src/Files.App.CsWin32/NativeMethods.txt @@ -225,3 +225,7 @@ QITIPF_FLAGS GetKeyboardState MapVirtualKey GetKeyboardLayout +CreateEvent +SetEvent +ResetEvent +CoWaitForMultipleObjects diff --git a/src/Files.App/App.xaml.cs b/src/Files.App/App.xaml.cs index a7b67a98829f..5bbf5f68494d 100644 --- a/src/Files.App/App.xaml.cs +++ b/src/Files.App/App.xaml.cs @@ -5,6 +5,8 @@ using Microsoft.Extensions.Logging; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; +using Microsoft.Win32.SafeHandles; +using Windows.Win32; using Microsoft.Windows.AppLifecycle; using Windows.ApplicationModel; using Windows.ApplicationModel.DataTransfer; @@ -223,9 +225,9 @@ private async void Window_Closed(object sender, WindowEventArgs args) var results = items.Select(x => x.ItemPath).ToList(); System.IO.File.WriteAllLines(OutputPath, results); - IntPtr eventHandle = Win32PInvoke.CreateEvent(IntPtr.Zero, false, false, "FILEDIALOG"); - Win32PInvoke.SetEvent(eventHandle); - Win32PInvoke.CloseHandle(eventHandle); + SafeFileHandle eventHandle = PInvoke.CreateEvent(null, false, false, "FILEDIALOG"); + PInvoke.SetEvent(eventHandle); + eventHandle.Close(); } // Continue running the app on the background diff --git a/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs b/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs index 5d700736a2fa..56d4cf213b9d 100644 --- a/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs +++ b/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs @@ -56,19 +56,6 @@ public static extern int RmGetList( ref uint lpdwRebootReasons ); - [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] - public static extern IntPtr CreateEvent( - IntPtr lpEventAttributes, - bool bManualReset, - bool bInitialState, - string lpName - ); - - [DllImport("kernel32.dll")] - public static extern bool SetEvent( - IntPtr hEvent - ); - [DllImport("ole32.dll")] public static extern uint CoWaitForMultipleObjects( uint dwFlags, diff --git a/src/Files.App/Program.cs b/src/Files.App/Program.cs index 6d7807095797..a5f9678f329a 100644 --- a/src/Files.App/Program.cs +++ b/src/Files.App/Program.cs @@ -5,11 +5,14 @@ using Microsoft.UI.Dispatching; using Microsoft.UI.Xaml; using Microsoft.Windows.AppLifecycle; +using Windows.Win32; +using Windows.Win32.Foundation; using System.IO; using System.Text; using Windows.ApplicationModel.Activation; using Windows.Storage; using static Files.App.Helpers.Win32PInvoke; +using Microsoft.Win32.SafeHandles; namespace Files.App { @@ -250,19 +253,19 @@ private static async void OnActivated(object? sender, AppActivationArguments arg /// public static void RedirectActivationTo(AppInstance keyInstance, AppActivationArguments args) { - IntPtr eventHandle = CreateEvent(IntPtr.Zero, true, false, null); + SafeFileHandle eventHandle = PInvoke.CreateEvent(null, true, false, null); Task.Run(() => { keyInstance.RedirectActivationToAsync(args).AsTask().Wait(); - SetEvent(eventHandle); + PInvoke.SetEvent(eventHandle); }); - _ = CoWaitForMultipleObjects( + _ = Win32PInvoke.CoWaitForMultipleObjects( CWMO_DEFAULT, INFINITE, 1, - [eventHandle], + [eventHandle.DangerousGetHandle()], out uint handleIndex); } @@ -273,19 +276,19 @@ public static void OpenShellCommandInExplorer(string shellCommand, int pid) public static void OpenFileFromTile(string filePath) { - IntPtr eventHandle = CreateEvent(IntPtr.Zero, true, false, null); + SafeFileHandle eventHandle = PInvoke.CreateEvent(null, true, false, null); Task.Run(() => { LaunchHelper.LaunchAppAsync(filePath, null, null).Wait(); - SetEvent(eventHandle); + PInvoke.SetEvent(eventHandle); }); _ = CoWaitForMultipleObjects( CWMO_DEFAULT, INFINITE, 1, - [eventHandle], + [eventHandle.DangerousGetHandle()], out uint handleIndex); } } diff --git a/src/Files.App/ViewModels/ShellViewModel.cs b/src/Files.App/ViewModels/ShellViewModel.cs index 68472561dc36..e34f5c0a336b 100644 --- a/src/Files.App/ViewModels/ShellViewModel.cs +++ b/src/Files.App/ViewModels/ShellViewModel.cs @@ -14,6 +14,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Vanara.Windows.Shell; +using Windows.Win32; using Windows.Foundation; using Windows.Storage; using Windows.Storage.FileProperties; @@ -2124,7 +2125,7 @@ private void WatchForDirectoryChanges(string path, CloudDriveSyncStatus syncStat notifyFilters |= FILE_NOTIFY_CHANGE_ATTRIBUTES; var overlapped = new OVERLAPPED(); - overlapped.hEvent = CreateEvent(IntPtr.Zero, false, false, null); + overlapped.hEvent = PInvoke.CreateEvent(null, false, false, null).DangerousGetHandle(); const uint INFINITE = 0xFFFFFFFF; while (x.Status != AsyncStatus.Canceled) @@ -2235,7 +2236,7 @@ private void WatchForGitChanges() 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); + overlapped.hEvent = PInvoke.CreateEvent(null, false, false, null).DangerousGetHandle(); const uint INFINITE = 0xFFFFFFFF; while (x.Status != AsyncStatus.Canceled) From 5988ea13517abd2c59790cf800c94eb0be04ca3a Mon Sep 17 00:00:00 2001 From: Lamparter <71598437+Lamparter@users.noreply.github.com> Date: Thu, 1 May 2025 07:30:07 +0100 Subject: [PATCH 2/8] Use HANDLE instead of SafeFileHandle --- src/Files.App/App.xaml.cs | 6 +++--- src/Files.App/Program.cs | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Files.App/App.xaml.cs b/src/Files.App/App.xaml.cs index 5bbf5f68494d..a1b37ca340d0 100644 --- a/src/Files.App/App.xaml.cs +++ b/src/Files.App/App.xaml.cs @@ -5,7 +5,7 @@ using Microsoft.Extensions.Logging; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; -using Microsoft.Win32.SafeHandles; +using Windows.Win32.Foundation; using Windows.Win32; using Microsoft.Windows.AppLifecycle; using Windows.ApplicationModel; @@ -225,9 +225,9 @@ private async void Window_Closed(object sender, WindowEventArgs args) var results = items.Select(x => x.ItemPath).ToList(); System.IO.File.WriteAllLines(OutputPath, results); - SafeFileHandle eventHandle = PInvoke.CreateEvent(null, false, false, "FILEDIALOG"); + HANDLE eventHandle = (HANDLE)PInvoke.CreateEvent(null, false, false, "FILEDIALOG").DangerousGetHandle(); PInvoke.SetEvent(eventHandle); - eventHandle.Close(); + PInvoke.CloseHandle(eventHandle); } // Continue running the app on the background diff --git a/src/Files.App/Program.cs b/src/Files.App/Program.cs index a5f9678f329a..9fdc968f4270 100644 --- a/src/Files.App/Program.cs +++ b/src/Files.App/Program.cs @@ -12,7 +12,6 @@ using Windows.ApplicationModel.Activation; using Windows.Storage; using static Files.App.Helpers.Win32PInvoke; -using Microsoft.Win32.SafeHandles; namespace Files.App { @@ -253,7 +252,7 @@ private static async void OnActivated(object? sender, AppActivationArguments arg /// public static void RedirectActivationTo(AppInstance keyInstance, AppActivationArguments args) { - SafeFileHandle eventHandle = PInvoke.CreateEvent(null, true, false, null); + HANDLE eventHandle = (HANDLE)PInvoke.CreateEvent(null, true, false, null).DangerousGetHandle(); Task.Run(() => { @@ -265,7 +264,7 @@ public static void RedirectActivationTo(AppInstance keyInstance, AppActivationAr CWMO_DEFAULT, INFINITE, 1, - [eventHandle.DangerousGetHandle()], + [eventHandle], out uint handleIndex); } @@ -276,7 +275,7 @@ public static void OpenShellCommandInExplorer(string shellCommand, int pid) public static void OpenFileFromTile(string filePath) { - SafeFileHandle eventHandle = PInvoke.CreateEvent(null, true, false, null); + HANDLE eventHandle = (HANDLE)PInvoke.CreateEvent(null, true, false, null).DangerousGetHandle(); Task.Run(() => { @@ -288,7 +287,7 @@ public static void OpenFileFromTile(string filePath) CWMO_DEFAULT, INFINITE, 1, - [eventHandle.DangerousGetHandle()], + [eventHandle], out uint handleIndex); } } From 4278039a7d876ffda40413e29c032c9567c4edc8 Mon Sep 17 00:00:00 2001 From: Lamparter <71598437+Lamparter@users.noreply.github.com> Date: Thu, 1 May 2025 07:31:57 +0100 Subject: [PATCH 3/8] Remove unnecessary method --- src/Files.App.CsWin32/NativeMethods.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Files.App.CsWin32/NativeMethods.txt b/src/Files.App.CsWin32/NativeMethods.txt index dbc4961a4565..eb856a79ad04 100644 --- a/src/Files.App.CsWin32/NativeMethods.txt +++ b/src/Files.App.CsWin32/NativeMethods.txt @@ -228,4 +228,3 @@ GetKeyboardLayout CreateEvent SetEvent ResetEvent -CoWaitForMultipleObjects From 156e4b396a663c6b7d9887a889b313784b4f49f4 Mon Sep 17 00:00:00 2001 From: Lamparter <71598437+Lamparter@users.noreply.github.com> Date: Thu, 1 May 2025 18:29:57 +0100 Subject: [PATCH 4/8] Use overload --- src/Files.App/App.xaml.cs | 12 +++++++++--- src/Files.App/Program.cs | 8 ++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/Files.App/App.xaml.cs b/src/Files.App/App.xaml.cs index a1b37ca340d0..745cc517dd63 100644 --- a/src/Files.App/App.xaml.cs +++ b/src/Files.App/App.xaml.cs @@ -225,9 +225,15 @@ private async void Window_Closed(object sender, WindowEventArgs args) var results = items.Select(x => x.ItemPath).ToList(); System.IO.File.WriteAllLines(OutputPath, results); - HANDLE eventHandle = (HANDLE)PInvoke.CreateEvent(null, false, false, "FILEDIALOG").DangerousGetHandle(); - PInvoke.SetEvent(eventHandle); - PInvoke.CloseHandle(eventHandle); + unsafe + { + fixed (char* fileDialog = "FILEDIALOG") + { + HANDLE eventHandle = PInvoke.CreateEvent(bManualReset: false, bInitialState: false, lpName: fileDialog); + PInvoke.SetEvent(eventHandle); + PInvoke.CloseHandle(eventHandle); + } + } } // Continue running the app on the background diff --git a/src/Files.App/Program.cs b/src/Files.App/Program.cs index 9fdc968f4270..28b3ca403e2c 100644 --- a/src/Files.App/Program.cs +++ b/src/Files.App/Program.cs @@ -250,9 +250,9 @@ private static async void OnActivated(object? sender, AppActivationArguments arg /// /// Redirects on another thread and uses a non-blocking wait method to wait for the redirection to complete. /// - public static void RedirectActivationTo(AppInstance keyInstance, AppActivationArguments args) + public static unsafe void RedirectActivationTo(AppInstance keyInstance, AppActivationArguments args) { - HANDLE eventHandle = (HANDLE)PInvoke.CreateEvent(null, true, false, null).DangerousGetHandle(); + HANDLE eventHandle = PInvoke.CreateEvent(bManualReset: true, bInitialState: false, lpName: null); Task.Run(() => { @@ -273,9 +273,9 @@ public static void OpenShellCommandInExplorer(string shellCommand, int pid) Win32Helper.OpenFolderInExistingShellWindow(shellCommand); } - public static void OpenFileFromTile(string filePath) + public static unsafe void OpenFileFromTile(string filePath) { - HANDLE eventHandle = (HANDLE)PInvoke.CreateEvent(null, true, false, null).DangerousGetHandle(); + HANDLE eventHandle = PInvoke.CreateEvent(bManualReset: true, bInitialState: false, lpName: null); Task.Run(() => { From 91cf7076cb730da1c787bc29b1933ae04e513c73 Mon Sep 17 00:00:00 2001 From: Lamparter <71598437+Lamparter@users.noreply.github.com> Date: Sat, 10 May 2025 09:30:59 +0100 Subject: [PATCH 5/8] Fix overload signature Co-authored-by: 0x5BFA <62196528+0x5bfa@users.noreply.github.com> Signed-off-by: Lamparter <71598437+Lamparter@users.noreply.github.com> --- src/Files.App/App.xaml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Files.App/App.xaml.cs b/src/Files.App/App.xaml.cs index 745cc517dd63..db821113884a 100644 --- a/src/Files.App/App.xaml.cs +++ b/src/Files.App/App.xaml.cs @@ -229,7 +229,7 @@ private async void Window_Closed(object sender, WindowEventArgs args) { fixed (char* fileDialog = "FILEDIALOG") { - HANDLE eventHandle = PInvoke.CreateEvent(bManualReset: false, bInitialState: false, lpName: fileDialog); + HANDLE eventHandle = PInvoke.CreateEvent((SECURITY_ATTRIBUTES*)null, false, false, fileDialog); PInvoke.SetEvent(eventHandle); PInvoke.CloseHandle(eventHandle); } From 4264a2f9b0ea28956f035a6b458c71b8642cb834 Mon Sep 17 00:00:00 2001 From: Lamparter <71598437+Lamparter@users.noreply.github.com> Date: Sat, 10 May 2025 09:40:01 +0100 Subject: [PATCH 6/8] Fix variable names --- src/Files.App/App.xaml.cs | 8 ++++---- src/Files.App/Program.cs | 13 +++++++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Files.App/App.xaml.cs b/src/Files.App/App.xaml.cs index db821113884a..be0556db4752 100644 --- a/src/Files.App/App.xaml.cs +++ b/src/Files.App/App.xaml.cs @@ -227,11 +227,11 @@ private async void Window_Closed(object sender, WindowEventArgs args) unsafe { - fixed (char* fileDialog = "FILEDIALOG") + fixed (char* pszEventObjectName = "FILEDIALOG") { - HANDLE eventHandle = PInvoke.CreateEvent((SECURITY_ATTRIBUTES*)null, false, false, fileDialog); - PInvoke.SetEvent(eventHandle); - PInvoke.CloseHandle(eventHandle); + HANDLE hEventHandle = PInvoke.CreateEvent((Windows.Win32.Security.SECURITY_ATTRIBUTES*)null, false, false, pszEventObjectName); + PInvoke.SetEvent(hEventHandle); + PInvoke.CloseHandle(hEventHandle); } } } diff --git a/src/Files.App/Program.cs b/src/Files.App/Program.cs index 28b3ca403e2c..e0d925258816 100644 --- a/src/Files.App/Program.cs +++ b/src/Files.App/Program.cs @@ -12,6 +12,7 @@ using Windows.ApplicationModel.Activation; using Windows.Storage; using static Files.App.Helpers.Win32PInvoke; +using Windows.Win32.Security; namespace Files.App { @@ -252,19 +253,19 @@ private static async void OnActivated(object? sender, AppActivationArguments arg /// public static unsafe void RedirectActivationTo(AppInstance keyInstance, AppActivationArguments args) { - HANDLE eventHandle = PInvoke.CreateEvent(bManualReset: true, bInitialState: false, lpName: null); + HANDLE hEventHandle = PInvoke.CreateEvent((SECURITY_ATTRIBUTES*)null, true, false, null); Task.Run(() => { keyInstance.RedirectActivationToAsync(args).AsTask().Wait(); - PInvoke.SetEvent(eventHandle); + PInvoke.SetEvent(hEventHandle); }); _ = Win32PInvoke.CoWaitForMultipleObjects( CWMO_DEFAULT, INFINITE, 1, - [eventHandle], + [hEventHandle], out uint handleIndex); } @@ -275,19 +276,19 @@ public static void OpenShellCommandInExplorer(string shellCommand, int pid) public static unsafe void OpenFileFromTile(string filePath) { - HANDLE eventHandle = PInvoke.CreateEvent(bManualReset: true, bInitialState: false, lpName: null); + HANDLE hEventHandle = PInvoke.CreateEvent((SECURITY_ATTRIBUTES*)null, true, false, null); Task.Run(() => { LaunchHelper.LaunchAppAsync(filePath, null, null).Wait(); - PInvoke.SetEvent(eventHandle); + PInvoke.SetEvent(hEventHandle); }); _ = CoWaitForMultipleObjects( CWMO_DEFAULT, INFINITE, 1, - [eventHandle], + [hEventHandle], out uint handleIndex); } } From 9937cb3278b87cf13cfc29e2f4ca7fbb3bee2ddd Mon Sep 17 00:00:00 2001 From: Lamparter <71598437+Lamparter@users.noreply.github.com> Date: Sat, 10 May 2025 10:02:23 +0100 Subject: [PATCH 7/8] Use `CoWaitForMultipleObjects` from CsWin32 --- src/Files.App.CsWin32/NativeMethods.txt | 1 + src/Files.App/Program.cs | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Files.App.CsWin32/NativeMethods.txt b/src/Files.App.CsWin32/NativeMethods.txt index eb856a79ad04..dbc4961a4565 100644 --- a/src/Files.App.CsWin32/NativeMethods.txt +++ b/src/Files.App.CsWin32/NativeMethods.txt @@ -228,3 +228,4 @@ GetKeyboardLayout CreateEvent SetEvent ResetEvent +CoWaitForMultipleObjects diff --git a/src/Files.App/Program.cs b/src/Files.App/Program.cs index e0d925258816..b054fca0ce53 100644 --- a/src/Files.App/Program.cs +++ b/src/Files.App/Program.cs @@ -255,18 +255,22 @@ public static unsafe void RedirectActivationTo(AppInstance keyInstance, AppActiv { HANDLE hEventHandle = PInvoke.CreateEvent((SECURITY_ATTRIBUTES*)null, true, false, null); + HANDLE* pHandles = stackalloc HANDLE[1]; + pHandles[0] = hEventHandle; + Task.Run(() => { keyInstance.RedirectActivationToAsync(args).AsTask().Wait(); PInvoke.SetEvent(hEventHandle); }); - _ = Win32PInvoke.CoWaitForMultipleObjects( + uint dwIndex = 0u; + PInvoke.CoWaitForMultipleObjects( CWMO_DEFAULT, INFINITE, - 1, - [hEventHandle], - out uint handleIndex); + 1u, + pHandles, + &dwIndex); } public static void OpenShellCommandInExplorer(string shellCommand, int pid) From f733a5fcb066960480cee11496147b19b6d5b0c9 Mon Sep 17 00:00:00 2001 From: Lamparter <71598437+Lamparter@users.noreply.github.com> Date: Sat, 10 May 2025 10:02:31 +0100 Subject: [PATCH 8/8] Revert changes to `WatchForGitChanges()` --- src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs | 1 - src/Files.App/ViewModels/ShellViewModel.cs | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs b/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs index 56d4cf213b9d..f7dc7d44cf97 100644 --- a/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs +++ b/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs @@ -55,7 +55,6 @@ public static extern int RmGetList( [In, Out] RM_PROCESS_INFO[] rgAffectedApps, ref uint lpdwRebootReasons ); - [DllImport("ole32.dll")] public static extern uint CoWaitForMultipleObjects( uint dwFlags, diff --git a/src/Files.App/ViewModels/ShellViewModel.cs b/src/Files.App/ViewModels/ShellViewModel.cs index e34f5c0a336b..68472561dc36 100644 --- a/src/Files.App/ViewModels/ShellViewModel.cs +++ b/src/Files.App/ViewModels/ShellViewModel.cs @@ -14,7 +14,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Vanara.Windows.Shell; -using Windows.Win32; using Windows.Foundation; using Windows.Storage; using Windows.Storage.FileProperties; @@ -2125,7 +2124,7 @@ private void WatchForDirectoryChanges(string path, CloudDriveSyncStatus syncStat notifyFilters |= FILE_NOTIFY_CHANGE_ATTRIBUTES; var overlapped = new OVERLAPPED(); - overlapped.hEvent = PInvoke.CreateEvent(null, false, false, null).DangerousGetHandle(); + overlapped.hEvent = CreateEvent(IntPtr.Zero, false, false, null); const uint INFINITE = 0xFFFFFFFF; while (x.Status != AsyncStatus.Canceled) @@ -2236,7 +2235,7 @@ private void WatchForGitChanges() 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 = PInvoke.CreateEvent(null, false, false, null).DangerousGetHandle(); + overlapped.hEvent = CreateEvent(IntPtr.Zero, false, false, null); const uint INFINITE = 0xFFFFFFFF; while (x.Status != AsyncStatus.Canceled)