[PATCH 3/3] Fix DRAWITEMSTRUCT filling when extra item data of a custom size is used

Nikolay Sivov nsivov at codeweavers.com
Tue Sep 28 17:36:14 CDT 2010


---
 dlls/comctl32/tab.c       |   32 ++++++------
 dlls/comctl32/tests/tab.c |  128 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 142 insertions(+), 18 deletions(-)

diff --git a/dlls/comctl32/tab.c b/dlls/comctl32/tab.c
index 0ecbb63..18a00fc 100644
--- a/dlls/comctl32/tab.c
+++ b/dlls/comctl32/tab.c
@@ -83,8 +83,10 @@ typedef struct
   BYTE   extra[1];  /* Space for caller supplied info, variable size */
 } TAB_ITEM;
 
-/* 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]))
+/* The size of a tab item depends on how much extra data is requested.
+   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
 {
@@ -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 ((infoPtr->dwStyle & TCS_OWNERDRAWFIXED) && GetParent(infoPtr->hwnd))
+  if ((infoPtr->dwStyle & TCS_OWNERDRAWFIXED) && IsWindow(infoPtr->hwndNotify))
   {
     DRAWITEMSTRUCT dis;
     UINT id;
@@ -1741,14 +1743,9 @@ TAB_DrawItemInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, RECT *drawRect
         drawRect->left += 1;
     }
 
-    /*
-     * get the control id
-     */
     id = (UINT)GetWindowLongPtrW( infoPtr->hwnd, GWLP_ID );
 
-    /*
-     * put together the DRAWITEMSTRUCT
-     */
+    /* fill DRAWITEMSTRUCT */
     dis.CtlType    = ODT_TAB;
     dis.CtlID      = id;
     dis.itemID     = iItem;
@@ -1761,11 +1758,14 @@ TAB_DrawItemInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, RECT *drawRect
     dis.hwndItem = infoPtr->hwnd;
     dis.hDC      = hdc;
     CopyRect(&dis.rcItem,drawRect);
-    dis.itemData = (ULONG_PTR)TAB_GetItem(infoPtr, iItem)->extra;
 
-    /*
-     * send the draw message
-     */
+    /* when extra data fits ULONG_PTR, store it directly */
+    if (infoPtr->cbInfo > sizeof(LPARAM))
+        dis.itemData =  (ULONG_PTR) TAB_GetItem(infoPtr, iItem)->extra;
+    else
+        dis.itemData = *(ULONG_PTR*)TAB_GetItem(infoPtr, iItem)->extra;
+
+    /* draw notification */
     SendMessageW( infoPtr->hwndNotify, WM_DRAWITEM, id, (LPARAM)&dis );
   }
   else
@@ -2686,10 +2686,10 @@ TAB_InsertItemT (TAB_INFO *infoPtr, INT iItem, const TCITEMW *pti, BOOL bUnicode
     item->iImage = -1;
 
   if (pti->mask & TCIF_PARAM)
-    memcpy(item->extra, &pti->lParam, infoPtr->cbInfo);
+    memcpy(item->extra, &pti->lParam, EXTRA_ITEM_SIZE(infoPtr));
   else
-    memset(item->extra, 0, infoPtr->cbInfo);
-  
+    memset(item->extra, 0, EXTRA_ITEM_SIZE(infoPtr));
+
   TAB_SetItemBounds(infoPtr);
   if (infoPtr->uNumItem > 1)
     TAB_InvalidateTabArea(infoPtr);
diff --git a/dlls/comctl32/tests/tab.c b/dlls/comctl32/tests/tab.c
index d74155d..65f294f 100644
--- a/dlls/comctl32/tests/tab.c
+++ b/dlls/comctl32/tests/tab.c
@@ -61,7 +61,8 @@
 	    "%s: Expected [%d,%d] got [%d,%d]\n", msg, (int)width, (int)height,\
             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];
 
@@ -337,6 +338,10 @@ static LRESULT WINAPI parentWindowProcess(HWND hwnd, UINT message, WPARAM wParam
         add_message(sequences, PARENT_SEQ_INDEX, &msg);
     }
 
+    /* dump sent structure data */
+    if (message == WM_DRAWITEM)
+        g_drawitem = *(DRAWITEMSTRUCT*)lParam;
+
     defwndproc_counter++;
     ret = DefWindowProcA(hwnd, message, wParam, lParam);
     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)
 {
+    char szText[32] = "New Label";
     TCITEM tcItem;
+    LPARAM lparam;
     DWORD ret;
-    char szText[32] = "New Label";
     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 specfiifed 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);
     ok(hTab != NULL, "Failed to create tab control\n");
 
@@ -1233,6 +1270,92 @@ static void test_TCM_SETITEMEXTRA(HWND parent_wnd)
     DestroyWindow(hTab);
 }
 
+static void test_TCS_OWNERDRAWFIXED(HWND parent_wnd)
+{
+    LPARAM lparam;
+    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 */
+    item.mask = TCIF_PARAM;
+    item.lParam = 0xdeadbeef;
+    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);
+
+    ok(g_drawitem.itemData == 0xdeadbeef, "got %lx, expected 0xdeadbeef\n", g_drawitem.itemData);
+
+    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 */
+    item.mask = TCIF_PARAM;
+    item.lParam = 0xdeadbeef;
+
+    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 == 0xdeadbeef, "got %lx, expected 0xdeadbeef\n", g_drawitem.itemData);
+
+    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);
+
+    ok(g_drawitem.itemData == lparam, "got 0x%lx, expected 0x%lx\n", g_drawitem.itemData, lparam);
+
+    DestroyWindow(hTab);
+}
+
 START_TEST(tab)
 {
     HWND parent_wnd;
@@ -1278,6 +1401,7 @@ START_TEST(tab)
     test_delete_selection(parent_wnd);
     test_removeimage(parent_wnd);
     test_TCM_SETITEMEXTRA(parent_wnd);
+    test_TCS_OWNERDRAWFIXED(parent_wnd);
 
     DestroyWindow(parent_wnd);
 }
-- 
1.5.6.5


--------------060404000302070600020803--



More information about the wine-patches mailing list