comctl32/listview: Use a code set by dispinfo holder to convert data encoding after LVN_GETDISPINFO.

This commit is contained in:
Nikolay Sivov 2010-11-16 23:55:23 +03:00 committed by Alexandre Julliard
parent 107a95d86b
commit 119860b05f
2 changed files with 120 additions and 49 deletions

View File

@ -928,74 +928,104 @@ static BOOL notify_deleteitem(const LISTVIEW_INFO *infoPtr, INT nItem)
Send notification. depends on dispinfoW having same
structure as dispinfoA.
infoPtr : listview struct
notificationCode : *Unicode* notification code
code : *Unicode* notification code
pdi : dispinfo structure (can be unicode or ansi)
isW : TRUE if dispinfo is Unicode
*/
static BOOL notify_dispinfoT(const LISTVIEW_INFO *infoPtr, UINT notificationCode, LPNMLVDISPINFOW pdi, BOOL isW)
static BOOL notify_dispinfoT(const LISTVIEW_INFO *infoPtr, UINT code, LPNMLVDISPINFOW pdi, BOOL isW)
{
BOOL bResult = FALSE;
BOOL convertToAnsi = FALSE, convertToUnicode = FALSE;
INT cchTempBufMax = 0, savCchTextMax = 0;
UINT realNotifCode;
LPWSTR pszTempBuf = NULL, savPszText = NULL;
INT length = 0, ret_length;
LPWSTR buffer = NULL, ret_text;
BOOL return_ansi = FALSE;
BOOL return_unicode = FALSE;
BOOL ret;
if ((pdi->item.mask & LVIF_TEXT) && is_text(pdi->item.pszText))
{
convertToAnsi = (isW && infoPtr->notifyFormat == NFR_ANSI);
convertToUnicode = (!isW && infoPtr->notifyFormat == NFR_UNICODE);
return_unicode = ( isW && infoPtr->notifyFormat == NFR_ANSI);
return_ansi = (!isW && infoPtr->notifyFormat == NFR_UNICODE);
}
if (convertToAnsi || convertToUnicode)
ret_length = pdi->item.cchTextMax;
ret_text = pdi->item.pszText;
if (return_unicode || return_ansi)
{
if (notificationCode != LVN_GETDISPINFOW)
{
cchTempBufMax = convertToUnicode ?
if (code != LVN_GETDISPINFOW)
{
length = return_ansi ?
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pdi->item.pszText, -1, NULL, 0):
WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, NULL, 0, NULL, NULL);
}
else
{
cchTempBufMax = pdi->item.cchTextMax;
*pdi->item.pszText = 0; /* make sure we don't process garbage */
}
}
else
{
length = pdi->item.cchTextMax;
*pdi->item.pszText = 0; /* make sure we don't process garbage */
}
pszTempBuf = Alloc( (convertToUnicode ? sizeof(WCHAR) : sizeof(CHAR)) * cchTempBufMax);
if (!pszTempBuf) return FALSE;
buffer = Alloc( (return_ansi ? sizeof(WCHAR) : sizeof(CHAR)) * length);
if (!buffer) return FALSE;
if (convertToUnicode)
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pdi->item.pszText, -1,
pszTempBuf, cchTempBufMax);
else
WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) pszTempBuf,
cchTempBufMax, NULL, NULL);
if (return_ansi)
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pdi->item.pszText, -1,
buffer, length);
else
WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) buffer,
length, NULL, NULL);
savCchTextMax = pdi->item.cchTextMax;
savPszText = pdi->item.pszText;
pdi->item.pszText = pszTempBuf;
pdi->item.cchTextMax = cchTempBufMax;
pdi->item.pszText = buffer;
pdi->item.cchTextMax = length;
}
if (infoPtr->notifyFormat == NFR_ANSI)
realNotifCode = get_ansi_notification(notificationCode);
else
realNotifCode = notificationCode;
TRACE(" pdi->item=%s\n", debuglvitem_t(&pdi->item, infoPtr->notifyFormat != NFR_ANSI));
bResult = notify_hdr(infoPtr, realNotifCode, &pdi->hdr);
code = get_ansi_notification(code);
if (convertToUnicode || convertToAnsi)
TRACE(" pdi->item=%s\n", debuglvitem_t(&pdi->item, infoPtr->notifyFormat != NFR_ANSI));
ret = notify_hdr(infoPtr, code, &pdi->hdr);
TRACE(" resulting code=0x%08x\n", pdi->hdr.code);
if (return_ansi || return_unicode)
{
if (convertToUnicode) /* note : pointer can be changed by app ! */
WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) savPszText,
savCchTextMax, NULL, NULL);
else
MultiByteToWideChar(CP_ACP, 0, (LPSTR) pdi->item.pszText, -1,
savPszText, savCchTextMax);
pdi->item.pszText = savPszText; /* restores our buffer */
pdi->item.cchTextMax = savCchTextMax;
Free (pszTempBuf);
if (return_ansi && (pdi->hdr.code == LVN_GETDISPINFOA))
{
strcpy((char*)ret_text, (char*)pdi->item.pszText);
}
else if (return_unicode && (pdi->hdr.code == LVN_GETDISPINFOW))
{
strcpyW(ret_text, pdi->item.pszText);
}
else if (return_ansi) /* note : pointer can be changed by app ! */
{
WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) ret_text,
ret_length, NULL, NULL);
}
else
MultiByteToWideChar(CP_ACP, 0, (LPSTR) pdi->item.pszText, -1,
ret_text, ret_length);
pdi->item.pszText = ret_text; /* restores our buffer */
pdi->item.cchTextMax = ret_length;
Free(buffer);
return ret;
}
return bResult;
/* if dipsinfo holder changed notification code then convert */
if (!isW && (pdi->hdr.code == LVN_GETDISPINFOW))
{
length = WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, NULL, 0, NULL, NULL);
buffer = Alloc(length * sizeof(CHAR));
if (!buffer) return FALSE;
WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) buffer,
ret_length, NULL, NULL);
strcpy((LPSTR)pdi->item.pszText, (LPSTR)buffer);
Free(buffer);
}
return ret;
}
static void customdraw_fill(NMLVCUSTOMDRAW *lpnmlvcd, const LISTVIEW_INFO *infoPtr, HDC hdc,
@ -6490,7 +6520,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem,
if (lpLVItem->mask & LVIF_STATE)
dispInfo.item.stateMask = lpLVItem->stateMask & infoPtr->uCallbackMask;
/* could be zeroed on LVIF_NORECOMPUTE case */
if (dispInfo.item.mask != 0)
if (dispInfo.item.mask)
{
notify_dispinfoT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW);
dispInfo.item.stateMask = lpLVItem->stateMask;
@ -6596,7 +6626,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem,
}
/* If we don't have all the requested info, query the application */
if (dispInfo.item.mask != 0)
if (dispInfo.item.mask)
{
dispInfo.item.iItem = lpLVItem->iItem;
dispInfo.item.iSubItem = lpLVItem->iSubItem; /* yes: the original subitem */

View File

@ -59,6 +59,8 @@ static INT notifyFormat;
static BOOL g_is_below_5;
/* item data passed to LVN_GETDISPINFOA */
static LVITEMA g_itema;
/* alter notification code A->W */
static BOOL g_disp_A_to_W;
static HWND subclass_editbox(HWND hwndListview);
@ -372,6 +374,13 @@ static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LP
{
NMLVDISPINFOA *dispinfo = (NMLVDISPINFOA*)lParam;
g_itema = dispinfo->item;
if (g_disp_A_to_W && (dispinfo->item.mask & LVIF_TEXT))
{
static const WCHAR testW[] = {'T','E','S','T',0};
dispinfo->hdr.code = LVN_GETDISPINFOW;
memcpy(dispinfo->item.pszText, testW, sizeof(testW));
}
}
break;
case NM_HOVER:
@ -4538,6 +4547,37 @@ static void test_createdragimage(void)
DestroyWindow(list);
}
static void test_dispinfo(void)
{
static const char testA[] = "TEST";
WCHAR buff[10];
LVITEMA item;
HWND hwnd;
INT ret;
hwnd = create_listview_control(LVS_ICON);
ok(hwnd != 0, "failed to create listview window\n");
insert_item(hwnd, 0);
memset(&item, 0, sizeof(item));
item.pszText = LPSTR_TEXTCALLBACKA;
ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
ok(ret, "got %d\n", ret);
g_disp_A_to_W = TRUE;
item.pszText = (char*)buff;
item.cchTextMax = sizeof(buff)/sizeof(WCHAR);
ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
ok(ret == sizeof(testA)-1, "got %d, expected 4\n", ret);
g_disp_A_to_W = FALSE;
ok(memcmp(item.pszText, testA, sizeof(testA)) == 0,
"got %s, expected %s\n", item.pszText, testA);
DestroyWindow(hwnd);
}
START_TEST(listview)
{
HMODULE hComctl32;
@ -4601,6 +4641,7 @@ START_TEST(listview)
test_hover();
test_destroynotify();
test_createdragimage();
test_dispinfo();
if (!load_v6_module(&ctx_cookie, &hCtx))
{