Signed-off-by: Zhiyi Zhang <zzhang(a)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