WINAPI/DWMAPI Blur-behind window with irregular shape

前端 未结 3 967
[愿得一人]
[愿得一人] 2021-02-10 15:29

NB: THIS IS NOT A QUESTION ABOUT A BORDERLESS WINDOW.

So, I stumbled upon this program while I was exploring my Start menu the other day on Windows 7:

3条回答
  •  甜味超标
    2021-02-10 16:03

    So, unbeknownst to me, hRgn can take an irregular shape (and DwmEnableBlurBehindWindow takes an hRgn, but I knew that). So, here's my solution that's (more or less) compatible with WPF:

    My own custom-shaped glass window

    ...and source code:

    MainWindow.xaml:

    
      
        
          
            
            
          
        
      
      
        
        
      
    
    

    MainWindow.xaml.cs:

    public partial class MainWindow : Window {
      public MainWindow() {
        InitializeComponent();
    
        this.SourceInitialized += MainWindow_SourceInitialized;
        this.KeyDown += MainWindow_KeyDown;
      }
    
      void MainWindow_KeyDown(object sender, KeyEventArgs e) {
        if (e.Key == Key.Escape) this.Close();
      }
    
      void MainWindow_SourceInitialized(object sender, EventArgs e) {
        var helper = new WindowInteropHelper(this);
        var hwnd = helper.Handle;
        var src = HwndSource.FromHwnd(hwnd);
    
        src.CompositionTarget.BackgroundColor = Colors.Transparent;
    
        WindowChrome.SetWindowChrome(this, new WindowChrome {
          CaptionHeight = 500,
          CornerRadius = new CornerRadius(0),
          GlassFrameThickness = new Thickness(0),
          NonClientFrameEdges = NonClientFrameEdges.None,
          ResizeBorderThickness = new Thickness(0),
          UseAeroCaptionButtons = false
        });
    
        GraphicsPath path = new GraphicsPath(FillMode.Alternate);
        path.StartFigure();
        path.AddArc(new RectangleF(0, 0, 500, 500), 0, 360);
        path.CloseFigure();
    
        var dbb = new DwmBlurBehind(true);
        dbb.SetRegion(Graphics.FromHwnd(hwnd), new Region(path));
        DwmApi.DwmEnableBlurBehindWindow(hwnd, ref dbb);
      }
    }
    

    I think somebody else beat me to it, but here's how my solution works:

    When the window's SourceInitialized event is fired, that means that we have a handle for our window. So in the handler of this function, I get the window handle. Then I make a call to a function I imported from dwmapi.dll called DwmEnableBlurBehindWindow. This basically turns transparent areas of the window into glass for a certain region. The DwmBlurBehind struct I got from pinvoke.net, and it converts a GDI+ System.Drawing.Region into an hRgn. The hRgn is passed to DwmEnableBlurBehindWindow, and it clips the transparent parts to the Region. In this case, I used a circle. Then the XAML is just the accent borders. It's worth noting that, for some reason, setting Window.Background to Transparent doesn't enable hit-testing when AllowsTransparency is true here. No idea why, but it probably has something to do with the code-behind.

提交回复
热议问题