WINAPI/DWMAPI Blur-behind window with irregular shape

win32 transparent window
dwm blur
dwmextendframeintoclientarea example

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:

It's a native Windows program, called "Math Input Panel." Now, I'm curious about the window shape. I know that it's not completely drawn by DWM, because the borders and Close button look fishy and the window has no drop shadow (I have drop shadows enabled). My first guess as to how this was made would be using DwmEnableBlurBehindWindow, but I can't imagine that works on irregular window shapes, does it? (Or is there another way to do this, or is it just completely Microsoft sorcery?)

Here's a quickly hacked together WPF solution. It uses the hRgnBlur of the DWM_BLURBEHIND structure, and some interop.

This example will apply an ellipse-shaped background blur on the window.

You can easily convert this to an attached property or behavior for MVVM-friendliness. It's also a good idea to listen to the WM_DWMCOMPOSITIONCHANGED message and reapply the blur if needed.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        WindowStyle = WindowStyle.None;
        AllowsTransparency = true;

        SourceInitialized += OnSourceInitialized;
    }

    private void OnSourceInitialized(object sender, EventArgs eventArgs)
    {
        if (!NativeMethods.DwmIsCompositionEnabled())
            return;

        var hwnd = new WindowInteropHelper(this).Handle;

        var hwndSource = HwndSource.FromHwnd(hwnd);
        var sizeFactor = hwndSource.CompositionTarget.TransformToDevice.Transform(new Vector(1.0, 1.0));

        Background = System.Windows.Media.Brushes.Transparent;
        hwndSource.CompositionTarget.BackgroundColor = Colors.Transparent;

        using (var path = new GraphicsPath())
        {
            path.AddEllipse(0, 0, (int)(ActualWidth * sizeFactor.X), (int)(ActualHeight * sizeFactor.Y));

            using (var region = new Region(path))
            using (var graphics = Graphics.FromHwnd(hwnd))
            {
                var hRgn = region.GetHrgn(graphics);

                var blur = new NativeMethods.DWM_BLURBEHIND
                {
                    dwFlags = NativeMethods.DWM_BB.DWM_BB_ENABLE | NativeMethods.DWM_BB.DWM_BB_BLURREGION | NativeMethods.DWM_BB.DWM_BB_TRANSITIONONMAXIMIZED,
                    fEnable = true,
                    hRgnBlur = hRgn,
                    fTransitionOnMaximized = true
                };

                NativeMethods.DwmEnableBlurBehindWindow(hwnd, ref blur);

                region.ReleaseHrgn(hRgn);
            }
        }
    }

    [SuppressUnmanagedCodeSecurity]
    private static class NativeMethods
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct DWM_BLURBEHIND
        {
            public DWM_BB dwFlags;
            public bool fEnable;
            public IntPtr hRgnBlur;
            public bool fTransitionOnMaximized;
        }

        [Flags]
        public enum DWM_BB
        {
            DWM_BB_ENABLE = 1,
            DWM_BB_BLURREGION = 2,
            DWM_BB_TRANSITIONONMAXIMIZED = 4
        }

        [DllImport("dwmapi.dll", PreserveSig = false)]
        public static extern bool DwmIsCompositionEnabled();

        [DllImport("dwmapi.dll", PreserveSig = false)]
        public static extern void DwmEnableBlurBehindWindow(IntPtr hwnd, ref DWM_BLURBEHIND blurBehind);
    }
}

Used with the following XAML:

<Window x:Class="WpfTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="200" Width="300" WindowStartupLocation="CenterScreen">

    <Border Background="#800000FF" Margin="30">
        <TextBlock Text="Hello, world!" VerticalAlignment="Center" HorizontalAlignment="Center" />
    </Border>
</Window>

The result is:

Blur Behind option for WPF Controls within the application, I was able to add the blur behind option to the Window based on the /​27787966/winapi-dwmapi-blur-behind-window-with-irregular-shape. Enables the blur effect on a specified window. Syntax DWMAPI DwmEnableBlurBehindWindow( HWND hWnd, const DWM_BLURBEHIND *pBlurBehind ); Parameters. hWnd. The handle to the window on which the blur behind data is applied. pBlurBehind. A pointer to a DWM_BLURBEHIND structure that provides blur behind data. Return value

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:

...and source code:

MainWindow.xaml:

<Window x:Class="IrregularGlassWindow.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Height="500"
        Width="500"
        Background="#01FFFFFF"
        AllowsTransparency="True"
        WindowStyle="None"
        ResizeMode="NoResize">
  <Window.Clip>
    <PathGeometry>
      <PathFigure StartPoint="250,0">
        <ArcSegment Point="250,500"
                    RotationAngle="180"
                    Size="250,250"
                    SweepDirection="Clockwise" />
        <ArcSegment Point="250,0"
                    RotationAngle="180"
                    Size="250,250"
                    SweepDirection="Clockwise" />
      </PathFigure>
    </PathGeometry>
  </Window.Clip>
  <Grid>
    <Ellipse Margin="1"
             Width="498"
             Height="498"
             Stroke="#8FFF"
             StrokeThickness="1.25" />
    <Ellipse Width="500"
             Height="500"
             Stroke="#C000"
             StrokeThickness="1"/>
  </Grid>
</Window>

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.

DwmEnableBlurBehindWindow function (dwmapi.h), DWMAPI DwmEnableBlurBehindWindow( HWND hWnd, const The handle to the window on which the blur behind data is applied. To apply the blur behind a subregion, apply a valid region handle (HRGN) to the hRgnBlur member of the DWM_BLURBEHIND structure and add the DWM_BB_BLURREGION flag to the dwFlags member. When you apply the blur-behind effect to a subregion of the window, the alpha channel of the window is used for the nonblurred area.

This is simply two borderless windows attempting to emulate the DWM. This is evidenced with the inconsistencies in the theme with shadows and the "fishy" close button and the break in the gradient of the right "subwindow." A simple query of the DWM would have given the proper hints to render the windows correctly.

There is no "sorcery involved," since both of the windows are perfectly square. The main window has a shape associated with it, causing the insert button to appear while the rest of the bottom appears translucent. The same effect could be achieved using either GDI+ or WPF.

I am purposing a clarification of how the original effect was created, and not a way to duplicate it. That has been successfully demonstrated by previous answers.

Questions for tag dwmapi, WINAPI/DWMAPI Blur-behind window with irregular shape. NB: THIS IS NOT A QUESTION ABOUT A BORDERLESS WINDOW. So, I stumbled upon this  DWM Blur Behind Constants. 05/31/2018; 2 minutes to read; In this article. Flags used by the DWM_BLURBEHIND structure to indicate which of its members contain valid information. DWM_BB_ENABLE. 0x00000001. A value for the fEnable member has been specified. DWM_BB_BLURREGION. 0x00000002. A value for the hRgnBlur member has been specified. DWM_BB

Glass Effect Extender Library for your Applications, Custom window frame using DWM: how to refresh it after remote desktop connetion? WINAPI/DWMAPI Blur-behind window with irregular shape · Hook to Win32  dwFlags. A bitwise combination of DWM Blur Behind constant values that indicates which of the members of this structure have been set. fEnable. TRUE to register the window handle to DWM blur behind; FALSE to unregister the window handle from DWM blur behind. hRgnBlur.

[SOLVED!] Windows: Transparent window with opaque contents , Windows Glass (Blur) Effect. The Glass or Blur Effect is an effect of the title bars and frame borders of the windows that display the items behind  WINAPI/DWMAPI Blur-behind window with irregular shape Here's a quickly hacked together WPF solution. It uses the hRgnBlur of the DWM_BLURBEHIND structure, and some interop.

knight of elf - 애들은 잘놀아, I'm not looking for any irregular window shapes, just a fullscreen, transparent rectangle. If that is the case, I need to have Windows set the background color, not Unity. [DllImport("Dwmapi.dll")] It's probably possible - WinAPI is so vast that it probably has a way to achieve it. like this but wihtout blur. 4 WINAPI/DWMAPI Blur-behind window with irregular shape Jan 5 '15 3 WINAPI/DWMAPI Blur-behind window with irregular shape Jan 5 '15 2 How do I wait for an asynchronous event to be called?

Comments
  • This ain't wpf, unless you can prove otherwise. But then, if you tried (by using snoop, for example) you'd have your answer.
  • I know it's not WPF. It's probably within the realm of Winapi, but I would prefer a solution that works with WPF. In fact, I think hRgn might be the answer...
  • It's sorcery. There is no wpf solution. Also, asking for libraries (like specialized window chrome libraries) is verboten. Hacking window chrome is a royal pain in the ass, with little benefit (the only chrome hack I've ever seen that didn't suck was ... Chrome).
  • As I said before, I know it's not WPF. I think using DwmEnableBlurBehindWindow and complex hRgns might be the solution, but I must conduct further testing.
  • @rookie1024 The DWM_BLURBEHIND structure has a hRgnBlur field. Just apply a non-rectangular region to it. Wrap everything in a nice attached property or behavior to make it MVVM-friendy and you'll have your WPF solution.
  • Looks similar enough to my answer that I'll use that, although I may have forgotten to dispose some stuff. Oh, well, that should be dealt with by garbage collection (I hope). Do you think that's an issue?
  • @rookie1024 it would be an issue if this was called often, but as it's called only once you should be fine. The wrappers' finalizers will take care of everything. But what I'd add to your solution is what I did with sizeFactor - this takes into account the user's DPI settings (control panel -> display). And I suggest handling WM_DWMCOMPOSITIONCHANGED too if you don't want your app to look ugly after an Aero on/off switch.
  • Is there any way to set the color of the blurred background. My Areo settings on my desktop are orange? However I would like the app to be white regardless of the users Windows Color Settings.
  • @Mike AFAIK there's no option for this, at least not in DWM_BLURBEHIND
  • How to implement this in winform?
  • @IlPADlI Well, I don't know much about the behind-the-scenes stuff for WinForms, and this solution is probably specific to WPF since it uses a special WPF helper (WindowChrome) to achieve it, but a possible solution might be getting the HWND of your window and using P/Invoke to run the DWMAPI methods. You'll probably want to ask that as a separate question, though.
  • Thanks you for reply! I found the way to implement it. OnPaintBackground to clear black or alpha color,OnSizeChanged to create Gdi Rgn and DwmEnableBlurBehindWindow.