Может ли изменение ImageList, используемого TVS_CHECKBOXES, вызвать утечку ресурсов? - PullRequest
0 голосов
/ 18 декабря 2018

Win32:

После создания элемента управления деревом и изменения стиля на TVS_CHECKBOXES, а затем изменения ImageList для TVSIL_STATE на пользовательский 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?

1 Ответ

0 голосов
/ 19 декабря 2018

Может ли изменение ImageList, используемого TVS_CHECKBOXES, вызвать утечку ресурсов?

Да.Из Стили окна управления древовидным представлением :

Уничтожение управления древовидным представлением не разрушает список изображений состояния флажка.Вы должны уничтожить это явно.Получите дескриптор списка изображений состояния, отправив элементу управления древовидного представления сообщение TVM_GETIMAGELIST.Затем уничтожьте список изображений с помощью ImageList_Destroy.

Бонусная ссылка «Старое новое»: Остерегайтесь списка пропущенных изображений при использовании стиля TVS_CHECKBOXES

Решение 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 не так уж отличается, то есть он не очищает автоматическисписок изображений, созданный в стиле 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(), чтобы избежать утечки ресурсов, но никогда delete на указателе, возвращаемом SetImageList.MFC автоматически очищает временные объекты во время обработки в режиме ожидания (CWinApp::OnIdle()).

Дополнительные сведения:

...