I have an application having 2 Forms, each Form and Application have individual Icon. O
TL;DR version: Don't set the Icon
property to any value other than that obtained by loading from a Win32 resource that contains multiple icon sizes. For example, only use TIcon.LoadFromResourceName
. If you set the Icon
property in the form designer, only one icon size will ever be used, resulting in scaling artifacts.
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 sets wParam
to ICON_BIG
: an examination of VCL sources shows it never uses ICON_SMALL
when setting the icon. Additionally, the hIcon
and hIconSm
member variables of WNDCLASSEX
structure are always NULL
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. The LoadIcon 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 an HICON
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:
A handle to a small icon that is associated with the window class. If this member is NULL, the system searches the icon resource specified by the hIcon member for an icon of the appropriate size to use as the small icon.
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 from TApplication.Icon
. The default value of this comes from the application's MAINICON
resource. From TApplication.Create
:
FIcon := TIcon.Create;
FIcon.Handle := LoadIcon(MainInstance, 'MAINICON');
If you don't want to use the application default icon, you can load a different icon resource at runtime; in C++:
myForm->Icon->LoadFromResourceName(FindHInstance(...), L"OtherResource");
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.
If you use VCL styles, see my answer to a related bug here: https://stackoverflow.com/a/35067909/562766