I have an icon file that contains a 24x24, 32x32, 48x48, 64x64, and 256x256 icon. However, when I load it like this:
Application->Icon->LoadFromFile("filename.ico");
it appears to only load the one image from the file, despite the fact that my icon contains multiple resolutions of the icon. The result is that any Forms use the single icon re-scaled for both the taskbar icon, and the corner icon, which looks bad.
However, if I set filename.ico
into a compiled resource, or if I set the icon in Project Properties > Application > Icon, then my Forms use the 24x24 icon for the corner icon, and the 48x48 icon for the taskbar.
My question is: how can I have my Forms use the icons from filename.ico
where the filename is not known until runtime; but still use the 24x24 icon for the corner and use the 48x48 icon for the taskbar?
NB. I prefer not to hardcode those sizes 24x24, and 48x48, because other versions of Windows (or if the person uses the windows font scaling option) may then call for a different size icon.
When you call
TIcon.LoadFrom...()
, it stores a copy of the raw icon data into an internal memory block and then exits. That block is not processed until the next time thatTIcon.HandleNeeded()
is called, such as when theTIcon.Handle
property is used.If the icon data represents an icon of type
RC3_STOCKICON
(not usually encountered), theIDI_APPLICATION
icon fromLoadIcon()
is used. Otherwise, if the icon data represents an icon of typeRC3_ICON
(the usual case), the data is parsed and the image that most closely matches the currentTIcon.Width
andTIcon.Height
property values (or theSM_CXICON
andSM_CYICON
metrics viaGetSystemMetrics()
if theTIcon
dimensions have not been assigned yet) are passed toCreateIcon()
.From that point on, the
HICON
returned byLoadIcon()
orCreateIcon()
is the image used for the remainder of theTIcon
's lifetime, or at least until theHICON
is freed/released viaTIcon.ReleaseHandle()
,TIcon.Assign()
,TIcon.LoadFrom...()
,TIcon.SetHandle()
, etc.The memory block itself is only freed when the
TIcon
is freed,TIcon.Assign()
is called, or a new image source is loaded. So it should be possible, for instance, to callTIcon.ReleaseHandle()
to release the currentHICON
(you will then have to free it manually viaDestroyIcon()
), then resize theTIcon
's dimensions, and then callTIcon.HandleNeeded()
to re-parse the memory block to load the next closest matching image.Update:
TIcon
cannot have multiple images of different resolutions loaded at the same time. AForm
's corner icon and its Taskbar icon (and remember, whenApplication->MainFormOnTaskbar
is false, the Taskbar button is controlled by the hiddenApplication
window, not theMainForm
window, unless you override that behavior manually) are actually separate icons at the OS layer, assigned via theWM_SETICON
message using different input parameters (wParam=ICON_SMALL
andwParam=ICON_BIG
, respectively). However, the VCL only ever usesWM_SETICON
to set a window's BIG icon, never its SMALL icon. So aForm
's corner icon is just a scaled down version of its Taskbar icon (whenMainFormOnTaskbar
is true) or theApplication
's Taskbar button (whenMainFormOnTaskbar
is false). When the VCL issuesWM_SETICON
for aForm
, it used theForm
's ownIcon
if assigned, otherwise it uses theApplication
'sIcon
if assigned, otherwise it usesLoadIcon()
to load the defaultIDI_APPLICATION
icon.So, if you really want different icons of different resolutions for the
Form
's corner icon and Taskbar icon, you will have to use separateTIcon
objects to load the desired resolution images, as described above, and then issue your ownWM_SETICON
messages accordingly.