Delphi The Strange Case of the VCL Forms ClientWidth and the Windows Versions PE Flags

FireWind

Свой
Регистрация
2 Дек 2005
Сообщения
1,957
Реакции
1,203
Credits
4,034
The Strange Case of the VCL Forms ClientWidth and the Windows Versions PE Flags
By Marco Cantu January 4, 2022

Only a few developers are aware that Windows application behave differently depending on the Windows versions declared in their PE headers in the EXE file. This has some unexpected effects Delphi customers are reporting, due to a core configuration change in Delphi 11, which went unnoticed by most.

A Windows application is stored in an EXE file in the PE format, which includes a number of PE flags that determine the application behavior in many areas. Для просмотра ссылки Войди или Зарегистрируйся. Over the last year, Embarcadero R&D team has started to witness that some Windows APIs (particularly related with the windows non-client area, but also around High DPI) were not behaving correctly in the latest versions of the operating system.
This was due to the fact that Delphi applications by default were using a fairly old Windows versions in the PE flags, despite having dropped official support for version like Windows XP. For this reason, to address some genuine API issues, in Delphi 11 Alexandria Embarcadero switched the PE flags Windows versions to 6.0.
While this change is beneficial in many areas, it can cause some significant changes in the behavior of existing VCL applications. One visible example is in the size of the windows border for in case of a bsDialog form border style. The border style become bigger and therefore the difference between the form width and its client width changes. Same for the height.
As a practical example, I’ve created a very simple VCL application with a button and two labels. Notice that the main form has this setting:
Код:
BorderStyle = bsDialog
This is the simple code of the only button:
Код:
procedure TForm10.Button1Click(Sender: TObject);
begin
  Width := 1000;
  Label1.Caption := 'Cli: ' + ClientWidth.ToString;
  Label2.Caption := 'Win: ' + Width.ToString;
end;
Now if you run this application with Delphi 11 (left) or with Delphi 10.4 (right) you’ll get different results:
1641807336753.png
With an overall form with of a 1000, I get 974 client pixels in Delphi 11, compared to 994 in older versions. That is because the border is thicker. The positive side is that the title bar has better spacing and the window caption is not crammed to the border (which was one of the bugs reported for older versions of Delphi). In other words, the window on the left, built in Delphi 11, is better looking in terms of non-client area.

By the way, notice that by default the form client width “wins” over the form width. Without the line to set the Width, in both cases you’d have the same client width and a different form width. So your components positioning (in case of absolute values) won’t be affected. It’s only by manually setting the Width that the Client Width is set to value different from the past.

Now if for any reason you want to stick with the old behavior — maybe just because it is how your existing application works — you don’t need to roll back to Delphi 10.4. The PE flags can be controlled by the compiler and linker. In fact I obtained the image on the right (the old version) by using Delphi 11 and adding to the main project file the following two compiler directives:
Код:
{$SETPEOSVERSION 4.0}
{$SETPESUBSYSVERSION 4.0}
With this code, you can revert the default change Embarcadero applied to Delphi 11 and keep using the older Windows version PE flags and the old behavior, for the good or the bad. Your choice.