WindowExtensions.cs
1 // Copyright (c) Microsoft Corporation 2 // The Microsoft Corporation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using Microsoft.UI; 6 using Microsoft.UI.Windowing; 7 using Microsoft.UI.Xaml; 8 using Windows.Win32; 9 using Windows.Win32.Foundation; 10 using Windows.Win32.Graphics.Dwm; 11 using Windows.Win32.UI.WindowsAndMessaging; 12 13 namespace Microsoft.CmdPal.UI.Helpers; 14 15 internal static class WindowExtensions 16 { 17 public static void SetIcon(this Window window) 18 { 19 var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(window); 20 WindowId windowId = Win32Interop.GetWindowIdFromWindow(hWnd); 21 AppWindow appWindow = AppWindow.GetFromWindowId(windowId); 22 appWindow.SetIcon(@"Assets\icon.ico"); 23 } 24 25 public static HWND GetWindowHwnd(this Window window) 26 { 27 return window is null 28 ? throw new ArgumentNullException(nameof(window)) 29 : new HWND(WinRT.Interop.WindowNative.GetWindowHandle(window)); 30 } 31 32 /// <summary> 33 /// Toggles the specified extended window style on or off for the supplied <see cref="Window"/>. 34 /// </summary> 35 /// <param name="window">The <see cref="Window"/> whose extended window styles will be modified. Cannot be null.</param> 36 /// <param name="style">The <see cref="WINDOW_EX_STYLE"/> flag(s) to set or clear.</param> 37 /// <param name="isStyleSet">When true, the specified <paramref name="style"/> bit(s) will be set (added). When false, the bit(s) will be cleared (removed).</param> 38 /// <returns>True if the call to SetWindowLong succeeded and the style was applied; otherwise false.</returns> 39 /// <exception cref="ArgumentNullException">Thrown if <paramref name="window"/> is null.</exception> 40 internal static bool ToggleExtendedWindowStyle(this Window window, WINDOW_EX_STYLE style, bool isStyleSet) 41 { 42 var hWnd = GetWindowHwnd(window); 43 var currentStyle = PInvoke.GetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE); 44 45 if (isStyleSet) 46 { 47 currentStyle |= (int)style; 48 } 49 else 50 { 51 currentStyle &= ~(int)style; 52 } 53 54 var wasSet = PInvoke.SetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, currentStyle) != 0; 55 56 // SWP_FRAMECHANGED - invalidate cached window style 57 PInvoke.SetWindowPos(hWnd, new HWND(IntPtr.Zero), 0, 0, 0, 0, SET_WINDOW_POS_FLAGS.SWP_FRAMECHANGED | SET_WINDOW_POS_FLAGS.SWP_NOMOVE | SET_WINDOW_POS_FLAGS.SWP_NOSIZE | SET_WINDOW_POS_FLAGS.SWP_NOZORDER | SET_WINDOW_POS_FLAGS.SWP_NOOWNERZORDER); 58 59 return wasSet; 60 } 61 62 /// <summary> 63 /// Sets the window corner preference 64 /// </summary> 65 /// <param name="window">The window</param> 66 /// <param name="cornerPreference">The desired corner preference</param> 67 /// <returns>True if the operation succeeded</returns> 68 public static bool SetCornerPreference(this Window window, DWM_WINDOW_CORNER_PREFERENCE cornerPreference) 69 { 70 return window.GetWindowHwnd().SetDwmWindowAttribute(DWMWINDOWATTRIBUTE.DWMWA_WINDOW_CORNER_PREFERENCE, cornerPreference); 71 } 72 73 /// <summary> 74 /// Unified wrapper for DwmSetWindowAttribute calls with enum values 75 /// </summary> 76 private static bool SetDwmWindowAttribute<T>(this HWND hwnd, DWMWINDOWATTRIBUTE attribute, T value) 77 where T : unmanaged, Enum 78 { 79 unsafe 80 { 81 var result = PInvoke.DwmSetWindowAttribute(hwnd, attribute, &value, (uint)sizeof(T)); 82 return result.Succeeded; 83 } 84 } 85 }