comctl32/listview: Fix LVM_GETITEM for out-of-range iSubItem case.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=44842 Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
8f9e1ae705
commit
37c3810557
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue