From c0b79e0b055a0093ab1c2c129c593d74e51d3709 Mon Sep 17 00:00:00 2001 From: Troy Rollo Date: Fri, 21 Oct 2005 15:49:36 +0000 Subject: [PATCH] Detect when the notification callback has destroyed the ListView to avoid attempts to access data that is no longer valid. --- dlls/comctl32/listview.c | 82 ++++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 24 deletions(-) diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c index b6f026d860b..7a1a4c23461 100644 --- a/dlls/comctl32/listview.c +++ b/dlls/comctl32/listview.c @@ -768,10 +768,12 @@ static LRESULT notify_hdr(LISTVIEW_INFO *infoPtr, INT code, LPNMHDR pnmh) return result; } -static inline LRESULT notify(LISTVIEW_INFO *infoPtr, INT code) +static inline BOOL notify(LISTVIEW_INFO *infoPtr, INT code) { NMHDR nmh; - return notify_hdr(infoPtr, code, &nmh); + HWND hwnd = infoPtr->hwndSelf; + notify_hdr(infoPtr, code, &nmh); + return IsWindow(hwnd); } static inline void notify_itemactivate(LISTVIEW_INFO *infoPtr, LVHITTESTINFO *htInfo) @@ -812,11 +814,12 @@ static inline LRESULT notify_listview(LISTVIEW_INFO *infoPtr, INT code, LPNMLIST return notify_hdr(infoPtr, code, (LPNMHDR)plvnm); } -static LRESULT notify_click(LISTVIEW_INFO *infoPtr, INT code, LVHITTESTINFO *lvht) +static BOOL notify_click(LISTVIEW_INFO *infoPtr, INT code, LVHITTESTINFO *lvht) { NMLISTVIEW nmlv; LVITEMW item; - + HWND hwnd = infoPtr->hwndSelf; + TRACE("code=%d, lvht=%s\n", code, debuglvhittestinfo(lvht)); ZeroMemory(&nmlv, sizeof(nmlv)); nmlv.iItem = lvht->iItem; @@ -826,14 +829,16 @@ static LRESULT notify_click(LISTVIEW_INFO *infoPtr, INT code, LVHITTESTINFO *lv item.iItem = lvht->iItem; item.iSubItem = 0; if (LISTVIEW_GetItemT(infoPtr, &item, TRUE)) nmlv.lParam = item.lParam; - return notify_listview(infoPtr, code, &nmlv); + notify_listview(infoPtr, code, &nmlv); + return IsWindow(hwnd); } -static void notify_deleteitem(LISTVIEW_INFO *infoPtr, INT nItem) +static BOOL notify_deleteitem(LISTVIEW_INFO *infoPtr, INT nItem) { NMLISTVIEW nmlv; LVITEMW item; - + HWND hwnd = infoPtr->hwndSelf; + ZeroMemory(&nmlv, sizeof (NMLISTVIEW)); nmlv.iItem = nItem; item.mask = LVIF_PARAM; @@ -841,6 +846,7 @@ static void notify_deleteitem(LISTVIEW_INFO *infoPtr, INT nItem) item.iSubItem = 0; if (LISTVIEW_GetItemT(infoPtr, &item, TRUE)) nmlv.lParam = item.lParam; notify_listview(infoPtr, LVN_DELETEITEM, &nmlv); + return IsWindow(hwnd); } static int get_ansi_notification(INT unicodeNotificationCode) @@ -3012,12 +3018,13 @@ static void LISTVIEW_ShiftIndices(LISTVIEW_INFO *infoPtr, INT nItem, INT directi * [I] nItem : item index * * RETURN: - * None + * Whether the window is still valid. */ -static void LISTVIEW_AddGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem) +static BOOL LISTVIEW_AddGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem) { INT nFirst = min(infoPtr->nSelectionMark, nItem); INT nLast = max(infoPtr->nSelectionMark, nItem); + HWND hwndSelf = infoPtr->hwndSelf; NMLVODSTATECHANGE nmlv; LVITEMW item; BOOL bOldChange; @@ -3046,7 +3053,10 @@ static void LISTVIEW_AddGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem) nmlv.uOldState = item.state; notify_hdr(infoPtr, LVN_ODSTATECHANGED, (LPNMHDR)&nmlv); + if (!IsWindow(hwndSelf)) + return FALSE; infoPtr->bDoChangeNotify = bOldChange; + return TRUE; } @@ -3400,9 +3410,15 @@ static BOOL set_main_item(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL /* send LVN_ITEMCHANGING notification, if the item is not being inserted */ /* and we are _NOT_ virtual (LVS_OWERNDATA), and change notifications */ /* are enabled */ - if(lpItem && !isNew && infoPtr->bDoChangeNotify && - notify_listview(infoPtr, LVN_ITEMCHANGING, &nmlv)) + if(lpItem && !isNew && infoPtr->bDoChangeNotify) + { + HWND hwndSelf = infoPtr->hwndSelf; + + if (notify_listview(infoPtr, LVN_ITEMCHANGING, &nmlv)) return FALSE; + if (!IsWindow(hwndSelf)) + return FALSE; + } /* copy information */ if (lpLVItem->mask & LVIF_TEXT) @@ -3546,6 +3562,7 @@ static BOOL set_sub_item(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL i static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isW) { UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + HWND hwndSelf = infoPtr->hwndSelf; LPWSTR pszText = NULL; BOOL bResult, bChanged = FALSE; @@ -3568,6 +3585,8 @@ static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, B bResult = set_sub_item(infoPtr, lpLVItem, TRUE, &bChanged); else bResult = set_main_item(infoPtr, lpLVItem, FALSE, TRUE, &bChanged); + if (!IsWindow(hwndSelf)) + return FALSE; /* redraw item, if necessary */ if (bChanged && !infoPtr->bIsDrawing) @@ -4516,7 +4535,7 @@ static BOOL LISTVIEW_DeleteItem(LISTVIEW_INFO *infoPtr, INT nItem) LISTVIEW_SetItemState(infoPtr, nItem, &item); /* send LVN_DELETEITEM notification. */ - notify_deleteitem(infoPtr, nItem); + if (!notify_deleteitem(infoPtr, nItem)) return FALSE; /* we need to do this here, because we'll be deleting stuff */ if (uView == LVS_SMALLICON || uView == LVS_ICON) @@ -4568,6 +4587,7 @@ static BOOL LISTVIEW_DeleteItem(LISTVIEW_INFO *infoPtr, INT nItem) */ static BOOL LISTVIEW_EndEditLabelT(LISTVIEW_INFO *infoPtr, LPWSTR pszText, BOOL isW) { + HWND hwndSelf = infoPtr->hwndSelf; NMLVDISPINFOW dispInfo; TRACE("(pszText=%s, isW=%d)\n", debugtext_t(pszText, isW), isW); @@ -4585,6 +4605,8 @@ static BOOL LISTVIEW_EndEditLabelT(LISTVIEW_INFO *infoPtr, LPWSTR pszText, BOOL /* Do we need to update the Item Text */ if (!notify_dispinfoT(infoPtr, LVN_ENDLABELEDITW, &dispInfo, isW)) return FALSE; + if (!IsWindow(hwndSelf)) + return FALSE; if (!pszText) return TRUE; if (!(infoPtr->dwStyle & LVS_OWNERDATA)) @@ -4625,6 +4647,7 @@ static HWND LISTVIEW_EditLabelT(LISTVIEW_INFO *infoPtr, INT nItem, BOOL isW) WCHAR szDispText[DISP_TEXT_SIZE] = { 0 }; NMLVDISPINFOW dispInfo; RECT rect; + HWND hwndSelf = infoPtr->hwndSelf; TRACE("(nItem=%d, isW=%d)\n", nItem, isW); @@ -4662,6 +4685,8 @@ static HWND LISTVIEW_EditLabelT(LISTVIEW_INFO *infoPtr, INT nItem, BOOL isW) if (notify_dispinfoT(infoPtr, LVN_BEGINLABELEDITW, &dispInfo, isW)) { + if (!IsWindow(hwndSelf)) + return 0; SendMessageW(infoPtr->hwndEdit, WM_CLOSE, 0, 0); infoPtr->hwndEdit = 0; return 0; @@ -6191,6 +6216,7 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, ITEM_INFO *lpItem; BOOL is_sorted, has_changed; LVITEMW item; + HWND hwndSelf = infoPtr->hwndSelf; TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW); @@ -6264,6 +6290,8 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, nmlv.iItem = nItem; nmlv.lParam = lpItem->lParam; notify_listview(infoPtr, LVN_INSERTITEM, &nmlv); + if (!IsWindow(hwndSelf)) + return -1; /* align items (set position of each item) */ if ((uView == LVS_SMALLICON || uView == LVS_ICON)) @@ -7967,6 +7995,7 @@ static LRESULT LISTVIEW_MouseWheel(LISTVIEW_INFO *infoPtr, INT wheelDelta) static LRESULT LISTVIEW_KeyDown(LISTVIEW_INFO *infoPtr, INT nVirtualKey, LONG lKeyData) { UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + HWND hwndSelf = infoPtr->hwndSelf; INT nItem = -1; NMLVKEYDOWN nmKeyDown; @@ -7976,14 +8005,16 @@ static LRESULT LISTVIEW_KeyDown(LISTVIEW_INFO *infoPtr, INT nVirtualKey, LONG lK nmKeyDown.wVKey = nVirtualKey; nmKeyDown.flags = 0; notify_hdr(infoPtr, LVN_KEYDOWN, &nmKeyDown.hdr); + if (!IsWindow(hwndSelf)) + return 0; switch (nVirtualKey) { case VK_RETURN: if ((infoPtr->nItemCount > 0) && (infoPtr->nFocusedItem != -1)) { - notify(infoPtr, NM_RETURN); - notify(infoPtr, LVN_ITEMACTIVATE); + if (!notify(infoPtr, NM_RETURN)) return 0; + if (!notify(infoPtr, LVN_ITEMACTIVATE)) return 0; } break; @@ -8069,7 +8100,7 @@ static LRESULT LISTVIEW_KillFocus(LISTVIEW_INFO *infoPtr) if (!infoPtr->bFocus) return 0; /* send NM_KILLFOCUS notification */ - notify(infoPtr, NM_KILLFOCUS); + if (!notify(infoPtr, NM_KILLFOCUS)) return 0; /* if we have a focus rectagle, get rid of it */ LISTVIEW_ShowFocusRect(infoPtr, FALSE); @@ -8102,14 +8133,14 @@ static LRESULT LISTVIEW_LButtonDblClk(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, TRACE("(key=%hu, X=%hu, Y=%hu)\n", wKey, x, y); /* send NM_RELEASEDCAPTURE notification */ - notify(infoPtr, NM_RELEASEDCAPTURE); + if (!notify(infoPtr, NM_RELEASEDCAPTURE)) return 0; htInfo.pt.x = x; htInfo.pt.y = y; /* send NM_DBLCLK notification */ LISTVIEW_HitTest(infoPtr, &htInfo, TRUE, FALSE); - notify_click(infoPtr, NM_DBLCLK, &htInfo); + if (!notify_click(infoPtr, NM_DBLCLK, &htInfo)) return 0; /* To send the LVN_ITEMACTIVATE, it must be on an Item */ if(htInfo.iItem != -1) notify_itemactivate(infoPtr,&htInfo); @@ -8139,7 +8170,7 @@ static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, IN TRACE("(key=%hu, X=%hu, Y=%hu)\n", wKey, x, y); /* send NM_RELEASEDCAPTURE notification */ - notify(infoPtr, NM_RELEASEDCAPTURE); + if (!notify(infoPtr, NM_RELEASEDCAPTURE)) return 0; if (!infoPtr->bFocus) SetFocus(infoPtr->hwndSelf); @@ -8182,7 +8213,7 @@ static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, IN { if (bGroupSelect) { - LISTVIEW_AddGroupSelection(infoPtr, nItem); + if (!LISTVIEW_AddGroupSelection(infoPtr, nItem)) return 0; LISTVIEW_SetItemFocus(infoPtr, nItem); infoPtr->nSelectionMark = nItem; } @@ -8257,7 +8288,7 @@ static LRESULT LISTVIEW_LButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT /* send NM_CLICK notification */ LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE); - notify_click(infoPtr, NM_CLICK, &lvHitTestInfo); + if (!notify_click(infoPtr, NM_CLICK, &lvHitTestInfo)) return 0; /* set left button flag */ infoPtr->bLButtonDown = FALSE; @@ -8332,6 +8363,7 @@ static LRESULT LISTVIEW_NCDestroy(LISTVIEW_INFO *infoPtr) static LRESULT LISTVIEW_HeaderNotification(LISTVIEW_INFO *infoPtr, const NMHEADERW *lpnmh) { UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + HWND hwndSelf = infoPtr->hwndSelf; TRACE("(lpnmh=%p)\n", lpnmh); @@ -8345,6 +8377,8 @@ static LRESULT LISTVIEW_HeaderNotification(LISTVIEW_INFO *infoPtr, const NMHEADE case HDN_ITEMCHANGEDW: case HDN_ITEMCHANGEDA: notify_forward_header(infoPtr, lpnmh); + if (!IsWindow(hwndSelf)) + break; /* Fall through */ case HDN_TRACKW: case HDN_TRACKA: @@ -8575,7 +8609,7 @@ static LRESULT LISTVIEW_RButtonDblClk(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, TRACE("(key=%hu,X=%hu,Y=%hu)\n", wKey, x, y); /* send NM_RELEASEDCAPTURE notification */ - notify(infoPtr, NM_RELEASEDCAPTURE); + if (!notify(infoPtr, NM_RELEASEDCAPTURE)) return 0; /* send NM_RDBLCLK notification */ lvHitTestInfo.pt.x = x; @@ -8606,7 +8640,7 @@ static LRESULT LISTVIEW_RButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, IN TRACE("(key=%hu,X=%hu,Y=%hu)\n", wKey, x, y); /* send NM_RELEASEDCAPTURE notification */ - notify(infoPtr, NM_RELEASEDCAPTURE); + if (!notify(infoPtr, NM_RELEASEDCAPTURE)) return 0; /* make sure the listview control window has the focus */ if (!infoPtr->bFocus) SetFocus(infoPtr->hwndSelf); @@ -8662,7 +8696,7 @@ static LRESULT LISTVIEW_RButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT lvHitTestInfo.pt.x = x; lvHitTestInfo.pt.y = y; LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE); - notify_click(infoPtr, NM_RCLICK, &lvHitTestInfo); + if (!notify_click(infoPtr, NM_RCLICK, &lvHitTestInfo)) return 0; /* Change to screen coordinate for WM_CONTEXTMENU */ pt = lvHitTestInfo.pt; @@ -8725,7 +8759,7 @@ static LRESULT LISTVIEW_SetFocus(LISTVIEW_INFO *infoPtr, HWND hwndLoseFocus) if (infoPtr->bFocus) return 0; /* send NM_SETFOCUS notification */ - notify(infoPtr, NM_SETFOCUS); + if (!notify(infoPtr, NM_SETFOCUS)) return 0; /* set window focus flag */ infoPtr->bFocus = TRUE;