Using Delphi XE7 on a Windows 7 Pro 64-bit system. If I choose 'Charcoal Dark Slate' VCL style, the 16x16 pixel titel bar icon down-sized from the 32x32 program icon looks not like expected.
It should look like the small icon below. If I load the program icon in 16x16 pixel format, it looks good in the titel bar, but ugly in the task bar because of the 16 to 32 pixel enlargement.
This is known issue with VCL Styles http://qc.embarcadero.com/wc/qcmain.aspx?d=106224
Also see this issue in Embarcadero's newer QC site: https://quality.embarcadero.com/browse/RSP-11572 --- it's been 3 years since initially reported, and still not fixed. If enough people vote for that issue, maybe it will get some attention.
As workaround you can load proper 16x16 icon into form's
Icon
property.In order for that to work you have to also set
Application.MainFormOnTaskBar := false;
in your.dpr
fileHowever that has some other undesirable effects because it will disable Windows Vista or Windows 7 Aero effects, including live taskbar thumbnails, Dynamic Windows, Windows Flip, and Windows Flip 3D. See: MainFormOnTaskBar
In any case do not change your application icon size because it is the worst solution.
I finally got to the bottom of this issue, and figured out why this worked without VCL styles, and doesn't work with VCL styles.
Preface: For years, VCL has not supported the concept of an icon graphic with multiple icon sizes: a
TIcon
was always assumed to be one single graphic - not a set of graphics of varying dimensions and resolutions. This is still true, and a design issue probably not easy to correct in the VCL.The VCL will set the form icon by way of the
WM_SETICON
message. VCL always setswParam
toICON_BIG
: an examination of VCL sources shows it never usesICON_SMALL
when setting the icon. Additionally, thehIcon
andhIconSm
member variables ofWNDCLASSEX
structure are alwaysNULL
when creating the window class. Therefore, it's clear that VCL never even attempts to set a small icon. Normally, if an app never sets a small icon, Windows will resize the large icon to be the small size, which is quite ugly. However, there is an important exception to that rule.Note that a Windows resource file's
ICON
resource will actually store what is known as an icon group, which is a set of the individual icon images from the original.ico
file. TheLoadIcon
API states that only the large 32x32 icon will be loaded. However, this is not actually strictly true. It seems that Windows itself maintains a link between anHICON
and the original resource, so that if icons of other sizes are required, Windows can go load them as needed.This fact is not well-documented, but there is one place in MSDN that states this fact:
WNDCLASSEX
structure,hIconSm
variable:Therefore, even though VCL did not support small icons properly by way of the public
TForm.Icon
class (e.g. by assigning it from the property editor at design time), it was still possible to get things working right using one of these two methods:Leave the
TForm.Icon
property unset (no icon). In that case, the form will get the icon fromTApplication.Icon
. The default value of this comes from the application'sMAINICON
resource. FromTApplication.Create
:If you don't want to use the application default icon, you can load a different icon resource at runtime; in C++:
Therefore, VCL provides basic support for small icons, because it supports loading icons from resources, and Windows supports loading small icons from large icons that were loaded from a resource.
The problem: VCL styles obviously does not rely on Windows-default rendering behavior for non-client areas, such as the title bar. Instead, it handles all the rendering itself. One task in rendering is that VCL styles must determine what icon to render. As it turns out, even though the main VCL form classes don't support small icons - the VCL styles hook does! Well, sort of. This happens in
TFormStyleHook.GetIcon
:The problem is that the hook calls
WM_GETICON
withICON_SMALL
and notICON_SMALL2
. From MSDN:ICON_SMALL
: Retrieve the small icon for the window.In the above code, this will return
NULL
because VCL is not setting a small icon.ICON_SMALL2
: Retrieves the small icon provided by the application. If the application does not provide one, the system uses the system-generated icon for that window. (emphasis mine)In the above code, this would return a real
HICON
: the question is how does the system generate the icon? My experiments show that one way or another, you'll get a small icon:The fix: VCL needs to use
ICON_SMALL2
instead ofICON_SMALL
whenever callingWM_GETICON
. (Note there is similar code inTFormStyleHook.TMainMenuBarStyleHook.GetIcon
that will also require fixing.) Since this is such a trivially easy fix, I hope Embarcadero applies it soon.The workaround: Until VCL is fixed, you have to make your own derived form hook. Unfortunately,
TFormStyleHook.GetIcon
is private, and really hard to get to. So we try a different technique: alter message handling behavior forWM_GETICON
whenwParam
isICON_SMALL
so that it will instead be likeICON_SMALL2
.@James Johnston,
Thank you! It works fine for me although there was a small glitch in the posted code:
Message.Result = SendMessage(this->Control->Handle, WM_GETICON, ICON_SMALL2, Message.LParam); PreventRecursion = false; this->Handled = true;
Remove
PreventRecursion = false;
Here is the Delphi port of your code:
Then in your DPR project: