comctl32/tab: Fix DRAWITEMSTRUCT filling when extra item data of a custom size is used.
This commit is contained in:
parent
66bad889f4
commit
f08938c381
|
@ -83,8 +83,10 @@ typedef struct
|
||||||
BYTE extra[1]; /* Space for caller supplied info, variable size */
|
BYTE extra[1]; /* Space for caller supplied info, variable size */
|
||||||
} TAB_ITEM;
|
} TAB_ITEM;
|
||||||
|
|
||||||
/* The size of a tab item depends on how much extra data is requested */
|
/* The size of a tab item depends on how much extra data is requested.
|
||||||
#define TAB_ITEM_SIZE(infoPtr) (FIELD_OFFSET(TAB_ITEM, extra[(infoPtr)->cbInfo]))
|
TCM_INSERTITEM always stores at least LPARAM sized data. */
|
||||||
|
#define EXTRA_ITEM_SIZE(infoPtr) (max((infoPtr)->cbInfo, sizeof(LPARAM)))
|
||||||
|
#define TAB_ITEM_SIZE(infoPtr) FIELD_OFFSET(TAB_ITEM, extra[EXTRA_ITEM_SIZE(infoPtr)])
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -1728,7 +1730,7 @@ TAB_DrawItemInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, RECT *drawRect
|
||||||
/*
|
/*
|
||||||
* if owner draw, tell the owner to draw
|
* if owner draw, tell the owner to draw
|
||||||
*/
|
*/
|
||||||
if ((infoPtr->dwStyle & TCS_OWNERDRAWFIXED) && GetParent(infoPtr->hwnd))
|
if ((infoPtr->dwStyle & TCS_OWNERDRAWFIXED) && IsWindow(infoPtr->hwndNotify))
|
||||||
{
|
{
|
||||||
DRAWITEMSTRUCT dis;
|
DRAWITEMSTRUCT dis;
|
||||||
UINT id;
|
UINT id;
|
||||||
|
@ -1741,14 +1743,9 @@ TAB_DrawItemInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, RECT *drawRect
|
||||||
drawRect->left += 1;
|
drawRect->left += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* get the control id
|
|
||||||
*/
|
|
||||||
id = (UINT)GetWindowLongPtrW( infoPtr->hwnd, GWLP_ID );
|
id = (UINT)GetWindowLongPtrW( infoPtr->hwnd, GWLP_ID );
|
||||||
|
|
||||||
/*
|
/* fill DRAWITEMSTRUCT */
|
||||||
* put together the DRAWITEMSTRUCT
|
|
||||||
*/
|
|
||||||
dis.CtlType = ODT_TAB;
|
dis.CtlType = ODT_TAB;
|
||||||
dis.CtlID = id;
|
dis.CtlID = id;
|
||||||
dis.itemID = iItem;
|
dis.itemID = iItem;
|
||||||
|
@ -1761,11 +1758,18 @@ TAB_DrawItemInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, RECT *drawRect
|
||||||
dis.hwndItem = infoPtr->hwnd;
|
dis.hwndItem = infoPtr->hwnd;
|
||||||
dis.hDC = hdc;
|
dis.hDC = hdc;
|
||||||
CopyRect(&dis.rcItem,drawRect);
|
CopyRect(&dis.rcItem,drawRect);
|
||||||
dis.itemData = (ULONG_PTR)TAB_GetItem(infoPtr, iItem)->extra;
|
|
||||||
|
|
||||||
/*
|
/* when extra data fits ULONG_PTR, store it directly */
|
||||||
* send the draw message
|
if (infoPtr->cbInfo > sizeof(LPARAM))
|
||||||
*/
|
dis.itemData = (ULONG_PTR) TAB_GetItem(infoPtr, iItem)->extra;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* this could be considered broken on 64 bit, but that's how it works -
|
||||||
|
only first 4 bytes are copied */
|
||||||
|
memcpy(&dis.itemData, (ULONG_PTR*)TAB_GetItem(infoPtr, iItem)->extra, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* draw notification */
|
||||||
SendMessageW( infoPtr->hwndNotify, WM_DRAWITEM, id, (LPARAM)&dis );
|
SendMessageW( infoPtr->hwndNotify, WM_DRAWITEM, id, (LPARAM)&dis );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2686,10 +2690,10 @@ TAB_InsertItemT (TAB_INFO *infoPtr, INT iItem, const TCITEMW *pti, BOOL bUnicode
|
||||||
item->iImage = -1;
|
item->iImage = -1;
|
||||||
|
|
||||||
if (pti->mask & TCIF_PARAM)
|
if (pti->mask & TCIF_PARAM)
|
||||||
memcpy(item->extra, &pti->lParam, infoPtr->cbInfo);
|
memcpy(item->extra, &pti->lParam, EXTRA_ITEM_SIZE(infoPtr));
|
||||||
else
|
else
|
||||||
memset(item->extra, 0, infoPtr->cbInfo);
|
memset(item->extra, 0, EXTRA_ITEM_SIZE(infoPtr));
|
||||||
|
|
||||||
TAB_SetItemBounds(infoPtr);
|
TAB_SetItemBounds(infoPtr);
|
||||||
if (infoPtr->uNumItem > 1)
|
if (infoPtr->uNumItem > 1)
|
||||||
TAB_InvalidateTabArea(infoPtr);
|
TAB_InvalidateTabArea(infoPtr);
|
||||||
|
|
|
@ -61,7 +61,8 @@
|
||||||
"%s: Expected [%d,%d] got [%d,%d]\n", msg, (int)width, (int)height,\
|
"%s: Expected [%d,%d] got [%d,%d]\n", msg, (int)width, (int)height,\
|
||||||
rTab.right - rTab.left, rTab.bottom - rTab.top);
|
rTab.right - rTab.left, rTab.bottom - rTab.top);
|
||||||
|
|
||||||
static HFONT hFont = 0;
|
static HFONT hFont;
|
||||||
|
static DRAWITEMSTRUCT g_drawitem;
|
||||||
|
|
||||||
static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
|
static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
|
||||||
|
|
||||||
|
@ -337,6 +338,10 @@ static LRESULT WINAPI parentWindowProcess(HWND hwnd, UINT message, WPARAM wParam
|
||||||
add_message(sequences, PARENT_SEQ_INDEX, &msg);
|
add_message(sequences, PARENT_SEQ_INDEX, &msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* dump sent structure data */
|
||||||
|
if (message == WM_DRAWITEM)
|
||||||
|
g_drawitem = *(DRAWITEMSTRUCT*)lParam;
|
||||||
|
|
||||||
defwndproc_counter++;
|
defwndproc_counter++;
|
||||||
ret = DefWindowProcA(hwnd, message, wParam, lParam);
|
ret = DefWindowProcA(hwnd, message, wParam, lParam);
|
||||||
defwndproc_counter--;
|
defwndproc_counter--;
|
||||||
|
@ -790,11 +795,43 @@ static void test_unicodeformat(HWND parent_wnd, INT nTabs)
|
||||||
|
|
||||||
static void test_getset_item(HWND parent_wnd, INT nTabs)
|
static void test_getset_item(HWND parent_wnd, INT nTabs)
|
||||||
{
|
{
|
||||||
TCITEM tcItem;
|
|
||||||
DWORD ret;
|
|
||||||
char szText[32] = "New Label";
|
char szText[32] = "New Label";
|
||||||
|
TCITEM tcItem;
|
||||||
|
LPARAM lparam;
|
||||||
|
DWORD ret;
|
||||||
HWND hTab;
|
HWND hTab;
|
||||||
|
|
||||||
|
hTab = CreateWindowA(
|
||||||
|
WC_TABCONTROLA,
|
||||||
|
"TestTab",
|
||||||
|
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | TCS_FIXEDWIDTH | TCS_OWNERDRAWFIXED,
|
||||||
|
10, 10, 300, 100,
|
||||||
|
parent_wnd, NULL, NULL, 0);
|
||||||
|
|
||||||
|
ok(GetParent(hTab) == NULL, "got %p, expected null parent\n", GetParent(hTab));
|
||||||
|
|
||||||
|
ret = SendMessageA(hTab, TCM_SETITEMEXTRA, sizeof(LPARAM)-1, 0);
|
||||||
|
ok(ret == TRUE, "got %d\n", ret);
|
||||||
|
|
||||||
|
/* set some item data */
|
||||||
|
tcItem.lParam = ~0;
|
||||||
|
tcItem.mask = TCIF_PARAM;
|
||||||
|
|
||||||
|
ret = SendMessageA(hTab, TCM_INSERTITEMA, 0, (LPARAM)&tcItem);
|
||||||
|
ok(ret == 0, "got %d\n", ret);
|
||||||
|
|
||||||
|
/* all sizeof(LPARAM) returned anyway when using sizeof(LPARAM)-1 size */
|
||||||
|
memset(&lparam, 0xaa, sizeof(lparam));
|
||||||
|
tcItem.lParam = lparam;
|
||||||
|
tcItem.mask = TCIF_PARAM;
|
||||||
|
ret = SendMessage(hTab, TCM_GETITEM, 0, (LPARAM)&tcItem);
|
||||||
|
expect(TRUE, ret);
|
||||||
|
/* everything higher specified size is preserved */
|
||||||
|
memset(&lparam, 0xff, sizeof(lparam)-1);
|
||||||
|
ok(tcItem.lParam == lparam, "Expected 0x%lx, got 0x%lx\n", lparam, tcItem.lParam);
|
||||||
|
|
||||||
|
DestroyWindow(hTab);
|
||||||
|
|
||||||
hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
|
hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
|
||||||
ok(hTab != NULL, "Failed to create tab control\n");
|
ok(hTab != NULL, "Failed to create tab control\n");
|
||||||
|
|
||||||
|
@ -1233,6 +1270,101 @@ static void test_TCM_SETITEMEXTRA(HWND parent_wnd)
|
||||||
DestroyWindow(hTab);
|
DestroyWindow(hTab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_TCS_OWNERDRAWFIXED(HWND parent_wnd)
|
||||||
|
{
|
||||||
|
LPARAM lparam, lparam2;
|
||||||
|
TCITEMA item;
|
||||||
|
HWND hTab;
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH|TCS_OWNERDRAWFIXED, TCIF_TEXT|TCIF_IMAGE, 4);
|
||||||
|
ok(hTab != NULL, "Failed to create tab control\n");
|
||||||
|
|
||||||
|
ok(GetParent(hTab) == NULL, "got %p, expected null parent\n", GetParent(hTab));
|
||||||
|
|
||||||
|
/* set some item data */
|
||||||
|
memset(&lparam, 0xde, sizeof(LPARAM));
|
||||||
|
|
||||||
|
item.mask = TCIF_PARAM;
|
||||||
|
item.lParam = lparam;
|
||||||
|
ret = SendMessageA(hTab, TCM_SETITEMA, 0, (LPARAM)&item);
|
||||||
|
ok(ret == TRUE, "got %d\n", ret);
|
||||||
|
|
||||||
|
memset(&g_drawitem, 0, sizeof(g_drawitem));
|
||||||
|
|
||||||
|
ShowWindow(hTab, SW_SHOW);
|
||||||
|
RedrawWindow(hTab, NULL, 0, RDW_UPDATENOW);
|
||||||
|
|
||||||
|
lparam = 0;
|
||||||
|
memset(&lparam, 0xde, 4);
|
||||||
|
ok(g_drawitem.itemData == lparam, "got %lx, expected %lx\n", g_drawitem.itemData, lparam);
|
||||||
|
|
||||||
|
DestroyWindow(hTab);
|
||||||
|
|
||||||
|
/* now with custom extra data length */
|
||||||
|
hTab = CreateWindowA(
|
||||||
|
WC_TABCONTROLA,
|
||||||
|
"TestTab",
|
||||||
|
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | TCS_FIXEDWIDTH | TCS_OWNERDRAWFIXED,
|
||||||
|
10, 10, 300, 100,
|
||||||
|
parent_wnd, NULL, NULL, 0);
|
||||||
|
|
||||||
|
ok(GetParent(hTab) == NULL, "got %p, expected null parent\n", GetParent(hTab));
|
||||||
|
|
||||||
|
ret = SendMessageA(hTab, TCM_SETITEMEXTRA, sizeof(LPARAM)+1, 0);
|
||||||
|
ok(ret == TRUE, "got %d\n", ret);
|
||||||
|
|
||||||
|
/* set some item data */
|
||||||
|
memset(&lparam, 0xde, sizeof(LPARAM));
|
||||||
|
item.mask = TCIF_PARAM;
|
||||||
|
item.lParam = lparam;
|
||||||
|
|
||||||
|
ret = SendMessageA(hTab, TCM_INSERTITEMA, 0, (LPARAM)&item);
|
||||||
|
ok(ret == 0, "got %d\n", ret);
|
||||||
|
|
||||||
|
memset(&g_drawitem, 0, sizeof(g_drawitem));
|
||||||
|
|
||||||
|
ShowWindow(hTab, SW_SHOW);
|
||||||
|
RedrawWindow(hTab, NULL, 0, RDW_UPDATENOW);
|
||||||
|
|
||||||
|
ok(*(ULONG_PTR*)g_drawitem.itemData == lparam, "got %lx, expected %lx\n", g_drawitem.itemData, lparam);
|
||||||
|
|
||||||
|
DestroyWindow(hTab);
|
||||||
|
|
||||||
|
/* same thing, but size smaller than default */
|
||||||
|
hTab = CreateWindowA(
|
||||||
|
WC_TABCONTROLA,
|
||||||
|
"TestTab",
|
||||||
|
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | TCS_FIXEDWIDTH | TCS_OWNERDRAWFIXED,
|
||||||
|
10, 10, 300, 100,
|
||||||
|
parent_wnd, NULL, NULL, 0);
|
||||||
|
|
||||||
|
ok(GetParent(hTab) == NULL, "got %p, expected null parent\n", GetParent(hTab));
|
||||||
|
|
||||||
|
ret = SendMessageA(hTab, TCM_SETITEMEXTRA, sizeof(LPARAM)-1, 0);
|
||||||
|
ok(ret == TRUE, "got %d\n", ret);
|
||||||
|
|
||||||
|
memset(&lparam, 0xde, sizeof(lparam));
|
||||||
|
item.mask = TCIF_PARAM;
|
||||||
|
item.lParam = lparam;
|
||||||
|
|
||||||
|
ret = SendMessageA(hTab, TCM_INSERTITEMA, 0, (LPARAM)&item);
|
||||||
|
ok(ret == 0, "got %d\n", ret);
|
||||||
|
|
||||||
|
memset(&g_drawitem, 0, sizeof(g_drawitem));
|
||||||
|
|
||||||
|
ShowWindow(hTab, SW_SHOW);
|
||||||
|
RedrawWindow(hTab, NULL, 0, RDW_UPDATENOW);
|
||||||
|
|
||||||
|
lparam = 0;
|
||||||
|
memset(&lparam, 0xde, 4);
|
||||||
|
memset(&lparam2, 0xde, sizeof(LPARAM)-1);
|
||||||
|
ok(g_drawitem.itemData == lparam || broken(g_drawitem.itemData == lparam2) /* win98 */,
|
||||||
|
"got 0x%lx, expected 0x%lx\n", g_drawitem.itemData, lparam);
|
||||||
|
|
||||||
|
DestroyWindow(hTab);
|
||||||
|
}
|
||||||
|
|
||||||
START_TEST(tab)
|
START_TEST(tab)
|
||||||
{
|
{
|
||||||
HWND parent_wnd;
|
HWND parent_wnd;
|
||||||
|
@ -1278,6 +1410,7 @@ START_TEST(tab)
|
||||||
test_delete_selection(parent_wnd);
|
test_delete_selection(parent_wnd);
|
||||||
test_removeimage(parent_wnd);
|
test_removeimage(parent_wnd);
|
||||||
test_TCM_SETITEMEXTRA(parent_wnd);
|
test_TCM_SETITEMEXTRA(parent_wnd);
|
||||||
|
test_TCS_OWNERDRAWFIXED(parent_wnd);
|
||||||
|
|
||||||
DestroyWindow(parent_wnd);
|
DestroyWindow(parent_wnd);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue