1

I want to create empty window - transparent and borderless, and make it overlay. To create overlay window, I use AppWindow.SetPresenter(AppWindowPresenterKind.CompactOverlay), to make it borderless i subclass window and using following WndProc:

 private unsafe LRESULT SubclassProc(HWND hWnd, uint uMsg, WPARAM wParam, LPARAM lParam, nuint uIdSubclass, nuint dwRefData)
 {
     if (uMsg == PInvoke.WM_NCCALCSIZE)
     {
         return new LRESULT(0);
     }

     return PInvoke.DefSubclassProc(hWnd, uMsg, wParam, lParam);
 }

And for make window transparent i use following code:

ICompositionSupportsSystemBackdrop composition = this.As<ICompositionSupportsSystemBackdrop>();
CompositionColorBrush compositionColorBrush = new Compositor().CreateColorBrush(Color.FromArgb(0, 255, 255, 255));
composition.SystemBackdrop = compositionColorBrush;

But i can't hide default close/minimize/maxmimize buttons. I'm using Windows 11.

Full code:

using Microsoft.UI;
using Microsoft.UI.Composition;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using Sentry;
using System;
using System.Linq;
using Windows.System;
using Windows.UI;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.Graphics.Dwm;
using Windows.Win32.Graphics.Gdi;
using Windows.Win32.System.WinRT;
using Windows.Win32.UI.Shell;
using Windows.Win32.UI.Controls;
using WinRT;
using WinRT.Interop;
using CompositionColorBrush = Windows.UI.Composition.CompositionColorBrush;
using Compositor = Windows.UI.Composition.Compositor;
using System.IO;
using Windows.Win32.UI.WindowsAndMessaging;
using Windows.ApplicationModel.Core;

namespace Widget.UI.Windows
{
    internal abstract class OverlayWindow : Window
    {
        private Grid _rootGrid
        {
            get
            {
                if (base.Content is Grid rootGrid)
                {
                    return rootGrid;
                }

                throw new InvalidOperationException("TopWindow: root isn't initalized");
            }
        }

        public new UIElement? Content
        {
            get
            {
                return _rootGrid.Children.FirstOrDefault();
            }
            set
            {
                _rootGrid.Children.Clear();
        
                Grid contentGrid = new();
        
                Grid.SetColumn(contentGrid, 0);
                Grid.SetRow(contentGrid, 1);
        
                contentGrid.Children.Add(value);
        
                _rootGrid.Children.Add(contentGrid);
            }
        }

        protected HorizontalAlignment HorizontalAlignment
        {
            set
            {
                AppWindow.Move(new global::Windows.Graphics.PointInt32()
                {
                    X = value switch
                    {
                        HorizontalAlignment.Left => 0,
                        HorizontalAlignment.Center => (_displayArea.WorkArea.Width - AppWindow.Size.Width) / 2,
                        HorizontalAlignment.Right => _displayArea.WorkArea.Width - AppWindow.Size.Width,
                        _ => throw new ArgumentException($"Invalid value (note: HorizontalAlignment.Stretch not supported)")
                    },
                    Y = AppWindow.Position.Y
                });
            }
        }

        protected VerticalAlignment VerticalAlignment
        {
            set
            {
                AppWindow.Move(new global::Windows.Graphics.PointInt32()
                {
                    X = AppWindow.Position.X,
                    Y = value switch
                    {
                        VerticalAlignment.Top => 0,
                        VerticalAlignment.Center => (_displayArea.WorkArea.Height - AppWindow.Size.Height) / 2,
                        VerticalAlignment.Bottom => _displayArea.WorkArea.Height - AppWindow.Size.Height,
                        _ => throw new ArgumentException($"Invalid value (note: VerticalAlignment.Stretch not supported)")
                    }
                });
            }
        }

        private DisplayArea _displayArea
        {
            get
            {
                return DisplayArea.GetFromWindowId(Win32Interop.GetWindowIdFromWindow(WindowNative.GetWindowHandle(this)), DisplayAreaFallback.Nearest);
            }
        }

        private SUBCLASSPROC? _subclassProc;

        public OverlayWindow()
        {
            AppWindow.SetPresenter(AppWindowPresenterKind.CompactOverlay);
            this.InitializeWindow();
            this.InitializeDwmBlur();
            this.InitializeComposition();
            this.InitializeSubclass();
        }

        private void InitializeWindow()
        {
            Grid root = new();

            root.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });

            root.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(0) });
            root.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) });

            Grid titleBar = new();

            Grid.SetColumn(titleBar, 0);
            Grid.SetRow(titleBar, 0);

            root.Children.Add(titleBar);

            root.Loaded += (s, e) =>
            {
                if (VisualTreeHelper.GetParent(base.Content) is not DependencyObject contentPresenter)
                {
                    return;
                }
                 
                if (VisualTreeHelper.GetParent(contentPresenter) is not DependencyObject layoutRoot)
                {
                    return;
                }
                    
                     if (VisualTreeHelper.GetChild(layoutRoot, 1) is not Grid titleBar)
                     {
                         return;
                     }
                 
                     if (VisualTreeHelper.GetChild(titleBar, 0) is not Grid buttonContainer)
                     {
                         return;
                     }
                 
                     foreach (UIElement child in buttonContainer.Children)
                     {
                         child.Visibility = Visibility.Collapsed;
                     }

                // For correct drawing background after creation
                PInvoke.SendMessage(_currentHWND, PInvoke.WM_ACTIVATE, new WPARAM(0), new LPARAM(0));
            };

            this.ExtendsContentIntoTitleBar = true;
            this.SetTitleBar(titleBar);

            base.Content = root;

        }

        private void InitializeComposition()
        {
            EnsureDispatcherQueueExists();
             
            ICompositionSupportsSystemBackdrop composition = this.As<ICompositionSupportsSystemBackdrop>();
            CompositionColorBrush compositionColorBrush = new Compositor().CreateColorBrush(Color.FromArgb(0, 255, 255, 255));
            composition.SystemBackdrop = compositionColorBrush;
        }

        private void InitializeDwmBlur()
        {
            PInvoke.DwmExtendFrameIntoClientArea(_currentHWND, new MARGINS());
            PInvoke.DwmEnableBlurBehindWindow(_currentHWND, new DWM_BLURBEHIND()
            {
                fEnable = true,
                dwFlags = PInvoke.DWM_BB_ENABLE | PInvoke.DWM_BB_BLURREGION,
                hRgnBlur = PInvoke.CreateRectRgn(-2, -2, 1, -1)
            });
        }

        private void InitializeSubclass()
        {
            _subclassProc = SubclassProc;

            PInvoke.SetWindowSubclass(_currentHWND, _subclassProc, 1000, 0);
        }

        private unsafe LRESULT SubclassProc(HWND hWnd, uint uMsg, WPARAM wParam, LPARAM lParam, nuint uIdSubclass, nuint dwRefData)
        {
            if (uMsg == PInvoke.WM_NCCALCSIZE)
            {
                return new LRESULT(0);
            }

            return PInvoke.DefSubclassProc(hWnd, uMsg, wParam, lParam);
        }

        private unsafe void EnsureDispatcherQueueExists()
        {
            DispatcherQueue dispatcherQueue = global::Windows.System.DispatcherQueue.GetForCurrentThread();

            if (dispatcherQueue == null)
            {
                DispatcherQueueOptions options = new()
                {
                    apartmentType = DISPATCHERQUEUE_THREAD_APARTMENTTYPE.DQTAT_COM_STA,
                    threadType = DISPATCHERQUEUE_THREAD_TYPE.DQTYPE_THREAD_CURRENT,
                    dwSize = (uint)sizeof(DispatcherQueueOptions)
                };

                PInvoke.CreateDispatcherQueueController(options, out DispatcherQueueController _);
            }
        }
    }
}
4
  • 1
    Your code is only partial, do you have a reproducile code stackoverflow.com/help/minimal-reproducible-example Commented Dec 8, 2023 at 15:58
  • @SimonMourier, i added full code of window Commented Dec 8, 2023 at 16:06
  • This is far from being compilable Commented Dec 8, 2023 at 18:02
  • "But i can't hide default close/minimize/maxmimize buttons" You could try to use SetBorderAndTitleBar to remove TitleBar and then add your own custom title bar. Commented Dec 11, 2023 at 6:26

1 Answer 1

3

Hide buttons with

((OverlappedPresenter)AppWindow.Presenter).SetBorderAndTitleBar(false, false);
        ((OverlappedPresenter)AppWindow.Presenter).IsMinimizable = false;
        ((OverlappedPresenter)AppWindow.Presenter).IsMaximizable = false;
        ((OverlappedPresenter)AppWindow.Presenter).IsResizable = false;
        AppWindow.IsShownInSwitchers = false;

For removing border around window use p/invoke:

public static void SetWindowCornerRadius(IntPtr hwnd, NativeValues.DWM_WINDOW_CORNER_PREFERENCE cornerPreference)
    {
        var attribute = NativeValues.DWMWINDOWATTRIBUTE.DWMWA_WINDOW_CORNER_PREFERENCE;
        var preference = (uint)cornerPreference;
        NativeMethods.DwmSetWindowAttribute(hwnd, attribute, ref preference, sizeof(uint));
    }

[DllImport(ExternDll.DwmApi, CharSet = CharSet.Unicode, PreserveSig = false)]
    public static extern int DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE dwAttribute, ref uint pvAttribute, uint cbAttribute);

[Flags]
    public enum DWMWINDOWATTRIBUTE : uint
    {
        DWMWA_WINDOW_CORNER_PREFERENCE = 33,
        DWMWA_BORDER_COLOR,
        DWMWA_VISIBLE_FRAME_BORDER_THICKNESS
    }

public enum DWM_WINDOW_CORNER_PREFERENCE
    {
        DWMWCP_DEFAULT = 0,
        DWMWCP_DONOTROUND = 1,
        DWMWCP_ROUND = 2,
        DWMWCP_ROUNDSMALL = 3
    }

SetWindowCornerRadius(hwnd, NativeValues.DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_DONOTROUND);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.