更改 TVS_CHECKBOXES 使用的 ImageList 会导致资源泄漏吗?

Can changing ImageList used by TVS_CHECKBOXES cause resource leak?

Win32:

创建树控件并将样式更改为 TVS_CHECKBOXES,然后 TVSIL_STATE 的 ImageList 更改为自定义 ImageList,您是否需要删除返回的先前 ImageList 或它是一个共享资源,不应该。

MFC:

由于存在对象层次结构,在这种情况下,您不知道 CImageList 是否正在替换系统提供的对象或来自父对象之一的对象 类。在那种情况下,正确的处理方法是什么?对于 ImageLists,你可以 CImageList::Attach()CTreeCtrl::SetImageList()CImageList::Detach() 然后 CTreeCtrl::OnDestroy() 继续 CImageList *pil=CTreeCtrl::SetImageList(NULL, TVSIL_STATE) 然后 pil->DeleteImageList(),但是对象呢? ,我们应该改为 delete pil 吗?或者我们是否总是需要设置一个成员变量,即图像列表,然后 CTreeCtrl::SetImageList() 更改它然后 OnDestroy() 放回旧的或者只是将其设置为 NULL?

Can changing ImageList used by TVS_CHECKBOXES cause resource leak?

是的。来自 Tree-View Control Window Styles:

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.

奖金"Old New Thing"link:Beware of the leaked image list when using the TVS_CHECKBOXES style

Win32 解决方案

我们可以利用 TVM_SETIMAGELIST(由 TreeView_SetImageList() 包装)returns 上一个图像列表的句柄。

HIMAGELIST hNewImageList = ImageList_Create(/* insert arguments */);
HIMAGELIST hOldImageList = TreeView_SetImageList( hwndTreeView, hNewImageList, TVSIL_STATE );
if( hOldImageList )  // a good habit, to check if handle is not NULL
{
    ImageList_Destroy( hOldImageList );
    hOldImageList = NULL;
}

树形控件销毁后,您还必须ImageList_Destroy新的图像列表。

MFC 解决方案

MFC 并没有太大的不同,我。 e.它不会自动清理由 TVS_CHECKBOXES 样式创建的图像列表。

在承载树控件的 class 的声明中创建一个成员变量 CImageList m_newImageList;(例如 CDialog 派生的 class)。这确保新图像列表的生命周期不会在树控件 window 之前结束,并通过其析构函数自动销毁图像列表。

m_newImageList.Create(/* insert arguments */);
CImageList* pOldImageList = m_treeCtrl.SetImageList( &m_newImageList, TVSIL_STATE );
if( pOldImageList )
{
    pOldImageList->DeleteImageList();
    pOldImageList = nullptr;
}

CTreeCtrl::SetImageList() returns 指向临时对象的指针(通过 CImageList::FromHandle()),该对象不拥有它包装的句柄。您必须 DeleteImageList() 以避免资源泄漏,但绝不能 delete 返回由 SetImageList 返回的指针。 MFC 在空闲处理期间自动清理临时对象(CWinApp::OnIdle())。

进一步阅读: