aehimself 396 Posted February 23, 2021 (edited) Hello all, I was trying to get my head around this for a while but I simply can not find the solution. In my project I have a frame which I create runtime on a TTabSheet. On this frame I have 2 TTreeView components. 1 is on the frame itself, the second one is on an inner tabsheet: Now, if the TreeView on the TabSheet has ANY items created if the application has a VCL style active, those items will not be freed up. I put a breakpoint in TTreeNode.Destroy and I can confirm that those are ONLY being called for nodes in the other TreeView. I even put TreeView2.Items.Clear in the frame's destructor, but as Owner.HandleAllocated is false at that stage, deleting all nodes never happen. So I put a breakpoint in the frame destructor and TTreeNode.Destroy, and the thing I quickly realized is that the nodes of the first TreeView are being freed before the destructor, because of a window message (TVN_DELETEITEMA or TVN_DELETEITEMW). This is actually deleting the nodes in Vcl.ComCtrls.pas : 11910. But, this message is sent only to the TreeView on the frame, not to the one in the PageControl. Again, only when VCL styles are active. I will try to send this message manually in the destructor (or explicitly deleting all nodes...?) to see if it solves my issue, but it bugs me to hell that I don't know what is happening. If I'd know where this message is sent, I could investigate why it is sent to / received by one TreeView only. Anyone has any ideas? Edit: Manually trying to delete nodes will fail, as TreeView.Items.Count shows 0 at the destructor already. Edit-edit: I have an event on the frame itself which is being called BEFORE the .Free is called upon the owning tabseet. If I move TreeView2.Items.Clear in that handler, the memory leak disappears. I guess it's an other quirk of the VCL styles but I'd still like to know the reason... Edited February 23, 2021 by aehimself 1 Share this post Link to post
pyscripter 689 Posted February 23, 2021 @Carlo Barazzetta SVGIconImageList/Demo at master · EtheaDev/SVGIconImageList (github.com) suffers from the same problem. Share this post Link to post
Carlo Barazzetta 116 Posted February 24, 2021 9 hours ago, pyscripter said: @Carlo Barazzetta SVGIconImageList/Demo at master · EtheaDev/SVGIconImageList (github.com) suffers from the same problem. Yes, and I haven't found a solution ... Share this post Link to post
Dalija Prasnikar 1396 Posted February 24, 2021 2 minutes ago, Carlo Barazzetta said: Yes, and I haven't found a solution ... Is there a bug report? Share this post Link to post
Carlo Barazzetta 116 Posted February 24, 2021 1 minute ago, Dalija Prasnikar said: Is there a bug report? No, I didn't open a bug report because in my case it was just a demo of a component with on-the-fly style modification on the form itself to show how the component reacted with different styles. Share this post Link to post
Dalija Prasnikar 1396 Posted February 24, 2021 7 minutes ago, Carlo Barazzetta said: No, I didn't open a bug report because in my case it was just a demo of a component with on-the-fly style modification on the form itself to show how the component reacted with different styles. Well, if nobody reports issues, chances they will be fixed is zero to none. Yes, there is always chance that EMBT developers themselves will eventually bump into the issue and make internal report, but those chances are rather slim. I am not judging anyone here, reporting bugs takes time, but the more people report reproducible bugs they encounter, the less bugs there will be out in the wild. Yes, I also know that report alone does not mean that bug will be promptly fixed. 1 Share this post Link to post
Attila Kovacs 629 Posted February 24, 2021 Do we know wich Delphi versions are affected? Share this post Link to post
aehimself 396 Posted February 24, 2021 10.4.1 and 10.3 for sure, I don't know about the rest. I'll check if moving .Clear in BeforeDestruction of the frame helps. That could be a workaround for most of us. Share this post Link to post
pyscripter 689 Posted February 24, 2021 The bug is not related to frames. Share this post Link to post
balabuev 102 Posted February 24, 2021 I was not able to reproduce the issue. Tried with Form>PageControl>TabSheet>Frame>PageControl>TabSheet>TreeView. Can you upload simplified demo project? 1 Share this post Link to post
aehimself 396 Posted February 24, 2021 2 minutes ago, pyscripter said: The bug is not related to frames. I had a guess about it, but since at me it is on a frame... but you are right, let me rephrase it to "moving Items.Clear to the owning component's BeforeDestruction event" to be more inclusive 🙂 Share this post Link to post
aehimself 396 Posted February 24, 2021 2 minutes ago, balabuev said: I was not able to reproduce the issue. Tried with Form>PageControl>TabSheet>Frame>PageControl>TabSheet>TreeView. Can you upload simplified demo project? My issue is that I have 5-6 TreeViews in my application in different locations and only one seems to be affected. I don't know what is the difference, this is what I was attempting to debug in the first place. If I know more, I will be able to make a small test case. Share this post Link to post
pyscripter 689 Posted February 24, 2021 5 minutes ago, balabuev said: I was not able to reproduce the issue. In the SvgIconImageList demo case, the application was compiled with the Windows default style and the error occurs when you change the style at runtime. I think that may be significant because it causes the controls to be recreated. Share this post Link to post
aehimself 396 Posted February 24, 2021 1 minute ago, pyscripter said: In the SvgIconImageList demo case, the application was compiled with the Windows default style and the error occurs when you change the style at runtime. I think that may be significant because it causes the controls to be recreated. This is interesting. I am also changing the style runtime, when the application starts. However at this stage the frame including the TreeView does not exist yet in my case so I'd say it's irrelevant. Share this post Link to post
balabuev 102 Posted February 24, 2021 1 minute ago, pyscripter said: the application was compiled with the Windows default style and the error occurs when you change the style at runtime. I think that may be significant because it causes the controls to be recreated. Tried this already, no luck. Btw, TTreeView with handle re-creation was always strange... Share this post Link to post
Attila Kovacs 629 Posted February 24, 2021 an MCVE would be nice as we could figure out which version are affected and also debug it instead of guessing 1 Share this post Link to post
pyscripter 689 Posted February 24, 2021 SVGIconImageList/Demo at master · EtheaDev/SVGIconImageList (github.com) is not a bad starting point for debugging. The treeview has no interaction with the rest of the program. Share this post Link to post
balabuev 102 Posted February 24, 2021 (edited) 48 minutes ago, pyscripter said: SVGIconImageList/Demo at master · EtheaDev/SVGIconImageList (github.com) is not a bad starting point for debugging. I removed as much as possible from your demo. It's now independent from SVG image list, and refers only to standard components. I removed almost all code also. Source.zip What is interesting: removing the bottom list view will stop the bug from occurring. Edited February 24, 2021 by balabuev 5 1 Share this post Link to post
Carlo Barazzetta 116 Posted February 24, 2021 4 hours ago, balabuev said: I removed as much as possible from your demo. It's now independent from SVG image list, and refers only to standard components. I removed almost all code also. Source.zip What is interesting: removing the bottom list view will stop the bug from occurring. Very strange that the presence of an empty ImageView in the same form affects the memory leak on another component (the TTreeNodes of the TTreeView) after changing styles! Share this post Link to post
Lajos Juhász 293 Posted February 24, 2021 (edited) 4 hours ago, balabuev said: I removed as much as possible from your demo. It's now independent from SVG image list, and refers only to standard components. I removed almost all code also. Source.zip You forgot to remove the build event. I've tested with Delphi 10.4.2 and the bug is still there: --------------------------- Unexpected Memory Leak --------------------------- An unexpected memory leak has occurred. The unexpected small block leaks are: 13 - 20 bytes: UnicodeString x 2 21 - 28 bytes: UnicodeString x 4 45 - 52 bytes: TTreeNode x 6 --------------------------- OK --------------------------- PS. It looks like that seBorder in the TListView's Styleelement is the problem. Remove it and the leak dissapear! Edited February 24, 2021 by Lajos Juhász Share this post Link to post
Attila Kovacs 629 Posted February 24, 2021 (edited) reproduced with Berlin U2 Edited February 24, 2021 by Attila Kovacs Share this post Link to post
Attila Kovacs 629 Posted February 24, 2021 You can achieve the same with two TListView's on the same parent, like a TPanel, both having one node. There is something with FTempItem or I don't know, TSubItems' constructor and destructor is not called the same time (4/3), I have no more time for debugging and I don't want to see this code anymore. I can't believe that on a theme change you have to destroy and create a component 4 times in a row. Share this post Link to post
balabuev 102 Posted February 24, 2021 Components are not destroyed on style change. Only RecreateWnd is called. Share this post Link to post
Attila Kovacs 629 Posted February 24, 2021 Sorry, I thought calling destructor TWinControl.Destroy; is equal to destroying a component. my bad Share this post Link to post
balabuev 102 Posted February 25, 2021 (edited) 9 hours ago, Attila Kovacs said: destructor TWinControl.Destroy; Hmm, now I cannot believe also. Will try to debug. Edit: These four controls - are styled scrollbars (TScrollingStyleHook.TScrollWindow). Edit: Workaround: type TTreeViewFix = class(TComponent) private FView: TTreeView; FOldWnd: TWndMethod; protected procedure Notification(C: TComponent; O: TOperation); override; procedure WndHook(var M: TMessage); public class procedure Apply(AView: TTreeView); end; procedure TTreeViewFix.Notification(C: TComponent; O: TOperation); begin inherited; if (C = FView) and (O = opRemove) then begin FView.WindowProc := FOldWnd; Free; end; end; procedure TTreeViewFix.WndHook(var M: TMessage); begin if (M.Msg = WM_NCDESTROY) and (csDestroying in FView.ComponentState) then FView.Items.Clear; FOldWnd(M); end; class procedure TTreeViewFix.Apply(AView: TTreeView); var fx: TTreeViewFix; begin fx := TTreeViewFix.Create(nil); try fx.FView := AView; fx.FOldWnd := AView.WindowProc; AView.WindowProc := fx.WndHook; AView.FreeNotification(fx); except fx.Free; raise; end; end; procedure TMainForm.FormCreate(Sender: TObject); begin TTreeViewFix.Apply(TreeView); //... end; Edited February 25, 2021 by balabuev 1 Share this post Link to post