TreeView Control will leak normal ImageList but ListView control doesn't?

153 views Asked by At

I was using task manager to watch my dynamically created controls and found each time I'd create a TreeView with an ImageList, the GDI objects count would increase by 4 each time I destroyed the tree and created again. However, a ListView never had a problem.

I know of the TVS_CHECKBOXES issues with the state images and was already destroying of the state imagelist, but I then implemented:

ImageList_Destroy(TreeView_SetImageList(GetHandle(), nullptr, TVSIL_NORMAL));

and now the resource leak is gone.

So far it looks like you have to manually clean up images in WM_DESTROY for the following:

Button_SetImageList() - Have to set it to switch it to `BUTTON_IMAGELIST.himl=BCCL_NOGLYPH` to clear it.
TreeView_SetImageList(LVILS_STATE) - if you set it or used `TVS_CHECKBOXES`
TreeView_SetImageList(LVILS_NORMAL) - if you set it
BM_SETIMAGE and STM_SETIMAGE - destroy your own but also set to NULL and destroy returned handle to get rid of potential hidden bitmap handle if different handle than your own.

But a ListView is different, is that by design or should I just go ahead in WM_DESTROY with something like:

ImageList_Destroy(ListView_SetImageList(GetHandle(), nullptr, LVSIL_STATE));
ImageList_Destroy(ListView_SetImageList(GetHandle(), nullptr, LVSIL_SMALL));
ImageList_Destroy(ListView_SetImageList(GetHandle(), nullptr, LVSIL_NORMAL));

Note that using WM_NCDESTROY is too late for TreeViews.

2

There are 2 answers

0
Remy Lebeau On BEST ANSWER

What you are seeing is documented behavior.

For a TreeView:

TVM_SETIMAGELIST message
TreeView_SetImageList macro

The tree-view control will not destroy the image list specified with this message. Your application must destroy the image list when it is no longer needed.

As well as:

Tree-View Control Window Styles

Constant Description
TVS_CHECKBOXES Version 4.70. Enables check boxes for items in a tree-view control. A check box is displayed only if an image is associated with the item. When set to this style, the control effectively uses DrawFrameControl to create and set a state image list containing two images. State image 1 is the unchecked box and state image 2 is the checked box. Setting the state image to zero removes the check box altogether. For more information, see Working with state image indexes.

Version 5.80. Displays a check box even if no image is associated with the item. Once a tree-view control is created with this style, the style cannot be removed. Instead, you must destroy the control and create a new one in its place. Destroying the tree-view control does not destroy the check box state image list. You must destroy it explicitly. Get the handle to the state image list by sending the tree-view control a TVM_GETIMAGELIST message. Then destroy the image list with ImageList_Destroy.

If you want to use this style, you must set the TVS_CHECKBOXES style with SetWindowLong after you create the treeview control, and before you populate the tree. Otherwise, the checkboxes might appear unchecked, depending on timing issues.

Compared to a ListView:

LVM_SETIMAGELIST message
ListView_SetImageList macro

The current image list will be destroyed when the list-view control is destroyed unless the LVS_SHAREIMAGELISTS style is set. If you use this message to replace one image list with another, your application must explicitly destroy all image lists other than the current one.

0
Jonathan Potter On

The two controls are inconsistent in this regard.

The tree control does not take ownership of the imagelist you give it, so you remain responsible for freeing it.

The listview control does take ownership, unless you set the LVS_SHAREIMAGELISTS window style.

Note that the tree control also has a related quirk; if you set the TVS_CHECKBOXES style, you are responsible for freeing the state image list even though you didn't create it.