I'm using this code to animate a tray icon in a thread (icon1 and icon2 are in a .res file):
while AnimationPending do
begin
TrayIcon.Icon.Handle := LoadIcon(hInstance,'icon1');
Sleep(300);
TrayIcon.Icon.Handle := LoadIcon(hInstance,'icon2');
Sleep(300);
end;
I have the fear that it may create a memory leak if I do it in a loop because icon1/2 are loaded all over again.
Does the code create a memory leak, or is it safe to use in a loop?
You are calling LoadIcon
. That returns what are known as shared icons. This is explained in the documentation for DestroyIcon
. One of the consequences of being a shared icon is that you do not need to call DestroyIcon
.
It is only necessary to call DestroyIcon for icons and cursors created with the following functions: CreateIconFromResourceEx (if called without the LR_SHARED flag), CreateIconIndirect, and CopyIcon. Do not use this function to destroy a shared icon. A shared icon is valid as long as the module from which it was loaded remains in memory. The following functions obtain a shared icon.
- LoadIcon
- LoadImage (if you use the LR_SHARED flag)
- CopyImage (if you use the LR_COPYRETURNORG flag and the hImage parameter is a shared icon)
- CreateIconFromResource
- CreateIconFromResourceEx (if you use the LR_SHARED flag)
So, how does this relate to your code? Well, when you write
TrayIcon.Icon.Handle := LoadIcon(hInstance,'icon1');
you are assigning to the Handle
property of a TIcon
object. If that TIcon
object already contains an icon, then that icon will be destroyed before being replaced by the new icon. That's because TIcon
has ownership of its icon handles. All this means that the line of code above results in a call to DestroyIcon
for a shared icon. This is what MSDN tells you not to do, but in fact it turns out to be benign. It's nothing to worry about.
Now, even if you were using a function that returns non-shared icons, e.g. CreateIconIndirect
then your code would not leak icon handles. That's because the TIcon
class takes on ownership of the icon handle.
But since you are using shared icons, it's not even possible to leak those handles. Objects that cannot be destroyed, cannot be leaked!
Some more points:
LoadIcon
over and over like that. I would call it twice at program startup and remember the shared icon handles. Then I would use those handles to assign to TrayIcon.Icon.Handle
.LoadIcon
you do not have a lot of control over the size of the icon returned. I think that it's possible that you will get a large icon rather than a small icon. And that will need to be scaled to the small icon size before display. When creating notification area icons you should make sure that they are SM_CXSMICON
by SM_CYSMICON
sized.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With