From 5313229fb918b19e99eddfd5023c41fed9724e66 Mon Sep 17 00:00:00 2001 From: zggsong Date: Fri, 14 Feb 2025 13:22:27 +0800 Subject: [PATCH 1/3] perf: hide main window from alt tab program switcher #2356 --- Flow.Launcher/Helper/WindowsInteropHelper.cs | 75 ++++++++++++++++++++ Flow.Launcher/MainWindow.xaml | 1 + Flow.Launcher/MainWindow.xaml.cs | 5 ++ 3 files changed, 81 insertions(+) diff --git a/Flow.Launcher/Helper/WindowsInteropHelper.cs b/Flow.Launcher/Helper/WindowsInteropHelper.cs index caf3f0a7f60..eeb24af2ea9 100644 --- a/Flow.Launcher/Helper/WindowsInteropHelper.cs +++ b/Flow.Launcher/Helper/WindowsInteropHelper.cs @@ -148,4 +148,79 @@ public static Point TransformPixelsToDIP(Visual visual, double unitX, double uni return new Point((int)(matrix.M11 * unitX), (int)(matrix.M22 * unitY)); } + + #region Alt Tab + + private const int GWL_EXSTYLE = -20; + private const int WS_EX_TOOLWINDOW = 0x00000080; + private const int WS_EX_APPWINDOW = 0x00040000; + + [DllImport("user32.dll")] + private static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex); + + [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", SetLastError = true)] + private static extern IntPtr IntSetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong); + + [DllImport("user32.dll", EntryPoint = "SetWindowLong", SetLastError = true)] + private static extern int IntSetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); + + [DllImport("kernel32.dll", EntryPoint = "SetLastError")] + private static extern void SetLastError(int dwErrorCode); + + private static IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong) + { + SetLastError(0); // Clear any existing error + + if (IntPtr.Size == 4) return new IntPtr(IntSetWindowLong(hWnd, nIndex, IntPtrToInt32(dwNewLong))); + + return IntSetWindowLongPtr(hWnd, nIndex, dwNewLong); + } + + private static int IntPtrToInt32(IntPtr intPtr) + { + return unchecked((int)intPtr.ToInt64()); + } + + /// + /// Hide windows in the Alt+Tab window list + /// + /// To hide a window + public static void HideFromAltTab(Window window) + { + var helper = new WindowInteropHelper(window); + var exStyle = GetWindowLong(helper.Handle, GWL_EXSTYLE).ToInt32(); + + // Add TOOLWINDOW style, remove APPWINDOW style + exStyle = (exStyle | WS_EX_TOOLWINDOW) & ~WS_EX_APPWINDOW; + + SetWindowLong(helper.Handle, GWL_EXSTYLE, new IntPtr(exStyle)); + } + + /// + /// Restore window display in the Alt+Tab window list. + /// + /// To restore the displayed window + public static void ShowInAltTab(Window window) + { + var helper = new WindowInteropHelper(window); + var exStyle = GetWindowLong(helper.Handle, GWL_EXSTYLE).ToInt32(); + + // Remove the TOOLWINDOW style and add the APPWINDOW style. + exStyle = (exStyle & ~WS_EX_TOOLWINDOW) | WS_EX_APPWINDOW; + + SetWindowLong(helper.Handle, GWL_EXSTYLE, new IntPtr(exStyle)); + } + + /// + /// To obtain the current overridden style of a window. + /// + /// To obtain the style dialog window + /// current extension style value + public static int GetCurrentWindowStyle(Window window) + { + var helper = new WindowInteropHelper(window); + return GetWindowLong(helper.Handle, GWL_EXSTYLE).ToInt32(); + } + + #endregion } diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index f5fd729d45b..da9e1a5b5ac 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -20,6 +20,7 @@ Closing="OnClosing" Deactivated="OnDeactivated" Icon="Images/app.png" + SourceInitialized="OnSourceInitialized" Initialized="OnInitialized" Left="{Binding Settings.WindowLeft, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Loaded="OnLoaded" diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 8ca153afc34..41dc68fd924 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -171,6 +171,11 @@ private async void OnClosing(object sender, CancelEventArgs e) Environment.Exit(0); } + private void OnSourceInitialized(object sender, EventArgs e) + { + WindowsInteropHelper.HideFromAltTab(this); + } + private void OnInitialized(object sender, EventArgs e) { } From 829dbaafe7fae537d487f4b67cfe593c01ac5081 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 14 Feb 2025 16:12:15 +0800 Subject: [PATCH 2/3] Use CSWin32 for code quality --- Flow.Launcher/Helper/WindowsInteropHelper.cs | 44 ++++++-------------- Flow.Launcher/NativeMethods.txt | 5 ++- 2 files changed, 17 insertions(+), 32 deletions(-) diff --git a/Flow.Launcher/Helper/WindowsInteropHelper.cs b/Flow.Launcher/Helper/WindowsInteropHelper.cs index eeb24af2ea9..4891bf41ad5 100644 --- a/Flow.Launcher/Helper/WindowsInteropHelper.cs +++ b/Flow.Launcher/Helper/WindowsInteropHelper.cs @@ -151,29 +151,11 @@ public static Point TransformPixelsToDIP(Visual visual, double unitX, double uni #region Alt Tab - private const int GWL_EXSTYLE = -20; - private const int WS_EX_TOOLWINDOW = 0x00000080; - private const int WS_EX_APPWINDOW = 0x00040000; - - [DllImport("user32.dll")] - private static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex); - - [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", SetLastError = true)] - private static extern IntPtr IntSetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong); - - [DllImport("user32.dll", EntryPoint = "SetWindowLong", SetLastError = true)] - private static extern int IntSetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); - - [DllImport("kernel32.dll", EntryPoint = "SetLastError")] - private static extern void SetLastError(int dwErrorCode); - - private static IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong) + private static IntPtr SetWindowLong(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex, int dwNewLong) { - SetLastError(0); // Clear any existing error - - if (IntPtr.Size == 4) return new IntPtr(IntSetWindowLong(hWnd, nIndex, IntPtrToInt32(dwNewLong))); + PInvoke.SetLastError(WIN32_ERROR.NO_ERROR); // Clear any existing error - return IntSetWindowLongPtr(hWnd, nIndex, dwNewLong); + return PInvoke.SetWindowLong(hWnd, nIndex, dwNewLong); } private static int IntPtrToInt32(IntPtr intPtr) @@ -182,44 +164,44 @@ private static int IntPtrToInt32(IntPtr intPtr) } /// - /// Hide windows in the Alt+Tab window list + /// Hide windows in the Alt+Tab window list /// /// To hide a window public static void HideFromAltTab(Window window) { var helper = new WindowInteropHelper(window); - var exStyle = GetWindowLong(helper.Handle, GWL_EXSTYLE).ToInt32(); + var exStyle = PInvoke.GetWindowLong(new(helper.Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE); // Add TOOLWINDOW style, remove APPWINDOW style - exStyle = (exStyle | WS_EX_TOOLWINDOW) & ~WS_EX_APPWINDOW; + var newExStyle = ((uint)exStyle | (uint)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW) & ~(uint)WINDOW_EX_STYLE.WS_EX_APPWINDOW; - SetWindowLong(helper.Handle, GWL_EXSTYLE, new IntPtr(exStyle)); + SetWindowLong(new(helper.Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle); } /// - /// Restore window display in the Alt+Tab window list. + /// Restore window display in the Alt+Tab window list. /// /// To restore the displayed window public static void ShowInAltTab(Window window) { var helper = new WindowInteropHelper(window); - var exStyle = GetWindowLong(helper.Handle, GWL_EXSTYLE).ToInt32(); + var exStyle = PInvoke.GetWindowLong(new(helper.Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE); // Remove the TOOLWINDOW style and add the APPWINDOW style. - exStyle = (exStyle & ~WS_EX_TOOLWINDOW) | WS_EX_APPWINDOW; + var newExStyle = ((uint)exStyle & ~(uint)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW) | (uint)WINDOW_EX_STYLE.WS_EX_APPWINDOW; - SetWindowLong(helper.Handle, GWL_EXSTYLE, new IntPtr(exStyle)); + SetWindowLong(new(helper.Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle); } /// - /// To obtain the current overridden style of a window. + /// To obtain the current overridden style of a window. /// /// To obtain the style dialog window /// current extension style value public static int GetCurrentWindowStyle(Window window) { var helper = new WindowInteropHelper(window); - return GetWindowLong(helper.Handle, GWL_EXSTYLE).ToInt32(); + return PInvoke.GetWindowLong(new(helper.Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE); } #endregion diff --git a/Flow.Launcher/NativeMethods.txt b/Flow.Launcher/NativeMethods.txt index 2b147c05f52..88eeeca6e5d 100644 --- a/Flow.Launcher/NativeMethods.txt +++ b/Flow.Launcher/NativeMethods.txt @@ -14,4 +14,7 @@ FindWindowEx WINDOW_STYLE WM_ENTERSIZEMOVE -WM_EXITSIZEMOVE \ No newline at end of file +WM_EXITSIZEMOVE + +SetLastError +WINDOW_EX_STYLE \ No newline at end of file From dc07e762fe0abc147a71ea5e8cd8b156e3ad611e Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 14 Feb 2025 16:25:51 +0800 Subject: [PATCH 3/3] Add error handling for Get & SetWindowLong failure & Combine get style function --- Flow.Launcher/Helper/WindowsInteropHelper.cs | 33 +++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/Flow.Launcher/Helper/WindowsInteropHelper.cs b/Flow.Launcher/Helper/WindowsInteropHelper.cs index 4891bf41ad5..3e57948a5f4 100644 --- a/Flow.Launcher/Helper/WindowsInteropHelper.cs +++ b/Flow.Launcher/Helper/WindowsInteropHelper.cs @@ -151,16 +151,17 @@ public static Point TransformPixelsToDIP(Visual visual, double unitX, double uni #region Alt Tab - private static IntPtr SetWindowLong(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex, int dwNewLong) + private static int SetWindowLong(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex, int dwNewLong) { PInvoke.SetLastError(WIN32_ERROR.NO_ERROR); // Clear any existing error - return PInvoke.SetWindowLong(hWnd, nIndex, dwNewLong); - } + var result = PInvoke.SetWindowLong(hWnd, nIndex, dwNewLong); + if (result == 0 && Marshal.GetLastPInvokeError() != 0) + { + throw new Win32Exception(Marshal.GetLastPInvokeError()); + } - private static int IntPtrToInt32(IntPtr intPtr) - { - return unchecked((int)intPtr.ToInt64()); + return result; } /// @@ -169,13 +170,12 @@ private static int IntPtrToInt32(IntPtr intPtr) /// To hide a window public static void HideFromAltTab(Window window) { - var helper = new WindowInteropHelper(window); - var exStyle = PInvoke.GetWindowLong(new(helper.Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE); + var exStyle = GetCurrentWindowStyle(window); // Add TOOLWINDOW style, remove APPWINDOW style var newExStyle = ((uint)exStyle | (uint)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW) & ~(uint)WINDOW_EX_STYLE.WS_EX_APPWINDOW; - SetWindowLong(new(helper.Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle); + SetWindowLong(new(new WindowInteropHelper(window).Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle); } /// @@ -184,13 +184,12 @@ public static void HideFromAltTab(Window window) /// To restore the displayed window public static void ShowInAltTab(Window window) { - var helper = new WindowInteropHelper(window); - var exStyle = PInvoke.GetWindowLong(new(helper.Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE); + var exStyle = GetCurrentWindowStyle(window); // Remove the TOOLWINDOW style and add the APPWINDOW style. var newExStyle = ((uint)exStyle & ~(uint)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW) | (uint)WINDOW_EX_STYLE.WS_EX_APPWINDOW; - SetWindowLong(new(helper.Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle); + SetWindowLong(new(new WindowInteropHelper(window).Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle); } /// @@ -198,10 +197,14 @@ public static void ShowInAltTab(Window window) /// /// To obtain the style dialog window /// current extension style value - public static int GetCurrentWindowStyle(Window window) + private static int GetCurrentWindowStyle(Window window) { - var helper = new WindowInteropHelper(window); - return PInvoke.GetWindowLong(new(helper.Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE); + var style = PInvoke.GetWindowLong(new(new WindowInteropHelper(window).Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE); + if (style == 0 && Marshal.GetLastPInvokeError() != 0) + { + throw new Win32Exception(Marshal.GetLastPInvokeError()); + } + return style; } #endregion