본문 바로가기
MFC

CTreeCtrl에서 SetItemData로 입력한 DWORD_PTR 삭제 방법

by leo21c 2017. 12. 20.

MFC에서 CTreeCtrl을 만들어 사용할 때 SetItemData에 DWORD_PTR를 특정 구조체나 Class의 객체 포인터를 넣어 사용하는 경우가 많다. 그럼 Struct 또는 Class를 Object을 New로 생성하고 언제 Delete를 해야 메모리 누수가 발생하지 않을까? 기존에 개발된 소스에는 Delete를 하는 부분이 없어서 많은 메모리 누수가 발생하고 있었다.


자료를 찾아보니 CTreeCtrl 객체를 선언에서 가지고 있는 Parent에 ON_NOTIFY 이벤트를 이용해서 처리를 하는 것을 발견했다.


일반적으로 CTreeCtrl의 Item을 삭제할 때에는 DeleteItem 또는 DeleteAllItems를 이용해서 삭제를 한다. 그러나 이것은 Tree의 Item을 삭제하는 것이지 동적으로 SetItemData로 넣은 것까지 자동으로 메모리 해제를 하는 것은 아니다.

따라서 Tree에서 Item이 Delete할 때 발생하는 TVN_DELETEITEM 이벤트를 MESSAGE_MAP을 통해서 메모리를 해제하는 함수를 제작해야 한다.


예를 들어 아래와 같은 Class가 있다고 하면

Class CSampleDlg 

{

protected:

virtual void DoDataExchange(CDataExchange* pDX);

DECLARE_MESSAGE_MAP()


public:

      afx_msg void OnTvnDeleteTreeItem(NMHDR *pNMHDR, LRESULT *pResult);


private:

CListCtrl m_treeCtrl;

}; 


예로 CTreeCtrl의 ID를 ID_TREE_SAMPLE로 하다.

아래와 같이 MESSAGE_MAP에서 TVN_DELETEITEM 이벤트를 후킹해서 처리를 하면 된다.

NodeInfo는 예를 들어 만든 Class 또는 struct의 이름이다. 동적으로 SetItemData로 입력되었다고 가정한다.

void CSampleDlg::DoDataExchange(CDataExchange* pDX)

{

DDX_Control(pDX, ID_TREE_SAMPLE, m_treeCtrl);

}


BEGIN_MESSAGE_MAP(CSampleDlg, CDialog)

ON_NOTIFY(TVN_DELETEITEM, ID_TREE_SAMPLE, &CSampleDlg::OnTvnDeleteTreeItem)

END_MESSAGE_MAP()


void CSampleDlg::OnTvnDeleteTreeItem(NMHDR *pNMHDR, LRESULT *pResult)

{

    LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);

    if (pNMTreeView == NULL) return;

    HTREEITEM hItem = pNMTreeView->itemOld.hItem;

    if (hItem == NULL) return;


    NodeInfo* pNodeInfo = (NodeInfo*)m_treeCtrl.GetItemData(hItem);


    if (NULL == pNodeInfo)

        return;

    else {

        free(pNodeInfo);

        pNodeInfo = NULL;

    }

    *pResult = 0;

}


DeleteItem을 하면 하위 Item도 모두 삭제가 된다. 따라서 OnTvnDeleteTreeItem()함수에서 DeleteItem을 하지 않도록 한다.

itemNew가 아니고 itemOld를 사용한다. TVN_DELETEITEM의 Pointer 정보는 itemOld에 들어있다.

(Pointer to an NMTREEVIEW structure. The itemOld member is a TVITEM structure whose hItem and lParam members contain valid information about the item being deleted.)


https://msdn.microsoft.com/en-us/library/windows/desktop/bb773512(v=vs.85).aspx


위와 같이 처리를 해서 메모리 누수를 방지한다.