WS_EX_LAYERED Style for Child Windows in Windows 8

  • Tutorial
On Windows, you cannot just make a translucent control; you must either draw all the controls yourself (Qt, FMX) or use DrawThemeParentBackground , which inevitably leads to brakes.
The regions will not help here. they do not support partial transparency.
It would be convenient to use windows with the WS_EX_LAYERED style ("Layered" windows that support alpha transparency of individual pixels), but Windows only supports this style for top-level windows. So it was before Windows 8 in which , not even half a century has passed, it finally became possible to assign this style to child windows.

What does it give? The first thing that comes to mind is that the video card will deal with the composition of the windows, which will give a performance boost.

Under cat, a little research into this feature of Windows 8 .

All code examples will be presented in Delphi , however, a similar approach can be used in other languages.

Let's try to create such a translucent button:

To simplify, we will not draw it using GDI + , but just use the ready-made 32-bit BitMap.

Let's create a new Vcl application, add a TImage to the form and upload our 32-bit BitMap there.
We also add a button to the form, when clicked we will create 100 “buttons”. We will make

our Layered component a successor from TButton , in which we add a constructor that accepts a 32-bit BitMap with an image of our button and overrides the CreateWnd procedure responsible for creating the window:
  TWin8Control = class(TButton)
    WinBitMap: TBitMap;
    procedure CreateWnd; override;
    constructor Create(AOWner: TComponent; BitMap: TBitMap);
// ...
constructor TWin8Control.Create(AOWner: TComponent; BitMap: TBitMap);
  inherited Create(AOwner);
  WinBitMap := BitMap;
procedure TWin8Control.CreateWnd;
  bf: TBlendFunction;
  BitmapSize: TSize;
  if Assigned(WinBitMap) then
    // убедимся в том что у нас Premultiplied битмап
    WinBitMap.AlphaFormat := afPremultiplied;
    bf.BlendOp := AC_SRC_OVER;
    bf.BlendFlags := 1;
    bf.AlphaFormat := AC_SRC_ALPHA;
    bf.SourceConstantAlpha := 255;
    // получаем размеры BitMap := WinBitMap.Width; := WinBitMap.Height;
    BitmapPos.X := 0;
    BitmapPos.Y := 0;
    // добавляем "слоистый" стиль окна
    SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED);

Let's now create 100 child Layered windows in the handler of our button :
procedure TfrmMain.btnAdd100Click(Sender: TObject);
  i: Integer;
  Win8Control: TWin8Control;
  for i := 0 to 99 do
    Win8Control := TWin8Control.Create(Self, Image.Picture.Bitmap);
    Win8Control.Parent := Self;
    Win8Control.Top := Random(400);
    Win8Control.Left := Random(400);

Launch the application and click on the button:

... And note that for some reason the WS_EX_LAYERED style did not apply to the child windows .

As it turned out, the whole point is that this feature does not work until you specify Windows 8 support in the application manifest (which is not explicitly indicated on msdn ):

Add these lines to the manifest, connect it to the project, run it again and click on the button:

Hooray, it works!

However, not everything is so rosy ...
The first thing that catches your eye is that such windows are created very slowly, about 10 times slower than usual.
The second is that even elementary dragging of a window began to slow down, not to mention resizing, during which you can observe wonderful artifacts (I apologize for the photo from the screen, but due to the specific operation of Windows with such windows, it is not visible in the screenshots of artifacts):

This is a must see, do not be lazy and play with an example.

If you press the button several times, then not only the application will freeze, but also ... the whole system, which does not happen when creating ordinary windows.
This leads to the conclusion that, unfortunately, such a great opportunity was not implemented high-quality, and its use in real applications is not possible .

And one more experiment, about how to suspend the whole system (just save all your data first).
Add one more button to the form and make such an endless loop in the handler:
procedure TfrmMain.LoopClick(Sender: TObject);
  Win8Control: TWin8Control;
  while True do
    Win8Control := TWin8Control.Create(Self, Image.Picture.Bitmap);
    Win8Control.Parent := Self;
    Win8Control.Top := Random(400);
    Win8Control.Left := Random(400);

After clicking on the button, Windows will only be busy creating Layered windows and will not respond anything even to Ctrl + Alt + Del :)

GitHub project:

Also popular now: