Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/comctl32/tests/listview.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-)
diff --git a/dlls/comctl32/tests/listview.c b/dlls/comctl32/tests/listview.c index 48cd614380..dc923c0b6e 100644 --- a/dlls/comctl32/tests/listview.c +++ b/dlls/comctl32/tests/listview.c @@ -1546,6 +1546,19 @@ static void test_columns(void) "get subitem text after column added", FALSE);
DestroyWindow(hwnd); + + /* Columns are not created right away. */ + hwnd = create_listview_control(LVS_REPORT); + ok(hwnd != NULL, "Failed to create a listview window.\n"); + + insert_item(hwnd, 0); + + header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0); + ok(IsWindow(header), "Expected header handle.\n"); + rc = SendMessageA(header, HDM_GETITEMCOUNT, 0, 0); + ok(!rc, "Unexpected column count.\n"); + + DestroyWindow(hwnd); }
/* test setting imagelist between WM_NCCREATE and WM_CREATE */ @@ -3939,25 +3952,6 @@ static void test_getitemposition(void) DestroyWindow(hwnd); }
-static void test_columnscreation(void) -{ - HWND hwnd, header; - DWORD r; - - hwnd = create_listview_control(LVS_REPORT); - ok(hwnd != NULL, "failed to create a listview window\n"); - - insert_item(hwnd, 0); - - /* headers columns aren't created automatically */ - header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0); - ok(IsWindow(header), "Expected header handle\n"); - r = SendMessageA(header, HDM_GETITEMCOUNT, 0, 0); - expect(0, r); - - DestroyWindow(hwnd); -} - static void test_getitemrect(void) { HWND hwnd; @@ -6577,7 +6571,6 @@ START_TEST(listview) test_hittest(); test_getviewrect(); test_getitemposition(); - test_columnscreation(); test_editbox(); test_notifyformat(); test_indentation(); @@ -6632,7 +6625,6 @@ START_TEST(listview) test_ownerdata(); test_norecompute(); test_nosortheader(); - test_columnscreation(); test_indentation(); test_finditem(); test_hover();
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=44842 Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/comctl32/listview.c | 41 ++++++++--------- dlls/comctl32/tests/listview.c | 81 +++++++++++++++++++++++++++++++++- 2 files changed, 99 insertions(+), 23 deletions(-)
diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c index acf6f31fe6..eb42526f57 100644 --- a/dlls/comctl32/listview.c +++ b/dlls/comctl32/listview.c @@ -6674,11 +6674,11 @@ static HIMAGELIST LISTVIEW_GetImageList(const LISTVIEW_INFO *infoPtr, INT nImage static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW) { ITEMHDR callbackHdr = { LPSTR_TEXTCALLBACKW, I_IMAGECALLBACK }; + BOOL is_subitem_invalid = FALSE; NMLVDISPINFOW dispInfo; ITEM_INFO *lpItem; ITEMHDR* pItemHdr; HDPA hdpaSubItems; - INT isubitem;
TRACE("(item=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
@@ -6688,10 +6688,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, if (lpLVItem->mask == 0) return TRUE; TRACE("mask=%x\n", lpLVItem->mask);
- /* make a local copy */ - isubitem = lpLVItem->iSubItem; - - if (isubitem && (lpLVItem->mask & LVIF_STATE)) + if (lpLVItem->iSubItem && (lpLVItem->mask & LVIF_STATE)) lpLVItem->state = 0;
/* a quick optimization if all we're asked is the focus state @@ -6701,7 +6698,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, !(infoPtr->uCallbackMask & LVIS_FOCUSED) ) { lpLVItem->state = 0; - if (infoPtr->nFocusedItem == lpLVItem->iItem && isubitem == 0) + if (infoPtr->nFocusedItem == lpLVItem->iItem && !lpLVItem->iSubItem) lpLVItem->state |= LVIS_FOCUSED; return TRUE; } @@ -6723,7 +6720,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, * depend on the uninitialized fields being 0 */ dispInfo.item.mask = lpLVItem->mask & ~LVIF_PARAM; dispInfo.item.iItem = lpLVItem->iItem; - dispInfo.item.iSubItem = isubitem; + dispInfo.item.iSubItem = lpLVItem->iSubItem; if (lpLVItem->mask & LVIF_TEXT) { if (lpLVItem->mask & LVIF_NORECOMPUTE) @@ -6770,7 +6767,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, lpLVItem->pszText = LPSTR_TEXTCALLBACKW;
/* we store only a little state, so if we're not asked, we're done */ - if (!(lpLVItem->mask & LVIF_STATE) || isubitem) return TRUE; + if (!(lpLVItem->mask & LVIF_STATE) || lpLVItem->iSubItem) return TRUE;
/* if focus is handled by us, report it */ if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED ) @@ -6796,21 +6793,22 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, lpItem = DPA_GetPtr(hdpaSubItems, 0); assert (lpItem);
- if (isubitem) + if (lpLVItem->iSubItem) { - SUBITEM_INFO *lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, isubitem); - pItemHdr = lpSubItem ? &lpSubItem->hdr : &callbackHdr; - if (!lpSubItem) + SUBITEM_INFO *lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem); + if (lpSubItem) + pItemHdr = &lpSubItem->hdr; + else { - WARN(" iSubItem invalid (%08x), ignored.\n", isubitem); - isubitem = 0; + pItemHdr = &callbackHdr; + is_subitem_invalid = TRUE; } } else pItemHdr = &lpItem->hdr;
/* Do we need to query the state from the app? */ - if ((lpLVItem->mask & LVIF_STATE) && infoPtr->uCallbackMask && isubitem == 0) + if ((lpLVItem->mask & LVIF_STATE) && infoPtr->uCallbackMask && (!lpLVItem->iSubItem || is_subitem_invalid)) { dispInfo.item.mask |= LVIF_STATE; dispInfo.item.stateMask = infoPtr->uCallbackMask; @@ -6818,15 +6816,14 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem,
/* Do we need to enquire about the image? */ if ((lpLVItem->mask & LVIF_IMAGE) && pItemHdr->iImage == I_IMAGECALLBACK && - (isubitem == 0 || (infoPtr->dwLvExStyle & LVS_EX_SUBITEMIMAGES))) + (!lpLVItem->iSubItem || (infoPtr->dwLvExStyle & LVS_EX_SUBITEMIMAGES))) { dispInfo.item.mask |= LVIF_IMAGE; dispInfo.item.iImage = I_IMAGECALLBACK; }
/* Only items support indentation */ - if ((lpLVItem->mask & LVIF_INDENT) && lpItem->iIndent == I_INDENTCALLBACK && - (isubitem == 0)) + if ((lpLVItem->mask & LVIF_INDENT) && lpItem->iIndent == I_INDENTCALLBACK && !lpLVItem->iSubItem) { dispInfo.item.mask |= LVIF_INDENT; dispInfo.item.iIndent = I_INDENTCALLBACK; @@ -6847,14 +6844,14 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, if (dispInfo.item.mask) { dispInfo.item.iItem = lpLVItem->iItem; - dispInfo.item.iSubItem = lpLVItem->iSubItem; /* yes: the original subitem */ + dispInfo.item.iSubItem = lpLVItem->iSubItem; dispInfo.item.lParam = lpItem->lParam; notify_dispinfoT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW); TRACE(" getdispinfo(2):item=%s\n", debuglvitem_t(&dispInfo.item, isW)); }
/* we should not store values for subitems */ - if (isubitem) dispInfo.item.mask &= ~LVIF_DI_SETITEM; + if (lpLVItem->iSubItem) dispInfo.item.mask &= ~LVIF_DI_SETITEM;
/* Now, handle the iImage field */ if (dispInfo.item.mask & LVIF_IMAGE) @@ -6865,7 +6862,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, } else if (lpLVItem->mask & LVIF_IMAGE) { - if(isubitem == 0 || (infoPtr->dwLvExStyle & LVS_EX_SUBITEMIMAGES)) + if (!lpLVItem->iSubItem || (infoPtr->dwLvExStyle & LVS_EX_SUBITEMIMAGES)) lpLVItem->iImage = pItemHdr->iImage; else lpLVItem->iImage = 0; @@ -6897,7 +6894,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, lpLVItem->lParam = lpItem->lParam;
/* if this is a subitem, we're done */ - if (isubitem) return TRUE; + if (lpLVItem->iSubItem) return TRUE;
/* ... the state field (this one is different due to uCallbackmask) */ if (lpLVItem->mask & LVIF_STATE) diff --git a/dlls/comctl32/tests/listview.c b/dlls/comctl32/tests/listview.c index dc923c0b6e..87f644abd1 100644 --- a/dlls/comctl32/tests/listview.c +++ b/dlls/comctl32/tests/listview.c @@ -956,6 +956,37 @@ static void test_images(void) ok(EqualRect(&r1, &r2), "rectangle should be the same\n");
DestroyWindow(hwnd); + + /* I_IMAGECALLBACK set for item, try to get image with invalid subitem. */ + hwnd = create_listview_control(LVS_REPORT); + ok(hwnd != NULL, "Failed to create listview.\n"); + + memset(&item, 0, sizeof(item)); + item.mask = LVIF_IMAGE; + item.iImage = I_IMAGECALLBACK; + r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item); + ok(!r, "Failed to insert item.\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + memset(&item, 0, sizeof(item)); + item.mask = LVIF_IMAGE; + r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item); + ok(r, "Failed to get item.\n"); + + ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq, "get image dispinfo 1", FALSE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + memset(&item, 0, sizeof(item)); + item.mask = LVIF_IMAGE; + item.iSubItem = 1; + r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item); + ok(r, "Failed to get item.\n"); + + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "get image dispinfo 2", FALSE); + + DestroyWindow(hwnd); }
static void test_checkboxes(void) @@ -4551,6 +4582,17 @@ static void test_indentation(void) ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq, "get indent dispinfo", FALSE);
+ /* Ask for iIndent with invalid subitem. */ + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + memset(&item, 0, sizeof(item)); + item.mask = LVIF_INDENT; + item.iSubItem = 1; + r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item); + ok(r, "Failed to get item.\n"); + + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "get indent dispinfo 2", FALSE); + DestroyWindow(hwnd); }
@@ -6058,6 +6100,44 @@ static void test_callback_mask(void) mask = SendMessageA(hwnd, LVM_GETCALLBACKMASK, 0, 0); ok(mask == ~0u, "got 0x%08x\n", mask);
+ /* Ask for state, invalid subitem. */ + insert_item(hwnd, 0); + + ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_FOCUSED, 0); + ok(ret, "Failed to set callback mask.\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + memset(&item, 0, sizeof(item)); + item.iSubItem = 1; + item.mask = LVIF_STATE; + item.stateMask = LVIS_SELECTED; + ret = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item); + ok(ret, "Failed to get item data.\n"); + + memset(&item, 0, sizeof(item)); + item.mask = LVIF_STATE; + item.stateMask = LVIS_SELECTED; + ret = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item); + ok(ret, "Failed to get item data.\n"); + + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "parent seq, callback mask/invalid subitem 1", TRUE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + memset(&item, 0, sizeof(item)); + memset(&g_itema, 0, sizeof(g_itema)); + item.iSubItem = 1; + item.mask = LVIF_STATE; + item.stateMask = LVIS_FOCUSED | LVIS_SELECTED; + ret = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item); + ok(ret, "Failed to get item data.\n"); + ok(g_itema.iSubItem == 1, "Unexpected LVN_DISPINFO subitem %d.\n", g_itema.iSubItem); + ok(g_itema.stateMask == LVIS_FOCUSED, "Unexpected state mask %#x.\n", g_itema.stateMask); + + ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq, + "parent seq, callback mask/invalid subitem 2", FALSE); + DestroyWindow(hwnd);
/* LVS_OWNERDATA, mask LVIS_FOCUSED */ @@ -6271,7 +6351,6 @@ static void test_state_image(void) item.iSubItem = 2; r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item); ok(r, "Failed to get subitem state.\n"); - todo_wine ok(item.state == 0, "Unexpected state %#x.\n", item.state);
item.mask = LVIF_TEXT;