diff --git a/dlls/user32/listbox.c b/dlls/user32/listbox.c index f7231f902bd..eaa805bf64b 100644 --- a/dlls/user32/listbox.c +++ b/dlls/user32/listbox.c @@ -1684,12 +1684,19 @@ static LRESULT LISTBOX_InsertString( LB_DESCR *descr, INT index, LPCWSTR str ) */ static void LISTBOX_DeleteItem( LB_DESCR *descr, INT index ) { + /* save the item data before it gets freed by LB_RESETCONTENT */ + ULONG_PTR item_data = descr->items[index].data; + LPWSTR item_str = descr->items[index].str; + + if (!descr->nb_items) + SendMessageW( descr->self, LB_RESETCONTENT, 0, 0 ); + /* Note: Win 3.1 only sends DELETEITEM on owner-draw items, * while Win95 sends it for all items with user data. * It's probably better to send it too often than not * often enough, so this is what we do here. */ - if (IS_OWNERDRAW(descr) || descr->items[index].data) + if (IS_OWNERDRAW(descr) || item_data) { DELETEITEMSTRUCT dis; UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID ); @@ -1698,11 +1705,11 @@ static void LISTBOX_DeleteItem( LB_DESCR *descr, INT index ) dis.CtlID = id; dis.itemID = index; dis.hwndItem = descr->self; - dis.itemData = descr->items[index].data; + dis.itemData = item_data; SendMessageW( descr->owner, WM_DELETEITEM, id, (LPARAM)&dis ); } if (HAS_STRINGS(descr)) - HeapFree( GetProcessHeap(), 0, descr->items[index].str ); + HeapFree( GetProcessHeap(), 0, item_str ); } @@ -1718,18 +1725,20 @@ static LRESULT LISTBOX_RemoveItem( LB_DESCR *descr, INT index ) if ((index < 0) || (index >= descr->nb_items)) return LB_ERR; + descr->nb_items--; + LISTBOX_DeleteItem( descr, index ); + + if (!descr->nb_items) return LB_OKAY; + /* We need to invalidate the original rect instead of the updated one. */ LISTBOX_InvalidateItems( descr, index ); - LISTBOX_DeleteItem( descr, index ); - /* Remove the item */ item = &descr->items[index]; - if (index < descr->nb_items-1) + if (index < descr->nb_items) RtlMoveMemory( item, item + 1, - (descr->nb_items - index - 1) * sizeof(LB_ITEMDATA) ); - descr->nb_items--; + (descr->nb_items - index) * sizeof(LB_ITEMDATA) ); if (descr->anchor_item == descr->nb_items) descr->anchor_item--; /* Shrink the item array if possible */ diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index f698b7f3eae..2445f82b5c7 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -11017,6 +11017,19 @@ static const struct message wm_lb_click_0[] = { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) }, { 0 } }; +static const struct message wm_lb_deletestring[] = +{ + { LB_DELETESTRING, sent|wparam|lparam, 0, 0 }, + { WM_DELETEITEM, sent|wparam|parent, ID_LISTBOX, 0 }, + { 0 } +}; +static const struct message wm_lb_deletestring_reset[] = +{ + { LB_DELETESTRING, sent|wparam|lparam, 0, 0 }, + { LB_RESETCONTENT, sent|wparam|lparam|defwinproc, 0, 0 }, + { WM_DELETEITEM, sent|wparam|parent, ID_LISTBOX, 0 }, + { 0 } +}; #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__) @@ -11127,6 +11140,33 @@ static void test_listbox_messages(void) check_lb_state(listbox, 3, 0, 0, 0); flush_sequence(); + trace("deleting item 0\n"); + ret = SendMessage(listbox, LB_DELETESTRING, 0, 0); + ok(ret == 2, "expected 2, got %ld\n", ret); + ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE ); + check_lb_state(listbox, 2, -1, 0, 0); + flush_sequence(); + + trace("deleting item 0\n"); + ret = SendMessage(listbox, LB_DELETESTRING, 0, 0); + ok(ret == 1, "expected 1, got %ld\n", ret); + ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE ); + check_lb_state(listbox, 1, -1, 0, 0); + flush_sequence(); + + trace("deleting item 0\n"); + ret = SendMessage(listbox, LB_DELETESTRING, 0, 0); + ok(ret == 0, "expected 0, got %ld\n", ret); + ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE ); + check_lb_state(listbox, 0, -1, 0, 0); + flush_sequence(); + + trace("deleting item 0\n"); + ret = SendMessage(listbox, LB_DELETESTRING, 0, 0); + ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret); + check_lb_state(listbox, 0, -1, 0, 0); + flush_sequence(); + log_all_parent_messages--; DestroyWindow(listbox);