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

Zhiyi Zhang zzhang at codeweavers.com
Tue Sep 11 07:26:59 CDT 2018


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

diff --git a/dlls/comctl32/pager.c b/dlls/comctl32/pager.c
index be9bccbbc7..fd9af3147b 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, DWORD flags)
 {
     CHAR *sendBuffer = NULL;
@@ -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, CONVERT_RECEIVE);
     }
+    /* 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, 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 8cc990a702..56b3116fd7 100644
--- a/dlls/comctl32/tests/pager.c
+++ b/dlls/comctl32/tests/pager.c
@@ -35,12 +35,26 @@ static CHAR test_a[] = {'t', 'e', 's', 't', 0};
 static WCHAR empty_w[] = {0};
 static CHAR empty_a[] = {0};
 static CHAR large_a[] = "You should have received a copy of the GNU Lesser General Public License along with this ...";
+static WCHAR large_w[] = 
+{
+    'Y', 'o', 'u', ' ', 's', 'h', 'o', 'u', 'l', 'd', ' ', 'h', 'a', 'v', 'e', ' ', 'r', 'e', 'c', 'e', 'i', 'v', 'e',
+    'd', ' ', 'a', ' ', 'c', 'o', 'p', 'y', ' ', 'o', 'f', ' ', 't', 'h', 'e', ' ', 'G', 'N', 'U', ' ', 'L', 'e', 's',
+    's', 'e', 'r', ' ', 'G', 'e', 'n', 'e', 'r', 'a', 'l', ' ', 'P', 'u', 'b', 'l', 'i', 'c', ' ', 'L', 'i', 'c', 'e',
+    'n', 's', 'e', ' ', 'a', 'l', 'o', 'n', 'g', ' ', 'w', 'i', 't', 'h', ' ', 't', 'h', 'i', 's', ' ', '.', '.', '.', 0
+};
 static WCHAR large_truncated_65_w[65] =
 {
     'Y', 'o', 'u', ' ', 's', 'h', 'o', 'u', 'l', 'd', ' ', 'h', 'a', 'v', 'e', ' ', 'r', 'e', 'c', 'e', 'i', 'v',
     'e', 'd', ' ', 'a', ' ', 'c', 'o', 'p', 'y', ' ', 'o', 'f', ' ', 't', 'h', 'e', ' ', 'G', 'N', 'U', ' ', 'L',
     'e', 's', 's', 'e', 'r', ' ', 'G', 'e', 'n', 'e', 'r', 'a', 'l', ' ', 'P', 'u', 'b', 'l', 'i', 'c', 0
 };
+static WCHAR large_truncated_80_w[80] =
+{
+    'Y', 'o', 'u', ' ', 's', 'h', 'o', 'u', 'l', 'd', ' ', 'h', 'a', 'v', 'e', ' ', 'r', 'e', 'c', 'e',
+    'i', 'v', 'e', 'd', ' ', 'a', ' ', 'c', 'o', 'p', 'y', ' ', 'o', 'f', ' ', 't', 'h', 'e', ' ', 'G',
+    'N', 'U', ' ', 'L', 'e', 's', 's', 'e', 'r', ' ', 'G', 'e', 'n', 'e', 'r', 'a', 'l', ' ', 'P', 'u',
+    'b', 'l', 'i', 'c', ' ', 'L', 'i', 'c', 'e', 'n', 's', 'e', ' ', 'a', 'l', 'o', 'n', 'g', ' ', 'w'
+};
 static WCHAR buffer[64];
 
 /* Text field conversion test behavior flags. */
@@ -132,6 +146,38 @@ static const struct notify_test_receive_data test_not_convert_receive_datas[] =
     {empty_w, sizeof(empty_w), ARRAY_SIZE(buffer), test_a, NULL, 0, -1, test_a, ARRAY_SIZE(buffer)},
 };
 
+static const struct notify_test_tooltip_data
+{
+    /* Data for parent to write */
+    CHAR *write_sztext;
+    INT write_sztext_size;
+    CHAR *write_lpsztext;
+    HMODULE write_hinst;
+    /* Data when message returned */
+    WCHAR *return_sztext;
+    INT return_sztext_size;
+    WCHAR *return_lpsztext;
+    HMODULE return_hinst;
+    /* Data expected by parent */
+    CHAR *expect_sztext;
+    /* Data send to parent */
+    WCHAR *send_sztext;
+    INT send_sztext_size;
+    WCHAR *send_lpsztext;
+} test_tooltip_datas[] =
+{
+    {NULL, 0, NULL, NULL, empty_w, -1, empty_w},
+    {test_a, sizeof(test_a), NULL, NULL, test_w, -1, test_w},
+    {test_a, sizeof(test_a), test_a, NULL, test_w, -1, test_w},
+    {test_a, sizeof(test_a), (CHAR *)1, (HMODULE)0xdeadbeef, empty_w, -1, (WCHAR *)1, (HMODULE)0xdeadbeef},
+    {test_a, sizeof(test_a), test_a, (HMODULE)0xdeadbeef, test_w, -1, test_w, (HMODULE)0xdeadbeef},
+    {NULL, 0, test_a, NULL, test_w, -1, test_w},
+    {test_a, 2, test_a, NULL, test_w, -1, test_w},
+    {NULL, 0, NULL, NULL, test_w, -1, test_w, NULL, test_a, test_w, sizeof(test_w)},
+    {NULL, 0, NULL, NULL, empty_w, -1, empty_w, NULL, empty_a, NULL, 0, test_w},
+    {NULL, 0, large_a, NULL, large_truncated_80_w, sizeof(large_truncated_80_w), large_w}
+};
+
 #define CHILD1_ID 1
 #define CHILD2_ID 2
 
@@ -574,6 +620,19 @@ static void notify_generic_text_handler(CHAR **text, INT *text_max)
     }
 }
 
+static void notify_tooltip_handler(NMTTDISPINFOA *nm)
+{
+    const struct notify_test_tooltip_data *data = test_tooltip_datas + notify_test_info.sub_test_id;
+    ok(nm->lpszText == nm->szText, "Sub test %d expect %p, got %p\n", notify_test_info.sub_test_id, nm->szText,
+       nm->lpszText);
+    if (data->expect_sztext)
+        ok(!lstrcmpA(data->expect_sztext, nm->szText), "Sub test %d expect %s, got %s\n", notify_test_info.sub_test_id,
+           data->expect_sztext, nm->szText);
+    if (data->write_sztext) memcpy(nm->szText, data->write_sztext, data->write_sztext_size);
+    if (data->write_lpsztext) nm->lpszText = data->write_lpsztext;
+    if (data->write_hinst) nm->hinst = data->write_hinst;
+}
+
 static LRESULT WINAPI test_notify_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     static const WCHAR test[] = {'t', 'e', 's', 't', 0};
@@ -630,6 +689,12 @@ static LRESULT WINAPI test_notify_proc(HWND hwnd, UINT message, WPARAM wParam, L
             notify_generic_text_handler(&nmtbgit->pszText, &nmtbgit->cchTextMax);
             break;
         }
+        /* Tooltip */
+        case TTN_GETDISPINFOA:
+        {
+            notify_tooltip_handler((NMTTDISPINFOA *)hdr);
+            break;
+        }
         default:
             ok(0, "Unexpected message 0x%08x\n", hdr->code);
         }
@@ -775,6 +840,44 @@ static void test_notify_generic_text_helper(HWND pager, void *ptr, size_t size,
     send_notify(code_unicode, code_ansi, (LPARAM)ptr, TRUE);
 }
 
+static void test_wm_notify_tooltip(HWND pager)
+{
+    NMTTDISPINFOW nmttdi;
+    const struct notify_test_tooltip_data *data;
+    INT i;
+
+    for (i = 0; i < ARRAY_SIZE(test_tooltip_datas); i++)
+    {
+        data = test_tooltip_datas + i;
+        notify_test_info.sub_test_id = i;
+
+        memset(&nmttdi, 0, sizeof(nmttdi));
+        if (data->send_sztext) memcpy(nmttdi.szText, data->send_sztext, data->send_sztext_size);
+        if (data->send_lpsztext) nmttdi.lpszText = data->send_lpsztext;
+        send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE);
+        if (data->return_sztext)
+        {
+            if (data->return_sztext_size == -1)
+                ok(!lstrcmpW(nmttdi.szText, data->return_sztext), "Sub test %d expect %s, got %s\n", i,
+                   wine_dbgstr_w(data->return_sztext), wine_dbgstr_w(nmttdi.szText));
+            else
+                ok(!memcmp(nmttdi.szText, data->return_sztext, data->return_sztext_size), "Wrong szText content\n");
+        }
+        if (data->return_lpsztext)
+        {
+            if (IS_INTRESOURCE(data->return_lpsztext))
+                ok(nmttdi.lpszText == data->return_lpsztext, "Sub test %d expect %s, got %s\n", i,
+                   wine_dbgstr_w(data->return_lpsztext), wine_dbgstr_w(nmttdi.lpszText));
+            else
+                ok(!lstrcmpW(nmttdi.lpszText, data->return_lpsztext), "Test %d expect %s, got %s\n", i,
+                   wine_dbgstr_w(data->return_lpsztext), wine_dbgstr_w(nmttdi.lpszText));
+        }
+        if (data->return_hinst)
+            ok(nmttdi.hinst == data->return_hinst, "Sub test %d expect %p, got %p\n", i, data->return_hinst,
+               nmttdi.hinst);
+    }
+}
+
 static void test_wm_notify(void)
 {
     static const CHAR *class = "Pager notify class";
@@ -818,6 +921,9 @@ static void test_wm_notify(void)
                                         p->code_unicode, p->code_ansi, p->flags);
     }
 
+    /* Tests for those that can't be covered by generic text test helper */
+    test_wm_notify_tooltip(pager);
+
     DestroyWindow(parent);
     UnregisterClassA(class, GetModuleHandleA(NULL));
 }
-- 
2.18.0





More information about the wine-devel mailing list