TreeView控件会泄露普通ImageList资源但ListView不会,是设计如此吗?
公共控件ImageList资源泄漏处理指南与常见疑问解答
问题背景
我此前通过任务管理器观察动态创建的控件时发现:每次创建绑定了ImageList的TreeView,再销毁重建该TreeView时,GDI对象计数每次都会增加4个,但ListView控件始终没有这类问题。
我已知晓TVS_CHECKBOXES与状态图像相关的问题,且已经会主动销毁状态图像列表,之后我又新增了如下实现:
ImageList_Destroy(TreeView_SetImageList(GetHandle(), nullptr, TVSIL_NORMAL));
至此资源泄漏问题彻底消失。
已验证的必填清理规则
你需要在WM_DESTROY消息中手动清理以下场景的图像资源:
Button_SetImageList():需将其设置为BUTTON_IMAGELIST.himl=BCCL_NOGLYPH以完成清理TreeView_SetImageList(LVILS_STATE):若你主动设置过该属性或使用了TVS_CHECKBOXESTreeView_SetImageList(LVILS_NORMAL):若你主动设置过该属性BM_SETIMAGE和STM_SETIMAGE:先销毁你自行创建的资源,同时将属性设为NULL并销毁返回的句柄,避免返回句柄与你自有句柄不同时出现隐藏位图句柄泄漏
注意:对于TreeView控件而言,在
WM_NCDESTROY消息中执行清理操作时机过晚,无法生效。
常见疑问解答
Q1:ListView没有出现同类泄漏是设计特性吗?
是,这是Windows公共控件的原生设计差异。TreeView的设计逻辑是仅持有ImageList的引用,不会主动管理其生命周期,销毁控件时不会自动释放关联的ImageList资源;而ListView内部实现了自动清理逻辑,销毁控件时会自动解绑并释放关联的所有ImageList资源,因此默认场景下不会出现同类泄漏。
Q2:是否需要给ListView也添加主动清理逻辑?
建议添加,主动清理不会产生任何副作用,同时可以覆盖两类特殊场景:
- 业务逻辑中存在ImageList跨控件传递、动态替换的场景,主动清理可以避免逻辑疏漏导致的泄漏
- 兼容自定义封装的ListView变体控件,多数第三方自定义ListView没有实现原生的自动清理逻辑,主动清理可以规避这类兼容问题
推荐的ListView清理逻辑如下:
ImageList_Destroy(ListView_SetImageList(GetHandle(), nullptr, LVSIL_STATE)); ImageList_Destroy(ListView_SetImageList(GetHandle(), nullptr, LVSIL_SMALL)); ImageList_Destroy(ListView_SetImageList(GetHandle(), nullptr, LVSIL_NORMAL));
清理操作同样需要放在WM_DESTROY消息阶段执行,不要延后到WM_NCDESTROY阶段。
内容的提问来源于stack exchange,提问作者user3161924
相关产品推荐
相关产品推荐

