📜 ⬆️ ⬇️

WS_EX_LAYERED style for child windows in Windows 8

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

What does this give? The first thing that comes to mind is that the video card will be engaged in the composition of the windows, which will give a performance boost.

Under the cat a little research of this feature of Windows 8 .

All code samples will be presented in Delphi , but this approach can be used in other languages.

Let's try to create such a translucent button:

For simplicity, we will not draw it with GDI + tools, but simply use a ready-made 32-bit BitMap.
')
Create a new Vcl application, add a TImage to the form and load our 32-bit BitMap there.
We will 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 the image of our button, and override the CreateWnd procedure responsible for creating the window:
TWin8Control = class(TButton) private WinBitMap: TBitMap; public procedure CreateWnd; override; constructor Create(AOWner: TComponent; BitMap: TBitMap); end; // ... constructor TWin8Control.Create(AOWner: TComponent; BitMap: TBitMap); begin inherited Create(AOwner); WinBitMap := BitMap; end; procedure TWin8Control.CreateWnd; var bf: TBlendFunction; BitmapSize: TSize; BitmapPos:Tpoint; begin inherited; if Assigned(WinBitMap) then begin //       Premultiplied  WinBitMap.AlphaFormat := afPremultiplied; bf.BlendOp := AC_SRC_OVER; bf.BlendFlags := 1; bf.AlphaFormat := AC_SRC_ALPHA; bf.SourceConstantAlpha := 255; //   BitMap BitmapSize.cx := WinBitMap.Width; BitmapSize.cy := WinBitMap.Height; BitmapPos.X := 0; BitmapPos.Y := 0; //  ""   SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED); UpdateLayeredWindow( Handle, 0, nil, @BitmapSize, WinBitMap.Canvas.Handle, @BitmapPos, 0, @bf, ULW_ALPHA ); end; end; 


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


Run the application and click on the button:

... And note that for some reason, the WS_EX_LAYERED style has not been applied to the child windows.

As it turned out, the whole thing is that this feature does not work until the application manifest shows support for Windows 8 (which is not explicitly stated on msdn ):
  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> <application> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> </application> </compatibility> 


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

Hurray, it works!

However, not everything is so rosy ...
The first thing that catches your eye is that such windows are created very slowly, 10 times slower than usual.
The second is that even elementary dragging of the window, let alone resize, under which you can observe wonderful artifacts (I apologize for the photo from the screen, but due to the specific work of Windows with such windows, is not visible on the screenshots of artifacts), has slowed down:

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

If you press the button several times, it will freeze not only the application, 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 qualitatively, and its use in real applications is not possible .

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

After clicking on the button, Windows will only be busy creating Layered windows and nothing else will react even to Ctrl + Alt + Del :)

Project on GitHub: https://github.com/errorcalc/LayeredTest

Source: https://habr.com/ru/post/247397/


All Articles