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

Alexandre Julliard julliard at winehq.org
Wed Nov 17 10:38:01 CST 2010


Module: wine
Branch: master
Commit: 119860b05f8c22d1525b573e461afe95e430a63b
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=119860b05f8c22d1525b573e461afe95e430a63b

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Tue Nov 16 23:55:23 2010 +0300

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

---

 dlls/comctl32/listview.c       |  130 ++++++++++++++++++++++++---------------
 dlls/comctl32/tests/listview.c |   41 +++++++++++++
 2 files changed, 121 insertions(+), 50 deletions(-)

diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c
index 6c4165d..fd9a499 100644
--- a/dlls/comctl32/listview.c
+++ b/dlls/comctl32/listview.c
@@ -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 */
- 	}
-
-	pszTempBuf = Alloc( (convertToUnicode ? sizeof(WCHAR) : sizeof(CHAR)) * cchTempBufMax);
-        if (!pszTempBuf) 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);
+        }
+        else
+        {
+            length = pdi->item.cchTextMax;
+            *pdi->item.pszText = 0; /* make sure we don't process garbage */
+        }
 
-        savCchTextMax = pdi->item.cchTextMax;
-        savPszText = pdi->item.pszText;
-        pdi->item.pszText = pszTempBuf;
-        pdi->item.cchTextMax = cchTempBufMax;
+        buffer = Alloc( (return_ansi ? sizeof(WCHAR) : sizeof(CHAR)) * length);
+        if (!buffer) return FALSE;
+
+        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);
+
+        pdi->item.pszText = buffer;
+        pdi->item.cchTextMax = length;
     }
 
     if (infoPtr->notifyFormat == NFR_ANSI)
-	realNotifCode = get_ansi_notification(notificationCode);
-    else
-	realNotifCode = notificationCode;
+        code = get_ansi_notification(code);
+
     TRACE(" pdi->item=%s\n", debuglvitem_t(&pdi->item, infoPtr->notifyFormat != NFR_ANSI));
-    bResult = notify_hdr(infoPtr, realNotifCode, &pdi->hdr);
+    ret = notify_hdr(infoPtr, code, &pdi->hdr);
+    TRACE(" resulting code=0x%08x\n", pdi->hdr.code);
 
-    if (convertToUnicode || convertToAnsi)
+    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 */
diff --git a/dlls/comctl32/tests/listview.c b/dlls/comctl32/tests/listview.c
index 0223167..89619f7 100644
--- a/dlls/comctl32/tests/listview.c
+++ b/dlls/comctl32/tests/listview.c
@@ -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))
     {




More information about the wine-cvs mailing list