Home > OS >  WinAPI - Blurring a window fails
WinAPI - Blurring a window fails

Time:11-27

I want to blur a window, and I have used DwmEnableBlurBehindWindow(), DwmExtendFrameIntoClientArea() and DwmSetWindowAttribute() (to enable the client area rendering). However, it fails to blur, and instead makes the client area white.

Minimum reproducable code:

#include <dwmapi.h>
#include <gdiplus.h>
#include <stdio.h>
#include <windows.h>

HWND hwnd;

HRESULT enableNCRendering(HWND hWnd)
{
    enum DWMNCRENDERINGPOLICY ncrp = DWMNCRP_ENABLED;

    HRESULT hr = DwmSetWindowAttribute(hWnd,
                               DWMWA_NCRENDERING_POLICY,
                               &ncrp,
                               sizeof(ncrp));

    if (!SUCCEEDED(hr))
        printf("Failed 0\n");
    return hr;
}

HRESULT EnableBlurBehind(HWND hwnd)
{
    DWM_BLURBEHIND bb = {0};

    bb.dwFlags = DWM_BB_ENABLE;
    bb.fEnable = true;
    bb.hRgnBlur = NULL;

    HRESULT hr = DwmEnableBlurBehindWindow(hwnd, &bb);
    if (!SUCCEEDED(hr))
        printf("Failed 1\n");
    return hr;
}

HRESULT ExtendIntoClientAll(HWND hwnd)
{
    MARGINS margins = {-1};
    HRESULT hr = DwmExtendFrameIntoClientArea(hwnd, &margins);
    if (!SUCCEEDED(hr))
        printf("Failed 2\n");
    return hr;
}

ATOM MyRegisterClass(HINSTANCE hInst, LPCWSTR name, UINT styles, COLORREF bkg_colour, WNDPROC proc)
{
    WNDCLASSEXW wc;
    wc.cbSize = sizeof(WNDCLASSEXW);
    wc.style = styles;
    wc.lpfnWndProc = proc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInst;
    wc.hIcon = LoadIconW(hInst, (LPCWSTR)IDI_APPLICATION);
    wc.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
    wc.hbrBackground = (HBRUSH)CreateSolidBrush(bkg_colour); // CreateSolidBrush(RGB(255, 0, 0))
    wc.lpszMenuName = NULL;
    wc.hIconSm = LoadIconW(hInst, (LPCWSTR)IDI_APPLICATION);
    wc.lpszClassName = (LPCWSTR)name;

    return RegisterClassExW(&wc);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
    switch (msg)
    {
    case WM_NCHITTEST:
        return HTCAPTION;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    }
    return DefWindowProcW(hwnd, msg, wp, lp);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MSG msg;
    MyRegisterClass(hInstance, L"Main", CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, RGB(255, 0, 0), WndProc);
    hwnd = CreateWindowExW(WS_EX_LAYERED, L"Main", L"main", WS_POPUP, 0, 0, 1000, 500, NULL, NULL, hInstance, NULL);
    if (!hwnd)
        return 1;
    SetLayeredWindowAttributes(hwnd, 0, 100, LWA_ALPHA);

    enableNCRendering(hwnd);
    EnableBlurBehind(hwnd);
    ExtendIntoClientAll(hwnd);

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while (GetMessageW(&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }
    return msg.wParam;
}

I have also tried SetWindowCompositionAttributes() but it was undefined in Mingw, and I wasn't able to find much information on using that. It also doesn't give the desired effect and gives barely any blur(https://imgur.com/a/kSZCWX1)

#include <Winerror.h>
#include <dwmapi.h>
#include <gdiplus.h>
#include <stdio.h>
#include <windows.h>

HWND hwnd;

struct ACCENTPOLICY
{
    int na;
    int nf;
    int nc;
    int nA;
};
struct WINCOMPATTRDATA
{
    int na;
    PVOID pd;
    ULONG ul;
};

typedef BOOL(WINAPI* pSetWindowCompositionAttribute)(HWND, WINCOMPATTRDATA*);

void makeBlur()
{
    const HINSTANCE hm = LoadLibraryW(L"user32.dll");
    if (hm)
    {
        const pSetWindowCompositionAttribute SetWindowCompositionAttribute = (pSetWindowCompositionAttribute)GetProcAddress(hm, "SetWindowCompositionAttribute");
        if (SetWindowCompositionAttribute)
        {
            struct ACCENTPOLICY policy = {3, 0, 0, 0};
            struct WINCOMPATTRDATA data = {19, &policy, sizeof(ACCENTPOLICY)};
            SetWindowCompositionAttribute(hwnd, &data);
        }
        FreeLibrary(hm);
    }
}
ATOM MyRegisterClass(HINSTANCE hInst, LPCWSTR name, UINT styles, COLORREF bkg_colour, WNDPROC proc)
{
    WNDCLASSEXW wc;
    wc.cbSize = sizeof(WNDCLASSEXW);
    wc.style = styles;
    wc.lpfnWndProc = proc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInst;
    wc.hIcon = LoadIconW(hInst, (LPCWSTR)IDI_APPLICATION);
    wc.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
    wc.hbrBackground = (HBRUSH)CreateSolidBrush(bkg_colour); // CreateSolidBrush(RGB(255, 0, 0))
    wc.lpszMenuName = NULL;
    wc.hIconSm = LoadIconW(hInst, (LPCWSTR)IDI_APPLICATION);
    wc.lpszClassName = (LPCWSTR)name;

    return RegisterClassExW(&wc);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
    switch (msg)
    {
    case WM_NCHITTEST:
        return HTCAPTION;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    }
    return DefWindowProcW(hwnd, msg, wp, lp);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MSG msg;

    //getting accent colors
    DWORD color = 0;
    BOOL opaque = FALSE;
    DwmGetColorizationColor(&color, &opaque);

    BYTE blue = color;

    color = color >> 8;
    BYTE green = color;
    
    color = color >> 8;
    BYTE red = color;

    color = color >> 8;
    BYTE alpha = color;

    MyRegisterClass(hInstance, L"Main", CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, RGB(red, green, blue), WndProc);
    hwnd = CreateWindowExW(WS_EX_LAYERED, L"Main", L"main", WS_POPUP, 0, 0, 1000, 500, NULL, NULL, hInstance, NULL);
    if (!hwnd)
        return 1;
    SetLayeredWindowAttributes(hwnd, 0, 100, LWA_ALPHA);

    makeBlur();

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while (GetMessageW(&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }
    return msg.wParam;
}

How can I make my window blur? Thanks in advance.

CodePudding user response:

The DwmEnableBlurBehindWindow documentation states:

Beginning with Windows 8, calling this function doesn't result in the blur effect, due to a style change in the way windows are rendered.

Aero Glass was officially discontinued in Windows 8. However, Aero Glass made a comeback (sort of) in Windows 10, as the Taskbar and some system notifications still use it. You have to use the undocumented SetWindowCompositionAttribute() API to enable the blur effect now, see:

How do you set the glass blend colour on Windows 10?

You are looking for the ACCENT_ENABLE_BLURBEHIND option.

  • Related