[PATCH 2/3] comctl32/pager: Support tooltip notification conversion.

Zhiyi Zhang zzhang at codeweavers.com
Mon Aug 27 22:28:16 CDT 2018


Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
 dlls/comctl32/pager.c       |  72 +++++++++++++++++++
 dlls/comctl32/tests/pager.c | 137 ++++++++++++++++++++++++++++++++++++
 2 files changed, 209 insertions(+)

diff --git a/dlls/comctl32/pager.c b/dlls/comctl32/pager.c
index 0367108db2..9ab492e333 100644
--- a/dlls/comctl32/pager.c
+++ b/dlls/comctl32/pager.c
@@ -84,6 +84,8 @@ typedef struct
     INT    TLbtnState; /* state of top or left btn */
     INT    BRbtnState; /* state of bottom or right btn */
     INT    direction;  /* direction of the scroll, (e.g. PGF_SCROLLUP) */
+    WCHAR  *pwszBuffer;/* text buffer for converted notifications */
+    INT    nBufferSize;/* size of the above buffer */
 } PAGER_INFO;
 
 #define TIMERID1         1
@@ -605,6 +607,7 @@ static LRESULT
 PAGER_Destroy (PAGER_INFO *infoPtr)
 {
     SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
+    heap_free (infoPtr->pwszBuffer);
     heap_free (infoPtr);
     return 0;
 }
@@ -1038,10 +1041,25 @@ static UINT PAGER_GetAnsiNtfCode(UINT code)
     /* Toolbar */
     case TBN_GETBUTTONINFOW: return TBN_GETBUTTONINFOA;
     case TBN_GETINFOTIPW: return TBN_GETINFOTIPA;
+    /* Tooltip */
+    case TTN_GETDISPINFOW: return TTN_GETDISPINFOA;
     }
     return code;
 }
 
+static BOOL PAGER_AdjustBuffer(PAGER_INFO *infoPtr, INT size)
+{
+    if (!infoPtr->pwszBuffer)
+        infoPtr->pwszBuffer = heap_alloc(size);
+    else if (infoPtr->nBufferSize < size)
+        infoPtr->pwszBuffer = heap_realloc(infoPtr->pwszBuffer, size);
+
+    if (!infoPtr->pwszBuffer) return FALSE;
+    if (infoPtr->nBufferSize < size) infoPtr->nBufferSize = size;
+
+    return TRUE;
+}
+
 static LRESULT PAGER_SendConvertedNotify(PAGER_INFO *infoPtr, NMHDR *hdr, WCHAR **text, INT *textMax, ConversionFlag flags)
 {
     WCHAR emptyW[] = {0};
@@ -1093,6 +1111,8 @@ done:
 
 static LRESULT PAGER_Notify(PAGER_INFO *infoPtr, NMHDR *hdr)
 {
+    LRESULT ret;
+
     if (infoPtr->bUnicode) return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
 
     switch (hdr->code)
@@ -1109,6 +1129,58 @@ static LRESULT PAGER_Notify(PAGER_INFO *infoPtr, NMHDR *hdr)
         NMTBGETINFOTIPW *nmtbgit = (NMTBGETINFOTIPW *)hdr;
         return PAGER_SendConvertedNotify(infoPtr, hdr, &nmtbgit->pszText, &nmtbgit->cchTextMax, FROM_ANSI);
     }
+    /* Tooltip */
+    case TTN_GETDISPINFOW:
+    {
+        NMTTDISPINFOW *nmttdiW = (NMTTDISPINFOW *)hdr;
+        NMTTDISPINFOA nmttdiA = {0};
+        INT size;
+
+        nmttdiA.hdr.code = PAGER_GetAnsiNtfCode(nmttdiW->hdr.code);
+        nmttdiA.hdr.hwndFrom = nmttdiW->hdr.hwndFrom;
+        nmttdiA.hdr.idFrom = nmttdiW->hdr.idFrom;
+        nmttdiA.hinst = nmttdiW->hinst;
+        nmttdiA.uFlags = nmttdiW->uFlags;
+        nmttdiA.lParam = nmttdiW->lParam;
+        nmttdiA.lpszText = nmttdiA.szText;
+        WideCharToMultiByte(CP_ACP, 0, nmttdiW->szText, ARRAY_SIZE(nmttdiW->szText), nmttdiA.szText,
+                            ARRAY_SIZE(nmttdiA.szText), NULL, FALSE);
+
+        ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)&nmttdiA);
+
+        nmttdiW->hinst = nmttdiA.hinst;
+        nmttdiW->uFlags = nmttdiA.uFlags;
+        nmttdiW->lParam = nmttdiA.lParam;
+
+        MultiByteToWideChar(CP_ACP, 0, nmttdiA.szText, ARRAY_SIZE(nmttdiA.szText), nmttdiW->szText,
+                            ARRAY_SIZE(nmttdiW->szText));
+        if (!nmttdiA.lpszText)
+            nmttdiW->lpszText = nmttdiW->szText;
+        else if (!IS_INTRESOURCE(nmttdiA.lpszText))
+        {
+            size = MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1, 0, 0);
+            if (size > ARRAY_SIZE(nmttdiW->szText))
+            {
+                if (!PAGER_AdjustBuffer(infoPtr, size * sizeof(WCHAR))) return ret;
+                MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1, infoPtr->pwszBuffer, size);
+                nmttdiW->lpszText = infoPtr->pwszBuffer;
+                /* Override content in szText */
+                memcpy(nmttdiW->szText, nmttdiW->lpszText, min(sizeof(nmttdiW->szText), size * sizeof(WCHAR)));
+            }
+            else
+            {
+                MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1, nmttdiW->szText, ARRAY_SIZE(nmttdiW->szText));
+                nmttdiW->lpszText = nmttdiW->szText;
+            }
+        }
+        else
+        {
+            nmttdiW->szText[0] = 0;
+            nmttdiW->lpszText = (WCHAR *)nmttdiA.lpszText;
+        }
+
+        return ret;
+    }
     }
     /* Other notifications or notifications above that don't have text, thus no need to convert */
     return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
diff --git a/dlls/comctl32/tests/pager.c b/dlls/comctl32/tests/pager.c
index 46f2eb0acb..bf79f34c5b 100644
--- a/dlls/comctl32/tests/pager.c
+++ b/dlls/comctl32/tests/pager.c
@@ -630,6 +630,53 @@ static LRESULT WINAPI test_notify_proc(HWND hwnd, UINT message, WPARAM wParam, L
             wm_notify_text_handler(&nmtbgit->pszText, &nmtbgit->cchTextMax);
             break;
         }
+        /* Tooltip */
+        case TTN_GETDISPINFOA:
+        {
+            NMTTDISPINFOA *nmttdi = (NMTTDISPINFOA *)hdr;
+            switch (notify_test_data.sub_test_id)
+            {
+            case 0:
+                break;
+            case 1:
+                memcpy(nmttdi->szText, test_a, sizeof(test_a));
+                break;
+            case 2:
+                memcpy(nmttdi->szText, test_a, sizeof(test_a));
+                nmttdi->lpszText = test_a;
+                break;
+            case 3:
+                memcpy(nmttdi->szText, test_a, sizeof(test_a));
+                nmttdi->lpszText = (CHAR *)1;
+                nmttdi->hinst = GetModuleHandleA(0);
+                break;
+            case 4:
+                memcpy(nmttdi->szText, test_a, sizeof(test_a));
+                nmttdi->lpszText = test_a;
+                nmttdi->hinst = GetModuleHandleA(0);
+                break;
+            case 5:
+                nmttdi->lpszText = test_a;
+                break;
+            case 6:
+                memcpy(nmttdi->szText, test_a, 2);
+                nmttdi->szText[2] = 0;
+                nmttdi->lpszText = test_a;
+                break;
+            case 7:
+                expect_eq_text_a(nmttdi->szText, test_a);
+                expect_eq_pointer(nmttdi->lpszText, nmttdi->szText);
+                break;
+            case 8:
+                expect_text_empty(nmttdi->szText);
+                expect_eq_pointer(nmttdi->lpszText, nmttdi->szText);
+                break;
+            case 9:
+                nmttdi->lpszText = large_a;
+                break;
+            }
+            break;
+        }
         default:
             ok(0, "Unexpected message 0x%08x\n", hdr->code);
         }
@@ -828,6 +875,95 @@ static void test_wm_notify_toolbar(HWND pager)
                                TBN_GETINFOTIPA, FROM_ANSI);
 }
 
+static void test_wm_notify_tooltip(HWND pager)
+{
+    NMTTDISPINFOW nmttdi;
+    WCHAR *buffer_w;
+    INT size;
+
+    /* if lpszText is not set by parent, will be set to the address of szText, even if szText is empty */
+    notify_test_data.sub_test_id = 0;
+    memset(&nmttdi, 0, sizeof(nmttdi));
+    send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE, TRUE);
+    expect_text_empty(nmttdi.szText);
+    expect_eq_pointer(nmttdi.lpszText, nmttdi.szText);
+
+    /* Parent write szText. If lpszText is not set by parent, will be set to the address of szText */
+    notify_test_data.sub_test_id = 1;
+    memset(&nmttdi, 0, sizeof(nmttdi));
+    send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE, TRUE);
+    expect_eq_text_w(nmttdi.szText, test_w);
+    expect_eq_pointer(nmttdi.lpszText, nmttdi.szText);
+
+    /* Parent write szText. Parent replace nmttdi.lpszText with pointer */
+    notify_test_data.sub_test_id = 2;
+    memset(&nmttdi, 0, sizeof(nmttdi));
+    send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE, TRUE);
+    expect_eq_text_w(nmttdi.szText, test_w);
+    expect_eq_pointer(nmttdi.lpszText, nmttdi.szText);
+
+    /* Parent write szText. Parent set int resource. szText end up empty */
+    notify_test_data.sub_test_id = 3;
+    memset(&nmttdi, 0, sizeof(nmttdi));
+    send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE, TRUE);
+    expect_text_empty(nmttdi.szText);
+    ok(IS_INTRESOURCE(nmttdi.lpszText), "Expect int resource\n");
+    ok(nmttdi.hinst != NULL, "Expect instance gets set\n");
+
+    /* Parent set szText, lpszText and instance */
+    notify_test_data.sub_test_id = 4;
+    memset(&nmttdi, 0, sizeof(nmttdi));
+    send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE, TRUE);
+    expect_eq_text_w(nmttdi.szText, test_w);
+    expect_eq_pointer(nmttdi.lpszText, nmttdi.szText);
+    ok(nmttdi.hinst != NULL, "Expect instance gets set\n");
+
+    /* Empty szText will be filled with lpszText if lpszText is set */
+    notify_test_data.sub_test_id = 5;
+    memset(&nmttdi, 0, sizeof(nmttdi));
+    send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE, TRUE);
+    expect_eq_text_w(nmttdi.szText, test_w);
+    expect_eq_pointer(nmttdi.lpszText, nmttdi.szText);
+
+    /* Not empty szText will be overwritten with lpszText if lpszText is set after conversion */
+    notify_test_data.sub_test_id = 6;
+    memset(&nmttdi, 0, sizeof(nmttdi));
+    send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE, TRUE);
+    expect_eq_text_w(nmttdi.szText, test_w);
+    expect_eq_pointer(nmttdi.lpszText, nmttdi.szText);
+
+    /* Set szText before send_notify. szText got converted for parent */
+    notify_test_data.sub_test_id = 7;
+    memset(&nmttdi, 0, sizeof(nmttdi));
+    memcpy(nmttdi.szText, test_w, sizeof(test_w));
+    send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE, TRUE);
+    expect_eq_text_w(nmttdi.szText, test_w);
+    expect_eq_pointer(nmttdi.lpszText, nmttdi.szText);
+
+    /* Set lpszText before send_notify. lpszText doesn't get converted for parent */
+    notify_test_data.sub_test_id = 8;
+    memset(&nmttdi, 0, sizeof(nmttdi));
+    nmttdi.lpszText = test_w;
+    send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE, TRUE);
+    expect_text_empty(nmttdi.szText);
+    expect_eq_pointer(nmttdi.lpszText, nmttdi.szText);
+
+    /* Parent set lpszText to a string larger than the size of szText array */
+    notify_test_data.sub_test_id = 9;
+    memset(&nmttdi, 0, sizeof(nmttdi));
+    send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE, TRUE);
+    size = MultiByteToWideChar(CP_ACP, 0, large_a, -1, 0, 0);
+    buffer_w = heap_alloc(size * sizeof(WCHAR));
+    if (!buffer_w) return;
+    MultiByteToWideChar(CP_ACP, 0, large_a, -1, buffer_w, size);
+    expect_eq_text_w(nmttdi.lpszText, buffer_w);
+    buffer_w[ARRAY_SIZE(nmttdi.szText)] = 0;
+    expect_eq_text_w(nmttdi.szText, buffer_w);
+    /* nmttdi.szText is not null terminated */
+    expect_eq_int(lstrlenW(nmttdi.szText), ARRAY_SIZE(nmttdi.szText));
+    heap_free(buffer_w);
+}
+
 static void test_wm_notify(void)
 {
     static const CHAR *class = "Pager notify class";
@@ -844,6 +980,7 @@ static void test_wm_notify(void)
     SendMessageW(pager, PGM_SETCHILD, 0, (LPARAM)child1_wnd);
 
     test_wm_notify_toolbar(pager);
+    test_wm_notify_tooltip(pager);
 
     DestroyWindow(parent);
     UnregisterClassA(class, GetModuleHandleA(NULL));
-- 
2.18.0





More information about the wine-devel mailing list