Lazarus
Programming => Graphics and Multimedia => Graphics => Topic started by: Steve on August 14, 2015, 01:53:42 pm
-
Hi,
I am using Lazarus 1.4.2 with FPC 2.6.4 SVN 49524 32-bit on Windows 10 64-bit OS.
I am having an issue with a memory leak when using a TIcon.
var
ico: TIcon;
bmp: TBitmap;
begin
ico:= TIcon.Create;
bmp:= TBitmap.Create;
bmp.Height:= 50;
bmp.Width:= 100;
bmp.Canvas.Brush.Style:= bsSolid;
bmp.Canvas.Brush.Color:= clBlack;
bmp.Canvas.Font.Color:= clWhite;
bmp.Canvas.TextOut(10,10,'Testing');
PaintBox.Canvas.Draw(10,20, bmp);
ico.Assign(bmp);
bmp.Free;
PaintBox.Canvas.Draw(10,80, ico);
ico.Free;
After closing the application heaptrc is reporting 1 unfreed memory blocks and is referencing the ico.Assign(bmp) line.
Does anyone know what I need to do to free the memory? I have tried calling TIcon.Destroy instead of TIcon.Free but that hasn't made any difference.
Note that the code above is a simple example which reproduces the problem. The actual application is getting Windows icons with SHGetFileInfo, hence why I want the icon and not the bitmap.
Thanks
-
Possibly a bug in the LLCL, but I'm not sure...
If you assign directly an icon, everything is fine. Like: "ico.Assign(Application.Icon);"
But when a raster image is assigned, a list and one image member are created. Then, the image data are moved from the source to this new image member.
Extract of icon.inc:
procedure TCustomIcon.Assign(Source: TPersistent);
...
if Source is TRasterImage
then begin
Clear;
with TRasterImage(Source) do
Self.Add(PixelFormat, Height, Width);
AssignImage(TRasterImage(Source));
...
I've tried to free directly the images (Images[index]) and the list (FSharedImage), but apparently they are not involved in the memory leak (i.e. they are correctly freed by the LCL, IMHO).
I guess, some "intermediate" graphical object might be not freed during this operation. Furthermore, the size of the memory leak is depending of the size of the assigned raster image.
Anyway, I'm not sure to understand your last paragraph. If you don't use a raster image, it seems OK to me.
For instance (when trying to adapt your sample code):
uses ..., Windows;
procedure TForm1.Button1Click(Sender: TObject);
const SHGFI_ICON = $000000100;
var
ico: TIcon;
MyshFileInfo: SHFILEINFO;
begin
if SHGetFileInfo(PChar(ParamStr(0)), 0, MyshFileInfo, SizeOf(MyshFileInfo), SHGFI_ICON)=0 then
begin
ShowMessage('Error when calling SHGetFileInfo');
Exit;
end;
ico:= TIcon.Create;
ico.Handle := MyshFileInfo.hIcon;
PaintBox.Canvas.TextOut(10,60,'Index is '+IntToStr(MyshFileInfo.iIcon));
PaintBox.Canvas.Draw(10,80, ico);
ico.Free;
DestroyIcon(MyshFileInfo.hIcon); // Free it, if we don't need it any more
end;
I've got no memory leak with this kind of code.
-
I cannot reproduce with trunk (Lazarus 1.5 r49658:49664M FPC 3.1.1 x86_64-linux-qt).
Sorry, I can reproduce (with r. 49672), I forgot to switch HeapTrace on. Also in ico.Assign(); method.
-
Thank you so much for your detailed reply Chris. You have completely solved the problem in my application.
I had been using a TBitmap as an intermediary means of getting the icon from SHGetFileInfo into a TIcon. This was because I didn't know what I was doing and copied some code from an old post. Your reply has shown me how to do it correctly and making that change has stopped the memory leak.
This highlights the fact that I should have actually posted the real code and not an example which was just a side effect of doing something else incorrectly. Anyway, it is really great having access to more experienced and knowledgeable people on this forum! Thanks for all the replies :)