Search code examples
c++winapiblurdwm

What are the requirements for window to be blurred, except SetWindowCompositionAttribute call?


I have a dll library that deals with windows: you can simply create windows, draw graphics, etc. Also this library provides you to make blurred windows for Win7 and Win10.

I have two almost same builds of library - one , older without sources, and one newer with sources.

I am writing some app in Win10 and have been using old library, but now decided to compile new build. It works almost the same, as I said, except blur - it doesn’t work. Here is the client code:

HWND hwnd; // here stored window created by library function

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

const HINSTANCE hm = LoadLibrary(L"user32.dll");
if (hm)
{
  typedef BOOL(WINAPI*pSetWindowCompositionAttribute)(HWND, WINCOMPATTRDATA*);

  const pSetWindowCompositionAttribute SetWindowCompositionAttribute = (pSetWindowCompositionAttribute)GetProcAddress(hm, "SetWindowCompositionAttribute");
  if (SetWindowCompositionAttribute)
  {
    ACCENTPOLICY policy = { 3, 0, 0, 0 }; // and even works 4,0,155,0 (Acrylic blur)
    WINCOMPATTRDATA data = { 19, &policy,sizeof(ACCENTPOLICY) };
    SetWindowCompositionAttribute(hwnd, &data);
  }
  FreeLibrary(hm);
}

It completely works in old library and doesn’t work in new - window is not transparent at all, and hence no blur.

Details

I am calling function from my library, that creates window, returns hwnd, then set background color with alfa, and then run code above. Nothing else.

In sources I have, window creates as CreateWindowEx without WS_EX_LAYERED. I tried to add this flag, add DwmBlurBehindWindow call, add SetLayeredWindowAttribute with LWA_ALPHA or LWA_COLORKEY, but the only result I got - transparency, without any blur.

Here is some code from WM_PAINT:

hdc = BeginPaint(hwnd, &ps);
hdcc = CreateCompatibleDC(hdc);
BITMAPINFO bmi;
LPBYTE bits;

ZeroMemory(&bmi, sizeof(bmi));

bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = ps.rcPaint.right - ps.rcPaint.left;
bmi.bmiHeader.biHeight = ps.rcPaint.bottom - ps.rcPaint.top;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;

bm = CreateDIBSection(hdcc, &bmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);

//All draws here. The first one is Gdi+ background draw with alfa brush

SetStretchBltMode(hdc, COLORONCOLOR);
SetStretchBltMode(hdcc, COLORONCOLOR);

StretchBlt(hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, hdcc, 0, 0, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, SRCCOPY);
EndPaint(hwnd,&ps);

What did I miss?


Old library, same code in client:

enter image description here

New library, DwmBlurBehindWindow call, setting WS_EX_LAYERED or SetLayeredWindowAttribute calling doesn’t make any effect, same code in client:

enter image description here

New library, without DwmBlurBehindWindow, same code in client:

enter image description here


Solution

  • I do not really understand what I did, but now it works.

    First of all, I should say, that library provides not just function, but an interface - abstract class.

    The second one - HWND of created window is actually doesn’t returns, because function that creates window is void. I found window by FindWindow().

    GetLastError() after SetWindowCompositionAttribute() returned 6, but now, if when it works it returns 10 - ERROR_BAD_ENVIRONMENT 10 (0xA) The environment is incorrect.

    Also I was getting crashes trying to call MessageBox() to display the error code. The program crashed even if I just check whether hwnd equals to NULL or not.

    Summary

    As I mentioned in question, I decided to make new build, because I wanted sone new features. Seems, the abstract interface class in current fresh dll is not the same as in client, but in the old one dll is. I think the problem is in this.