ChangeLog Streamline the GetItem usage. Fix fatal bug for ICON mode in LVS_ONWERDATA. Update documentation. --- dlls/comctl32/listview.c.K7 Fri Oct 4 12:29:55 2002 +++ dlls/comctl32/listview.c Fri Oct 4 14:30:45 2002 @@ -261,7 +261,7 @@ /* * forward declarations */ -static BOOL LISTVIEW_GetItemT(LISTVIEW_INFO *, LPLVITEMW, BOOL, BOOL); +static BOOL LISTVIEW_GetItemT(LISTVIEW_INFO *, LPLVITEMW, BOOL); static INT LISTVIEW_SuperHitTestItem(LISTVIEW_INFO *, LPLVHITTESTINFO, BOOL, BOOL); static void LISTVIEW_AlignLeft(LISTVIEW_INFO *); static void LISTVIEW_AlignTop(LISTVIEW_INFO *); @@ -677,7 +677,7 @@ item.iItem = iItem; item.iSubItem = 0; item.mask = LVIF_PARAM; - if (!LISTVIEW_GetItemT(infoPtr, &item, TRUE, TRUE)) return FALSE; + if (!LISTVIEW_GetItemT(infoPtr, &item, TRUE)) return FALSE; uItemState = 0; @@ -737,9 +737,9 @@ #define LISTVIEW_InvalidateList(infoPtr)\ LISTVIEW_InvalidateRect(infoPtr, &infoPtr->rcList) -static inline BOOL LISTVIEW_GetItemW(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL internal) +static inline BOOL LISTVIEW_GetItemW(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem) { - return LISTVIEW_GetItemT(infoPtr, lpLVItem, internal, TRUE); + return LISTVIEW_GetItemT(infoPtr, lpLVItem, TRUE); } static inline int LISTVIEW_GetType(LISTVIEW_INFO *infoPtr) @@ -955,7 +955,7 @@ item.iSubItem = 0; item.pszText = buffer; item.cchTextMax = COUNTOF(buffer); - if (!LISTVIEW_GetItemW(infoPtr, &item, TRUE)) return 0; + if (!LISTVIEW_GetItemW(infoPtr, &item)) return 0; /* check for a match */ if (lstrncmpiW(item.pszText,infoPtr->szSearchParam,infoPtr->nSearchParamLength) == 0) { @@ -1248,7 +1248,7 @@ lvItem.mask = LVIF_INDENT; lvItem.iItem = nItem; lvItem.iSubItem = 0; - if (!LISTVIEW_GetItemW(infoPtr, &lvItem, TRUE)) return FALSE; + if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE; /* do indent */ nIndent = infoPtr->iconSize.cx * lvItem.iIndent; @@ -2915,7 +2915,7 @@ lvItem.cchTextMax = COUNTOF(szDispText); lvItem.pszText = szDispText; *lvItem.pszText = '\0'; - if (!LISTVIEW_GetItemW(infoPtr, &lvItem, TRUE)) return FALSE; + if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE; TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem, TRUE)); @@ -2960,7 +2960,7 @@ lvItem.cchTextMax = DISP_TEXT_SIZE; lvItem.pszText = szDispText; *lvItem.pszText = '\0'; - if (!LISTVIEW_GetItemW(infoPtr, &lvItem, TRUE)) return FALSE; + if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE; TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem, TRUE)); /* now check if we need to update the focus rectangle */ @@ -3055,7 +3055,7 @@ lvItem.cchTextMax = DISP_TEXT_SIZE; lvItem.pszText = szDispText; *lvItem.pszText = '\0'; - if (!LISTVIEW_GetItemW(infoPtr, &lvItem, FALSE)) return FALSE; + if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE; TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem, TRUE)); /* now check if we need to update the focus rectangle */ @@ -3311,7 +3311,7 @@ item.iSubItem = 0; item.mask = LVIF_PARAM | LVIF_STATE; item.stateMask = LVIS_SELECTED | LVIS_FOCUSED; - if (!LISTVIEW_GetItemW(infoPtr, &item, TRUE)) continue; + if (!LISTVIEW_GetItemW(infoPtr, &item)) continue; ZeroMemory(&dis, sizeof(dis)); dis.hwndItem = infoPtr->hwndSelf; @@ -3341,7 +3341,7 @@ item.stateMask = LVIS_SELECTED; item.iItem = nItem; item.iSubItem = 0; - if (!LISTVIEW_GetItemW(infoPtr, &item, TRUE)) continue; + if (!LISTVIEW_GetItemW(infoPtr, &item)) continue; rcFullSelect.left = lpCols[0].rc.left + REPORT_MARGINX + infoPtr->iconSize.cx * item.iIndent + @@ -4068,7 +4068,7 @@ dispInfo.item.iItem = infoPtr->nEditLabelItem; dispInfo.item.iSubItem = 0; dispInfo.item.stateMask = ~0; - if (!LISTVIEW_GetItemW(infoPtr, &dispInfo.item, TRUE)) return FALSE; + if (!LISTVIEW_GetItemW(infoPtr, &dispInfo.item)) return FALSE; dispInfo.item.pszText = pszText; dispInfo.item.cchTextMax = textlenT(pszText, isW); @@ -4130,7 +4130,7 @@ dispInfo.item.stateMask = ~0; dispInfo.item.pszText = szDispText; dispInfo.item.cchTextMax = DISP_TEXT_SIZE; - if (!LISTVIEW_GetItemT(infoPtr, &dispInfo.item, FALSE, isW)) return 0; + if (!LISTVIEW_GetItemT(infoPtr, &dispInfo.item, isW)) return 0; infoPtr->hwndEdit = CreateEditLabelT(infoPtr, dispInfo.item.pszText, WS_VISIBLE, rect.left-2, rect.top-1, 0, rect.bottom - rect.top+2, isW); @@ -4348,7 +4348,7 @@ lvItem.iItem = nItem; lvItem.iSubItem = 0; - if (LISTVIEW_GetItemW(infoPtr, &lvItem, TRUE)) + if (LISTVIEW_GetItemW(infoPtr, &lvItem)) { if (lvItem.mask & LVIF_TEXT) { @@ -4666,28 +4666,33 @@ * PARAMETER(S): * [I] hwnd : window handle * [IO] lpLVItem : item info - * [I] internal : if true then we will use tricks that avoid copies - * but are not compatible with the regular interface * [I] isW : if TRUE, then lpLVItem is a LPLVITEMW, * if FALSE, the lpLVItem is a LPLVITEMA. * + * NOTE: + * This is the internal 'GetItem' interface -- it tries to + * be smart, and avoids text copies, if possible, by modifing + * lpLVItem->pszText to point to the text string. Please note + * that this is not always possible (e.g. OWNERDATA), so on + * entry you *must* supply valid values for pszText, and cchTextMax. + * The only difference to the documented interface is that upon + * return, you should use *only* the lpLVItem->pszText, rather than + * the buffer pointer you provided on input. Most code already does + * that, so it's not a problem. + * For the two cases when the text must be copied (that is, + * for LVM_GETITEM, and LVMGETITEMTEXT), use LISTVIEW_GetItemExtT. + * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ -static BOOL LISTVIEW_GetItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL internal, BOOL isW) +static BOOL LISTVIEW_GetItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW) { NMLVDISPINFOW dispInfo; LISTVIEW_ITEM *lpItem; ITEMHDR* pItemHdr; HDPA hdpaSubItems; - if (internal && !isW) - { - ERR("We can't have internal non-Unicode GetItem!\n"); - return FALSE; - } - /* In the following: * lpLVItem describes the information requested by the user * lpItem is what we have @@ -4695,7 +4700,7 @@ * information from the application */ - TRACE("(lpLVItem=%s, internal=%d, isW=%d)\n", debuglvitem_t(lpLVItem, isW), internal, isW); + TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW); if (!lpLVItem || (lpLVItem->iItem < 0) || (lpLVItem->iItem >= GETITEMCOUNT(infoPtr))) @@ -4826,14 +4831,11 @@ if ((dispInfo.item.mask & LVIF_DI_SETITEM) && pItemHdr->pszText) textsetptrT(&pItemHdr->pszText, dispInfo.item.pszText, isW); - /* If lpLVItem->pszText==dispInfo.item.pszText a copy is unnecessary, but */ - /* some apps give a new pointer in ListView_Notify so we can't be sure. */ - if (lpLVItem->pszText != dispInfo.item.pszText) - textcpynT(lpLVItem->pszText, isW, dispInfo.item.pszText, isW, lpLVItem->cchTextMax); + lpLVItem->pszText = dispInfo.item.pszText; } else if (lpLVItem->mask & LVIF_TEXT) { - if (internal) lpLVItem->pszText = pItemHdr->pszText; + if (isW) lpLVItem->pszText = pItemHdr->pszText; else textcpynT(lpLVItem->pszText, isW, pItemHdr->pszText, TRUE, lpLVItem->cchTextMax); } @@ -4881,6 +4883,42 @@ return TRUE; } +/*** + * DESCRIPTION: + * Retrieves item attributes. + * + * PARAMETER(S): + * [I] hwnd : window handle + * [IO] lpLVItem : item info + * [I] isW : if TRUE, then lpLVItem is a LPLVITEMW, + * if FALSE, the lpLVItem is a LPLVITEMA. + * + * NOTE: + * This is the external 'GetItem' interface -- it properly copies + * the text in the provided buffer. + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_GetItemExtT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW) +{ + LPWSTR pszText; + BOOL bResult; + + if (!lpLVItem || (lpLVItem->iItem < 0) || + (lpLVItem->iItem >= GETITEMCOUNT(infoPtr))) + return FALSE; + + pszText = lpLVItem->pszText; + bResult = LISTVIEW_GetItemT(infoPtr, lpLVItem, isW); + if (bResult && lpLVItem->pszText != pszText) + textcpynT(pszText, isW, lpLVItem->pszText, isW, lpLVItem->cchTextMax); + lpLVItem->pszText = pszText; + + return bResult; +} + /*** * DESCRIPTION: @@ -4955,6 +4993,7 @@ HDC hdc = GetDC (infoPtr->hwndSelf); HFONT hOldFont = SelectObject (hdc, infoPtr->hFont); UINT uFormat = LISTVIEW_DTFLAGS | DT_CALCRECT; + WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' }; RECT rcText = *rect; RECT rcBack = *rect; BOOL focused, selected; @@ -4984,11 +5023,9 @@ lvItem.mask = LVIF_TEXT; lvItem.iItem = nItem; lvItem.iSubItem = 0; - /* We will specify INTERNAL and so will receive back a const - * pointer to the text, rather than specifying a buffer to which - * to copy it. FIXME: what about OWNERDRAW??? - */ - if (!LISTVIEW_GetItemW(infoPtr, &lvItem, TRUE)) return FALSE; + lvItem.pszText = szDispText; + lvItem.cchTextMax = DISP_TEXT_SIZE; + if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE; InflateRect(&rcText, -2, 0); DrawTextW (hdc, lvItem.pszText, -1, &rcText, uFormat); @@ -5176,9 +5213,9 @@ lvItem.mask = LVIF_TEXT; lvItem.iItem = nItem; lvItem.iSubItem = 0; - lvItem.cchTextMax = DISP_TEXT_SIZE; lvItem.pszText = szDispText; - if (!LISTVIEW_GetItemW(infoPtr, &lvItem, TRUE)) return 0; + lvItem.cchTextMax = DISP_TEXT_SIZE; + if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return 0; /* FIXME: is this right? What if the label is very long? */ return LISTVIEW_GetStringWidthT(infoPtr, lvItem.pszText, TRUE); @@ -5235,7 +5272,7 @@ lvItem.iSubItem = 0; lvItem.mask = LVIF_STATE; lvItem.stateMask = uMask; - if (!LISTVIEW_GetItemW(infoPtr, &lvItem, TRUE)) return 0; + if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return 0; return lvItem.state & uMask; } @@ -5260,7 +5297,7 @@ lpLVItem->mask = LVIF_TEXT; lpLVItem->iItem = nItem; - if (!LISTVIEW_GetItemT(infoPtr, lpLVItem, FALSE, isW)) return 0; + if (!LISTVIEW_GetItemExtT(infoPtr, lpLVItem, isW)) return 0; return textlenT(lpLVItem->pszText, isW); } @@ -6263,7 +6300,7 @@ INT nLabelWidth; RECT rcHeader; LVITEMW lvItem; - WCHAR szDispText[DISP_TEXT_SIZE]; + WCHAR szDispText[DISP_TEXT_SIZE] = { 0 }; if (!infoPtr->hwndHeader) /* make sure we have a header */ return (FALSE); @@ -6306,14 +6343,13 @@ { lvItem.iSubItem = iCol; lvItem.mask = LVIF_TEXT; - lvItem.cchTextMax = DISP_TEXT_SIZE; lvItem.pszText = szDispText; - *lvItem.pszText = '\0'; + lvItem.cchTextMax = DISP_TEXT_SIZE; cx = 0; for(item_index = 0; item_index < GETITEMCOUNT(infoPtr); item_index++) { lvItem.iItem = item_index; - if (!LISTVIEW_GetItemT(infoPtr, &lvItem, FALSE, TRUE)) continue; + if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) continue; nLabelWidth = LISTVIEW_GetStringWidthT(infoPtr, lvItem.pszText, TRUE); cx = (nLabelWidth>cx)?nLabelWidth:cx; } @@ -6370,14 +6406,13 @@ lvItem.iSubItem = iCol; lvItem.mask = LVIF_TEXT; - lvItem.cchTextMax = DISP_TEXT_SIZE; lvItem.pszText = szDispText; - *lvItem.pszText = '\0'; + lvItem.cchTextMax = DISP_TEXT_SIZE; cx = size.cx; for(item_index = 0; item_index < GETITEMCOUNT(infoPtr); item_index++) { lvItem.iItem = item_index; - if (!LISTVIEW_GetItemT(infoPtr, &lvItem, FALSE, TRUE)) continue; + if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) continue; nLabelWidth = LISTVIEW_GetStringWidthT(infoPtr, lvItem.pszText, TRUE); nLabelWidth += TRAILING_PADDING; /* While it is possible for subitems to have icons, even MS messes @@ -8520,10 +8555,10 @@ return FALSE; case LVM_GETITEMA: - return LISTVIEW_GetItemT(infoPtr, (LPLVITEMW)lParam, FALSE, FALSE); + return LISTVIEW_GetItemExtT(infoPtr, (LPLVITEMW)lParam, FALSE); case LVM_GETITEMW: - return LISTVIEW_GetItemT(infoPtr, (LPLVITEMW)lParam, FALSE, TRUE); + return LISTVIEW_GetItemExtT(infoPtr, (LPLVITEMW)lParam, TRUE); case LVM_GETITEMCOUNT: return GETITEMCOUNT(infoPtr);