[PATCH 1/3] comctl32/pager: Support toolbar notification conversion.

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


Fix BibleWorks 10 not displaying toolbar.

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

diff --git a/dlls/comctl32/pager.c b/dlls/comctl32/pager.c
index de63cad717..0367108db2 100644
--- a/dlls/comctl32/pager.c
+++ b/dlls/comctl32/pager.c
@@ -91,6 +91,17 @@ typedef struct
 #define INITIAL_DELAY    500
 #define REPEAT_DELAY     50
 
+/* Text field conversion behavior flags for PAGER_SendConvertedNotify() */
+typedef enum
+{
+    /* Convert ANSI text from parent back to Unicode for pager */
+    FROM_ANSI = 0x01,
+    /* Convert Unicode text to ANSI for parent before sending. If not set, do nothing */
+    TO_ANSI = 0x02,
+    /* Send empty text to parent if text is NULL, original text pointer still remain NULL */
+    SET_NULL_EMPTY = 0x04
+} ConversionFlag;
+
 static void
 PAGER_GetButtonRects(const PAGER_INFO* infoPtr, RECT* prcTopLeft, RECT* prcBottomRight, BOOL bClientCoords)
 {
@@ -1020,6 +1031,89 @@ static LRESULT PAGER_NotifyFormat(PAGER_INFO *infoPtr, INT command)
     }
 }
 
+static UINT PAGER_GetAnsiNtfCode(UINT code)
+{
+    switch (code)
+    {
+    /* Toolbar */
+    case TBN_GETBUTTONINFOW: return TBN_GETBUTTONINFOA;
+    case TBN_GETINFOTIPW: return TBN_GETINFOTIPA;
+    }
+    return code;
+}
+
+static LRESULT PAGER_SendConvertedNotify(PAGER_INFO *infoPtr, NMHDR *hdr, WCHAR **text, INT *textMax, ConversionFlag flags)
+{
+    WCHAR emptyW[] = {0};
+    WCHAR *oldText;
+    INT oldTextMax;
+    void *sendBuffer = NULL;
+    void *receiveBuffer = NULL;
+    INT bufferSize;
+    LRESULT ret = 0;
+
+    oldText = *text;
+    oldTextMax = textMax ? *textMax : 0;
+
+    hdr->code = PAGER_GetAnsiNtfCode(hdr->code);
+
+    if (oldTextMax < 0) goto done;
+
+    if (!*text && flags & SET_NULL_EMPTY)
+        *text = emptyW;
+
+    if (*text && flags & TO_ANSI)
+    {
+        bufferSize = WideCharToMultiByte(CP_ACP, 0, *text, -1, 0, 0, NULL, FALSE);
+        bufferSize = max(bufferSize, oldTextMax);
+        sendBuffer = heap_alloc(bufferSize);
+        if (!sendBuffer) goto done;
+        WideCharToMultiByte(CP_ACP, 0, *text, -1, sendBuffer, bufferSize, NULL, FALSE);
+        *text = sendBuffer;
+    }
+
+    ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
+
+    if (*text && flags & FROM_ANSI)
+    {
+        bufferSize = lstrlenA((CHAR *)*text);
+        receiveBuffer = heap_alloc(bufferSize + 1);
+        if (!receiveBuffer) goto done;
+        memcpy(receiveBuffer, *text, bufferSize + 1);
+        if (!oldText) goto done;
+        MultiByteToWideChar(CP_ACP, 0, receiveBuffer, -1, oldText, oldTextMax);
+    }
+
+done:
+    heap_free(sendBuffer);
+    heap_free(receiveBuffer);
+    *text = oldText;
+    return ret;
+}
+
+static LRESULT PAGER_Notify(PAGER_INFO *infoPtr, NMHDR *hdr)
+{
+    if (infoPtr->bUnicode) return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
+
+    switch (hdr->code)
+    {
+    /* Toolbar */
+    case TBN_GETBUTTONINFOW:
+    {
+        NMTOOLBARW *nmtb = (NMTOOLBARW *)hdr;
+        return PAGER_SendConvertedNotify(infoPtr, hdr, &nmtb->pszText, &nmtb->cchText,
+                                         SET_NULL_EMPTY | TO_ANSI | FROM_ANSI);
+    }
+    case TBN_GETINFOTIPW:
+    {
+        NMTBGETINFOTIPW *nmtbgit = (NMTBGETINFOTIPW *)hdr;
+        return PAGER_SendConvertedNotify(infoPtr, hdr, &nmtbgit->pszText, &nmtbgit->cchTextMax, FROM_ANSI);
+    }
+    }
+    /* 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);
+}
+
 static LRESULT WINAPI
 PAGER_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
@@ -1115,6 +1209,8 @@ PAGER_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
             return PAGER_NotifyFormat (infoPtr, lParam);
 
         case WM_NOTIFY:
+            return PAGER_Notify (infoPtr, (NMHDR *)lParam);
+
         case WM_COMMAND:
             return SendMessageW (infoPtr->hwndNotify, uMsg, wParam, lParam);
 
diff --git a/dlls/comctl32/tests/pager.c b/dlls/comctl32/tests/pager.c
index a1f6683a57..46f2eb0acb 100644
--- a/dlls/comctl32/tests/pager.c
+++ b/dlls/comctl32/tests/pager.c
@@ -30,10 +30,91 @@
 static HWND parent_wnd, child1_wnd, child2_wnd;
 static INT notify_format;
 static BOOL notify_query_received;
+static WCHAR test_w[] = {'t', 'e', 's', 't', 0};
+static CHAR test_a[] = {'t', 'e', 's', 't', 0};
+static WCHAR t_w[] = {'t', 0};
+static CHAR large_a[] = "You should have received a copy of the GNU Lesser General Public License along with this ...";
+static WCHAR buffer[64];
+static WCHAR buffer2[64];
+
+/* Text field conversion behavior flags for PAGER_SendConvertedNotify() */
+typedef enum
+{
+    /* Convert ANSI text from parent back to Unicode for pager */
+    FROM_ANSI = 0x01,
+    /* Convert Unicode text to ANSI for parent before sending. If not set, do nothing */
+    TO_ANSI = 0x02,
+    /* Send empty text to parent if text is NULL, original text pointer still remain NULL */
+    SET_NULL_EMPTY = 0x04
+} ConversionFlag;
+
+static struct notify_test_data
+{
+    UINT unicode;
+    UINT ansi;
+    UINT_PTR id_from;
+    HWND hwnd_from;
+    INT text_size;
+    /* Whether parent receive notification */
+    BOOL received;
+    UINT sub_test_id;
+    /* Text field conversion behavior flags */
+    ConversionFlag flags;
+} notify_test_data;
 
 #define CHILD1_ID 1
 #define CHILD2_ID 2
 
+#define expect_eq_int(actual, expected)                                                                  \
+    do                                                                                                   \
+    {                                                                                                    \
+        ok((actual) == (expected), "Code:0x%08x Subtest:0x%08x Expect " #actual " 0x%08x, got 0x%08x\n", \
+           notify_test_data.unicode, notify_test_data.sub_test_id, (expected), (actual));                \
+    } while (0)
+
+#define expect_eq_long(actual, expected)                                                                   \
+    do                                                                                                     \
+    {                                                                                                      \
+        ok((actual) == (expected), "Code:0x%08x Subtest:0x%08x Expect " #actual " 0x%08lx, got 0x%08lx\n", \
+           notify_test_data.unicode, notify_test_data.sub_test_id, (expected), (actual));                  \
+    } while (0)
+
+#define expect_eq_pointer(actual, expected)                                                      \
+    do                                                                                           \
+    {                                                                                            \
+        ok((actual) == (expected), "Code:0x%08x Subtest:0x%08x Expect " #actual " %p, got %p\n", \
+           notify_test_data.unicode, notify_test_data.sub_test_id, (expected), (actual));        \
+    } while (0)
+
+#define expect_eq_text_a(actual, expected)                                                                \
+    do                                                                                                    \
+    {                                                                                                     \
+        ok(!lstrcmpA((actual), (expected)), "Code:0x%08x Subtest:0x%08x Expect " #actual " %s, got %s\n", \
+           notify_test_data.unicode, notify_test_data.sub_test_id, (expected), (actual));                 \
+    } while (0)
+
+#define expect_eq_text_w(actual, expected)                                                                \
+    do                                                                                                    \
+    {                                                                                                     \
+        ok(!lstrcmpW((actual), (expected)), "Code:0x%08x Subtest:0x%08x Expect " #actual " %s, got %s\n", \
+           notify_test_data.unicode, notify_test_data.sub_test_id, wine_dbgstr_w((expected)),             \
+           wine_dbgstr_w((actual)));                                                                      \
+    } while (0)
+
+#define expect_text_empty(actual)                                                             \
+    do                                                                                        \
+    {                                                                                         \
+        ok((actual) && !(actual)[0], "Code:0x%08x Subtest:0x%08x Expect " #actual " empty\n", \
+           notify_test_data.unicode, notify_test_data.sub_test_id);                           \
+    } while (0)
+
+#define expect_null(actual)                                                                                     \
+    do                                                                                                          \
+    {                                                                                                           \
+        ok(!(actual), "Code:0x%08x Subtest:0x%08x Expect " #actual " NULL, got %p\n", notify_test_data.unicode, \
+           notify_test_data.sub_test_id, (actual));                                                             \
+    } while (0)
+
 static BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
 static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
 
@@ -419,6 +500,355 @@ static void test_wm_notifyformat(void)
     UnregisterClassW(class_w, GetModuleHandleW(NULL));
 }
 
+static void wm_notify_text_handler(CHAR **text, INT *textMax)
+{
+    expect_eq_int(*textMax, notify_test_data.text_size);
+    switch (notify_test_data.sub_test_id)
+    {
+    case 1:
+        if (notify_test_data.flags & SET_NULL_EMPTY)
+            expect_text_empty(*text);
+        else
+            expect_null(*text);
+        break;
+    case 2:
+    {
+        INT length = lstrlenA(*text);
+        ok(length == 0
+           || broken(length == 3) /* 2003 */
+           || broken(length == 1) /* <= Win7 */,
+           "Wrong text length\n");
+        break;
+    }
+    case 3:
+        if (notify_test_data.flags & TO_ANSI)
+        {
+            expect_eq_text_a(*text, test_a);
+            ok(*text != (CHAR *)buffer, "Expect using a new buffer\n");
+        }
+        else
+        {
+            expect_eq_text_w((WCHAR *)*text, test_w);
+            expect_eq_pointer(*text, (CHAR *)buffer);
+        }
+        break;
+    case 4:
+        expect_text_empty(*text);
+        memcpy(*text, test_a, sizeof(test_a));
+        break;
+    case 5:
+        expect_text_empty(*text);
+        *textMax = 1;
+        break;
+    case 6:
+        expect_text_empty(*text);
+        *text = test_a;
+        break;
+    case 7:
+        *text = test_a;
+        break;
+    case 8:
+        expect_text_empty(*text);
+        *text = large_a;
+        break;
+    }
+}
+
+static LRESULT WINAPI test_notify_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    static const WCHAR test[] = {'t', 'e', 's', 't', 0};
+    switch (message)
+    {
+    case WM_NOTIFY:
+    {
+        NMHDR *hdr = (NMHDR *)lParam;
+
+        /* Not notifications we want to test */
+        if (!notify_test_data.unicode) break;
+        ok(!notify_test_data.received, "Extra notification received\n");
+
+        expect_eq_long(wParam, notify_test_data.id_from);
+        expect_eq_int(hdr->code, notify_test_data.ansi);
+        expect_eq_long(hdr->idFrom, notify_test_data.id_from);
+        expect_eq_pointer(hdr->hwndFrom, notify_test_data.hwnd_from);
+
+        if (hdr->code != notify_test_data.ansi)
+        {
+            skip("Notification code mismatch, skipping lParam check\n");
+            return 0;
+        }
+        switch (hdr->code)
+        {
+        /* Toolbar */
+        /* No conversion for TBN_SAVE and TBN_RESTORE */
+        case TBN_SAVE:
+        {
+            NMTBSAVE *nmtbs = (NMTBSAVE *)hdr;
+            switch (notify_test_data.sub_test_id)
+            {
+            case 0:
+                expect_eq_text_w((WCHAR *)nmtbs->tbButton.iString, test_w);
+                break;
+            case 1:
+                nmtbs->tbButton.iString = (INT_PTR)test_a;
+                break;
+            }
+            break;
+        }
+        case TBN_RESTORE:
+        {
+            NMTBRESTORE *nmtbr = (NMTBRESTORE *)hdr;
+            switch (notify_test_data.sub_test_id)
+            {
+            case 0:
+                expect_eq_text_w((WCHAR *)nmtbr->tbButton.iString, test_w);
+                break;
+            case 1:
+                nmtbr->tbButton.iString = (INT_PTR)test_a;
+                break;
+            }
+            break;
+        }
+        case TBN_GETBUTTONINFOA:
+        {
+            NMTOOLBARA *nmtb = (NMTOOLBARA *)hdr;
+            wm_notify_text_handler(&nmtb->pszText, &nmtb->cchText);
+            break;
+        }
+        /* TBN_GETDISPINFOW doesn't get converted to TBN_GETDISPINFOA */
+        case TBN_GETDISPINFOW:
+        {
+            NMTBDISPINFOW *nmtbdi = (NMTBDISPINFOW *)hdr;
+            expect_eq_text_w(nmtbdi->pszText, test_w);
+            expect_eq_int(nmtbdi->cchText, ARRAY_SIZE(buffer));
+            memcpy(nmtbdi->pszText, test_a, sizeof(test_a));
+            break;
+        }
+        case TBN_GETINFOTIPA:
+        {
+            NMTBGETINFOTIPA *nmtbgit = (NMTBGETINFOTIPA *)hdr;
+            wm_notify_text_handler(&nmtbgit->pszText, &nmtbgit->cchTextMax);
+            break;
+        }
+        default:
+            ok(0, "Unexpected message 0x%08x\n", hdr->code);
+        }
+        notify_test_data.received = TRUE;
+        ok(!lstrcmpA(test_a, "test"), "test_a got modified\n");
+        ok(!lstrcmpW(test_w, test), "test_w got modified\n");
+        return 0;
+    }
+    case WM_NOTIFYFORMAT:
+        if (lParam == NF_QUERY) return NFR_ANSI;
+        break;
+    }
+    return DefWindowProcA(hwnd, message, wParam, lParam);
+}
+
+static BOOL register_test_notify_class(void)
+{
+    WNDCLASSA cls = {0};
+
+    cls.lpfnWndProc = test_notify_proc;
+    cls.hInstance = GetModuleHandleA(NULL);
+    cls.lpszClassName = "Pager notify class";
+    return RegisterClassA(&cls);
+}
+
+static void send_notify_(HWND pager, UINT unicode, UINT ansi, LPARAM lParam, BOOL code_change, BOOL received)
+{
+    NMHDR *hdr = (NMHDR *)lParam;
+
+    notify_test_data.unicode = unicode;
+    notify_test_data.id_from = 1;
+    notify_test_data.hwnd_from = child1_wnd;
+    notify_test_data.ansi = ansi;
+    notify_test_data.received = FALSE;
+
+    hdr->code = unicode;
+    hdr->idFrom = 1;
+    hdr->hwndFrom = child1_wnd;
+
+    SendMessageW(pager, WM_NOTIFY, hdr->idFrom, lParam);
+    expect_eq_int(notify_test_data.received, received);
+    expect_eq_int(hdr->code, code_change ? notify_test_data.ansi : notify_test_data.unicode);
+}
+
+#define send_notify(a, b, c, d, e) send_notify_(pager, a, b, c, d, e)
+
+/* Send notify to test text field conversion. In parent proc wm_notify_text_handler() handles these messages */
+static void test_wm_notify_text_helper_(HWND pager, void *ptr, size_t size, WCHAR **text, INT *textMax,
+                                        UINT code_unicode, UINT code_ansi, ConversionFlag flags)
+{
+    notify_test_data.flags = flags;
+
+    /* NULL text */
+    notify_test_data.sub_test_id = 1;
+    memset(ptr, 0, size);
+    *textMax = ARRAY_SIZE(buffer);
+    notify_test_data.text_size = *textMax;
+    send_notify(code_unicode, code_ansi, (LPARAM)ptr, TRUE, TRUE);
+    expect_null(*text);
+    expect_eq_int(*textMax, notify_test_data.text_size);
+
+    /* Zero text max size */
+    notify_test_data.sub_test_id = 2;
+    memset(ptr, 0, size);
+    memset(buffer, 0, sizeof(buffer));
+    *text = buffer;
+    notify_test_data.text_size = *textMax;
+    send_notify(code_unicode, code_ansi, (LPARAM)ptr, TRUE, TRUE);
+    /* Got *text null on Windows <= Win7 */
+    ok(broken(!*text) || (!lstrlenW(*text) && *text == buffer), "Wrong *text\n");
+    expect_eq_int(*textMax, notify_test_data.text_size);
+
+    /* Valid notification */
+    notify_test_data.sub_test_id = 3;
+    memset(ptr, 0, size);
+    memcpy(buffer, test_w, sizeof(test_w));
+    *text = buffer;
+    *textMax = ARRAY_SIZE(buffer);
+    notify_test_data.text_size = *textMax;
+    send_notify(code_unicode, code_ansi, (LPARAM)ptr, TRUE, TRUE);
+    if (!(flags & TO_ANSI) && flags & FROM_ANSI)
+        expect_eq_text_w(*text, t_w);
+    else
+        expect_eq_text_w(*text, test_w);
+    expect_eq_pointer(*text, buffer);
+    expect_eq_int(*textMax, notify_test_data.text_size);
+
+    /* Valid notification. Parent write to buffer */
+    notify_test_data.sub_test_id = 4;
+    memset(ptr, 0, size);
+    memset(buffer, 0, sizeof(buffer));
+    *text = buffer;
+    *textMax = ARRAY_SIZE(buffer);
+    notify_test_data.text_size = *textMax;
+    send_notify(code_unicode, code_ansi, (LPARAM)ptr, TRUE, TRUE);
+    expect_eq_text_w(*text, test_w);
+    expect_eq_pointer(*text, buffer);
+    expect_eq_int(*textMax, notify_test_data.text_size);
+
+    /* Valid notification. Parent set buffer size to one */
+    notify_test_data.sub_test_id = 5;
+    memset(ptr, 0, size);
+    memset(buffer, 0, sizeof(buffer));
+    *text = buffer;
+    *textMax = ARRAY_SIZE(buffer);
+    notify_test_data.text_size = *textMax;
+    send_notify(code_unicode, code_ansi, (LPARAM)ptr, TRUE, TRUE);
+    expect_eq_pointer(*text, buffer);
+    expect_eq_int(*textMax, 1);
+
+    /* Valid notification. Parent replace buffer */
+    notify_test_data.sub_test_id = 6;
+    memset(ptr, 0, size);
+    memset(buffer, 0, sizeof(buffer));
+    *text = buffer;
+    *textMax = ARRAY_SIZE(buffer);
+    notify_test_data.text_size = *textMax;
+    send_notify(code_unicode, code_ansi, (LPARAM)ptr, TRUE, TRUE);
+    expect_eq_text_w(*text, test_w);
+    expect_eq_pointer(*text, buffer);
+    expect_eq_int(*textMax, notify_test_data.text_size);
+
+    /* NULL text. Parent replace buffer */
+    notify_test_data.sub_test_id = 7;
+    memset(ptr, 0, size);
+    *textMax = ARRAY_SIZE(buffer);
+    notify_test_data.text_size = *textMax;
+    send_notify(code_unicode, code_ansi, (LPARAM)ptr, TRUE, TRUE);
+    expect_null(*text);
+    expect_eq_int(*textMax, notify_test_data.text_size);
+
+    /* Valid notification. Parent replace buffer with a pointer pointing to a string larger than old buffer can store */
+    notify_test_data.sub_test_id = 8;
+    memset(ptr, 0, size);
+    memset(buffer, 0, sizeof(buffer));
+    memset(buffer2, 0, sizeof(buffer2));
+    *text = buffer;
+    *textMax = ARRAY_SIZE(buffer);
+    notify_test_data.text_size = *textMax;
+    send_notify(code_unicode, code_ansi, (LPARAM)ptr, TRUE, TRUE);
+    MultiByteToWideChar(CP_ACP, 0, large_a, -1, buffer2, ARRAY_SIZE(buffer2));
+    ok(!memcmp(*text, buffer2, sizeof(buffer2)), "Expect memory content to be the same\n");
+    expect_eq_pointer(*text, buffer);
+    expect_eq_int(*textMax, notify_test_data.text_size);
+}
+
+#define test_wm_notify_text_helper(a, b, c, d, e, f, g) test_wm_notify_text_helper_(pager, a, b, c, d, e, f, g)
+
+static void test_wm_notify_toolbar(HWND pager)
+{
+    NMTBRESTORE nmtbr;
+    NMTBSAVE nmtbs;
+    NMTOOLBARW nmtb;
+    NMTBDISPINFOW nmtbdi;
+    NMTBGETINFOTIPW nmtbgit;
+
+    /* No conversion for TBN_SAVE */
+    notify_test_data.sub_test_id = 0;
+    memset(&nmtbs, 0, sizeof(nmtbs));
+    nmtbs.tbButton.iString = (INT_PTR)test_w;
+    send_notify(TBN_SAVE, TBN_SAVE, (LPARAM)&nmtbs, TRUE, TRUE);
+    expect_eq_text_w((WCHAR *)nmtbs.tbButton.iString, test_w);
+
+    notify_test_data.sub_test_id = 1;
+    memset(&nmtbs, 0, sizeof(nmtbs));
+    nmtbs.tbButton.iString = (INT_PTR)test_w;
+    send_notify(TBN_SAVE, TBN_SAVE, (LPARAM)&nmtbs, TRUE, TRUE);
+    expect_eq_text_a((CHAR *)nmtbs.tbButton.iString, test_a);
+
+    /* No conversion for TBN_RESTORE */
+    notify_test_data.sub_test_id = 0;
+    memset(&nmtbr, 0, sizeof(nmtbr));
+    nmtbr.tbButton.iString = (INT_PTR)test_w;
+    send_notify(TBN_RESTORE, TBN_RESTORE, (LPARAM)&nmtbr, TRUE, TRUE);
+    expect_eq_text_w((WCHAR *)nmtbr.tbButton.iString, test_w);
+
+    notify_test_data.sub_test_id = 1;
+    memset(&nmtbr, 0, sizeof(nmtbr));
+    nmtbr.tbButton.iString = (INT_PTR)test_w;
+    send_notify(TBN_RESTORE, TBN_RESTORE, (LPARAM)&nmtbr, TRUE, TRUE);
+    expect_eq_text_a((CHAR *)nmtbr.tbButton.iString, test_a);
+
+    /* TBN_GETDISPINFOW doesn't get unconverted */
+    memset(&nmtbdi, 0, sizeof(nmtbdi));
+    memcpy(buffer, test_w, sizeof(test_w));
+    nmtbdi.dwMask = TBNF_TEXT;
+    nmtbdi.pszText = buffer;
+    nmtbdi.cchText = ARRAY_SIZE(buffer);
+    notify_test_data.text_size = nmtbdi.cchText;
+    send_notify(TBN_GETDISPINFOW, TBN_GETDISPINFOW, (LPARAM)&nmtbdi, TRUE, TRUE);
+    expect_eq_text_a((CHAR *)nmtbdi.pszText, test_a);
+
+    test_wm_notify_text_helper(&nmtb, sizeof(nmtb), &nmtb.pszText, &nmtb.cchText, TBN_GETBUTTONINFOW,
+                               TBN_GETBUTTONINFOA, SET_NULL_EMPTY | TO_ANSI);
+    test_wm_notify_text_helper(&nmtbgit, sizeof(nmtbgit), &nmtbgit.pszText, &nmtbgit.cchTextMax, TBN_GETINFOTIPW,
+                               TBN_GETINFOTIPA, FROM_ANSI);
+}
+
+static void test_wm_notify(void)
+{
+    static const CHAR *class = "Pager notify class";
+    HWND parent, pager;
+
+    ok(register_test_notify_class(), "Register test class failed, error 0x%08x\n", GetLastError());
+
+    parent = CreateWindowA(class, "parent", WS_OVERLAPPED, 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), 0);
+    ok(parent != NULL, "CreateWindow failed\n");
+    pager = CreateWindowA(WC_PAGESCROLLERA, "pager", WS_CHILD, 0, 0, 100, 100, parent, 0, GetModuleHandleA(0), 0);
+    ok(pager != NULL, "CreateWindow failed\n");
+    child1_wnd = CreateWindowA(class, "child", WS_CHILD, 0, 0, 100, 100, pager, (HMENU)1, GetModuleHandleA(0), 0);
+    ok(child1_wnd != NULL, "CreateWindow failed\n");
+    SendMessageW(pager, PGM_SETCHILD, 0, (LPARAM)child1_wnd);
+
+    test_wm_notify_toolbar(pager);
+
+    DestroyWindow(parent);
+    UnregisterClassA(class, GetModuleHandleA(NULL));
+}
+
 static void init_functions(void)
 {
     HMODULE mod = LoadLibraryA("comctl32.dll");
@@ -447,6 +877,7 @@ START_TEST(pager)
 
     test_pager();
     test_wm_notifyformat();
+    test_wm_notify();
 
     DestroyWindow(parent_wnd);
 }
-- 
2.18.0





More information about the wine-devel mailing list