【问题标题】:Can changing ImageList used by TVS_CHECKBOXES cause resource leak?更改 TVS_CHECKBOXES 使用的 ImageList 会导致资源泄漏吗?
【发布时间】:2018-12-18 05:55:27
【问题描述】:

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?

【问题讨论】:

  • 所以在 Win32 的情况下,这意味着是。使用 CImageLists 的 MFC 案例呢?
  • MFC 是一个非常薄的包装器,所以我猜它是一样的,但不确定。
  • 检查任务管理器的 GDI 句柄。
  • CTreeCtrl::SetImageList() 返回一个 temporary 对象(通过CImageList::FromHandle()),该对象不拥有它所包装的句柄。你必须DeleteImageList() 来避免资源泄漏(见第一条评论),但不要在SetImageList 返回的指针上使用delete。 MFC 在空闲处理期间自动清理临时对象。 More about that.

标签: winapi mfc imagelist


【解决方案1】:

改变TVS_CHECKBOXES使用的ImageList会导致资源泄露吗?

是的。来自Tree-View Control Window Styles

销毁树视图控件不会破坏复选框状态 图像列表。你必须明确地销毁它。获取句柄 通过向树视图控件发送TVM_GETIMAGELIST 来状态图像列表 信息。然后用ImageList_Destroy销毁图片列表。

奖励“旧新事物”链接:Beware of the leaked image list when using the TVS_CHECKBOXES style

Win32解决方案

我们可以利用TVM_SETIMAGELIST(被TreeView_SetImageList()包裹)返回上一个图像列表的句柄这一事实。

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 样式创建的图像列表。

在托管树控件的类的声明中创建成员变量CImageList m_newImageList;(例如CDialog 派生类)。这确保了新的图像列表生命周期不会在树形控制窗口之前结束,并通过其析构函数自动销毁图像列表。

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

CTreeCtrl::SetImageList() 返回一个指向临时对象的指针(通过CImageList::FromHandle()),该对象不拥有它所包装的句柄。你必须DeleteImageList() 来避免资源泄漏,但不要在SetImageList 返回的指针上使用delete。 MFC 在空闲处理期间自动清理临时对象(在CWinApp::OnIdle())。

进一步阅读:

【讨论】:

  • 好信息,使用 MFC 和成员变量时只剩下一个问题。说一些扩展该基类并使用上面的过程放入自己的图像列表的东西。成员变量句柄现在在基中无效?还是以某种方式同步?
  • @user3161924 这个场景不用多说。基类的成员变量通过 MFC 句柄映射保持同步。当您调用CImageList::Create() 时,MFC 将HIMAGELIST 和指向CImageList 的指针存储在“永久”句柄映射中。当您调用SetImageList() 时,您将有效地获得指向基类的CImageList 成员变量的指针。在我的代码示例中调用pOldImageList->DeleteImageList() 时,您将通过基类的成员删除图像列表。
猜你喜欢
  • 1970-01-01
  • 2021-04-10
  • 1970-01-01
  • 2010-11-18
  • 2013-03-27
  • 2021-03-23
  • 2021-09-25
  • 2014-12-08
  • 1970-01-01
相关资源
最近更新 更多