mfreadwrite/reader: Add missing allocation check (Coverity).
[wine/zf.git] / dlls / comctl32 / tests / tooltips.c
blob639d51f7c2806e7583fc1a7b02bad7956cc2f781
1 /*
2 * Copyright 2005 Dmitry Timoshkov
3 * Copyright 2008 Jason Edmeades
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <windows.h>
21 #include <commctrl.h>
23 #include "resources.h"
25 #include "wine/test.h"
27 #include "v6util.h"
28 #include "msg.h"
30 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
32 enum seq_index
34 PARENT_SEQ_INDEX = 0,
35 NUM_MSG_SEQUENCES
38 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
40 static void test_create_tooltip(BOOL is_v6)
42 HWND parent, hwnd;
43 DWORD style, exp_style;
45 parent = CreateWindowExA(0, "static", NULL, WS_POPUP,
46 0, 0, 0, 0,
47 NULL, NULL, NULL, 0);
48 ok(parent != NULL, "failed to create parent wnd\n");
50 hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0x7fffffff | WS_POPUP,
51 10, 10, 300, 100,
52 parent, NULL, NULL, 0);
53 ok(hwnd != NULL, "failed to create tooltip wnd\n");
55 style = GetWindowLongA(hwnd, GWL_STYLE);
56 exp_style = 0x7fffffff | WS_POPUP;
57 exp_style &= ~(WS_CHILD | WS_MAXIMIZE | WS_BORDER | WS_DLGFRAME);
58 ok(style == exp_style || broken(style == (exp_style | WS_BORDER)), /* nt4 */
59 "wrong style %08x/%08x\n", style, exp_style);
61 DestroyWindow(hwnd);
63 hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
64 10, 10, 300, 100,
65 parent, NULL, NULL, 0);
66 ok(hwnd != NULL, "failed to create tooltip wnd\n");
68 style = GetWindowLongA(hwnd, GWL_STYLE);
69 exp_style = WS_POPUP | WS_CLIPSIBLINGS;
70 if (!is_v6)
71 exp_style |= WS_BORDER;
72 todo_wine_if(is_v6)
73 ok(style == exp_style || broken(style == (exp_style | WS_BORDER)) /* XP */,
74 "Unexpected window style %#x.\n", style);
76 DestroyWindow(hwnd);
78 DestroyWindow(parent);
81 /* try to make sure pending X events have been processed before continuing */
82 static void flush_events(int waitTime)
84 MSG msg;
85 int diff = waitTime;
86 DWORD time = GetTickCount() + waitTime;
88 while (diff > 0)
90 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min(100,diff), QS_ALLEVENTS) == WAIT_TIMEOUT) break;
91 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
92 diff = time - GetTickCount();
96 static int CD_Stages;
97 static LRESULT CD_Result;
98 static HWND g_hwnd;
100 #define TEST_CDDS_PREPAINT 0x00000001
101 #define TEST_CDDS_POSTPAINT 0x00000002
102 #define TEST_CDDS_PREERASE 0x00000004
103 #define TEST_CDDS_POSTERASE 0x00000008
104 #define TEST_CDDS_ITEMPREPAINT 0x00000010
105 #define TEST_CDDS_ITEMPOSTPAINT 0x00000020
106 #define TEST_CDDS_ITEMPREERASE 0x00000040
107 #define TEST_CDDS_ITEMPOSTERASE 0x00000080
108 #define TEST_CDDS_SUBITEM 0x00000100
110 static LRESULT CALLBACK custom_draw_wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
112 switch(msg) {
114 case WM_DESTROY:
115 PostQuitMessage(0);
116 break;
118 case WM_NOTIFY:
119 if (((NMHDR *)lParam)->code == NM_CUSTOMDRAW) {
120 NMTTCUSTOMDRAW *ttcd = (NMTTCUSTOMDRAW*) lParam;
121 ok(ttcd->nmcd.hdr.hwndFrom == g_hwnd, "Unexpected hwnd source %p (%p)\n",
122 ttcd->nmcd.hdr.hwndFrom, g_hwnd);
123 ok(ttcd->nmcd.hdr.idFrom == 0x1234ABCD, "Unexpected id %x\n", (int)ttcd->nmcd.hdr.idFrom);
125 switch (ttcd->nmcd.dwDrawStage) {
126 case CDDS_PREPAINT : CD_Stages |= TEST_CDDS_PREPAINT; break;
127 case CDDS_POSTPAINT : CD_Stages |= TEST_CDDS_POSTPAINT; break;
128 case CDDS_PREERASE : CD_Stages |= TEST_CDDS_PREERASE; break;
129 case CDDS_POSTERASE : CD_Stages |= TEST_CDDS_POSTERASE; break;
130 case CDDS_ITEMPREPAINT : CD_Stages |= TEST_CDDS_ITEMPREPAINT; break;
131 case CDDS_ITEMPOSTPAINT: CD_Stages |= TEST_CDDS_ITEMPOSTPAINT; break;
132 case CDDS_ITEMPREERASE : CD_Stages |= TEST_CDDS_ITEMPREERASE; break;
133 case CDDS_ITEMPOSTERASE: CD_Stages |= TEST_CDDS_ITEMPOSTERASE; break;
134 case CDDS_SUBITEM : CD_Stages |= TEST_CDDS_SUBITEM; break;
135 default: CD_Stages = -1;
138 if (ttcd->nmcd.dwDrawStage == CDDS_PREPAINT) return CD_Result;
140 /* drop through */
142 default:
143 return DefWindowProcA(hWnd, msg, wParam, lParam);
146 return 0L;
149 static void test_customdraw(void) {
150 static struct {
151 LRESULT FirstReturnValue;
152 int ExpectedCalls;
153 } expectedResults[] = {
154 /* Valid notification responses */
155 {CDRF_DODEFAULT, TEST_CDDS_PREPAINT},
156 {CDRF_SKIPDEFAULT, TEST_CDDS_PREPAINT},
157 {CDRF_NOTIFYPOSTPAINT, TEST_CDDS_PREPAINT | TEST_CDDS_POSTPAINT},
159 /* Invalid notification responses */
160 {CDRF_NOTIFYITEMDRAW, TEST_CDDS_PREPAINT},
161 {CDRF_NOTIFYPOSTERASE, TEST_CDDS_PREPAINT},
162 {CDRF_NEWFONT, TEST_CDDS_PREPAINT}
165 DWORD iterationNumber;
166 WNDCLASSA wc;
167 POINT orig_pos;
168 LRESULT ret;
170 /* Create a class to use the custom draw wndproc */
171 wc.style = CS_HREDRAW | CS_VREDRAW;
172 wc.cbClsExtra = 0;
173 wc.cbWndExtra = 0;
174 wc.hInstance = GetModuleHandleA(NULL);
175 wc.hIcon = NULL;
176 wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
177 wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
178 wc.lpszMenuName = NULL;
179 wc.lpszClassName = "CustomDrawClass";
180 wc.lpfnWndProc = custom_draw_wnd_proc;
181 RegisterClassA(&wc);
183 GetCursorPos(&orig_pos);
185 for (iterationNumber = 0;
186 iterationNumber < ARRAY_SIZE(expectedResults);
187 iterationNumber++) {
189 HWND parent, hwndTip;
190 RECT rect;
191 TTTOOLINFOA toolInfo = { 0 };
193 /* Create a main window */
194 parent = CreateWindowExA(0, "CustomDrawClass", NULL,
195 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
196 WS_MAXIMIZEBOX | WS_VISIBLE,
197 50, 50,
198 300, 300,
199 NULL, NULL, NULL, 0);
200 ok(parent != NULL, "%d: Creation of main window failed\n", iterationNumber);
202 /* Make it show */
203 ShowWindow(parent, SW_SHOWNORMAL);
204 flush_events(100);
206 /* Create Tooltip */
207 hwndTip = CreateWindowExA(WS_EX_TOPMOST, TOOLTIPS_CLASSA,
208 NULL, TTS_NOPREFIX | TTS_ALWAYSTIP,
209 CW_USEDEFAULT, CW_USEDEFAULT,
210 CW_USEDEFAULT, CW_USEDEFAULT,
211 parent, NULL, GetModuleHandleA(NULL), 0);
212 ok(hwndTip != NULL, "%d: Creation of tooltip window failed\n", iterationNumber);
214 /* Set up parms for the wndproc to handle */
215 CD_Stages = 0;
216 CD_Result = expectedResults[iterationNumber].FirstReturnValue;
217 g_hwnd = hwndTip;
219 /* Make it topmost, as per the MSDN */
220 SetWindowPos(hwndTip, HWND_TOPMOST, 0, 0, 0, 0,
221 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
223 /* Create a tool */
224 toolInfo.cbSize = TTTOOLINFOA_V1_SIZE;
225 toolInfo.hwnd = parent;
226 toolInfo.hinst = GetModuleHandleA(NULL);
227 toolInfo.uFlags = TTF_SUBCLASS;
228 toolInfo.uId = 0x1234ABCD;
229 toolInfo.lpszText = (LPSTR)"This is a test tooltip";
230 toolInfo.lParam = 0xdeadbeef;
231 GetClientRect (parent, &toolInfo.rect);
232 ret = SendMessageA(hwndTip, TTM_ADDTOOLA, 0, (LPARAM)&toolInfo);
233 ok(ret, "%d: Failed to add the tool.\n", iterationNumber);
235 /* Make tooltip appear quickly */
236 SendMessageA(hwndTip, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1,0));
238 /* Put cursor inside window, tooltip will appear immediately */
239 GetWindowRect( parent, &rect );
240 SetCursorPos( (rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2 );
241 flush_events(200);
243 if (CD_Stages)
245 /* Check CustomDraw results */
246 ok(CD_Stages == expectedResults[iterationNumber].ExpectedCalls ||
247 broken(CD_Stages == (expectedResults[iterationNumber].ExpectedCalls & ~TEST_CDDS_POSTPAINT)), /* nt4 */
248 "%d: CustomDraw stages %x, expected %x\n", iterationNumber, CD_Stages,
249 expectedResults[iterationNumber].ExpectedCalls);
252 ret = SendMessageA(hwndTip, TTM_GETCURRENTTOOLA, 0, 0);
253 ok(ret, "%d: Failed to get current tool %#lx.\n", iterationNumber, ret);
255 memset(&toolInfo, 0xcc, sizeof(toolInfo));
256 toolInfo.cbSize = sizeof(toolInfo);
257 toolInfo.lpszText = NULL;
258 toolInfo.lpReserved = (void *)0xdeadbeef;
259 SendMessageA(hwndTip, TTM_GETCURRENTTOOLA, 0, (LPARAM)&toolInfo);
260 ok(toolInfo.hwnd == parent, "%d: Unexpected hwnd %p.\n", iterationNumber, toolInfo.hwnd);
261 ok(toolInfo.hinst == GetModuleHandleA(NULL), "%d: Unexpected hinst %p.\n", iterationNumber, toolInfo.hinst);
262 ok(toolInfo.uId == 0x1234abcd, "%d: Unexpected uId %lx.\n", iterationNumber, toolInfo.uId);
263 ok(toolInfo.lParam == 0, "%d: Unexpected lParam %lx.\n", iterationNumber, toolInfo.lParam);
264 ok(toolInfo.lpReserved == (void *)0xdeadbeef, "%d: Unexpected lpReserved %p.\n", iterationNumber, toolInfo.lpReserved);
266 /* Clean up */
267 DestroyWindow(hwndTip);
268 DestroyWindow(parent);
271 SetCursorPos(orig_pos.x, orig_pos.y);
274 static const CHAR testcallbackA[] = "callback";
276 static RECT g_ttip_rect;
277 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
279 static LONG defwndproc_counter = 0;
280 struct message msg;
281 LRESULT ret;
283 if (message == WM_NOTIFY && lParam)
285 NMTTDISPINFOA *ttnmdi = (NMTTDISPINFOA*)lParam;
286 NMHDR *hdr = (NMHDR *)lParam;
287 RECT rect;
289 if (hdr->code != NM_CUSTOMDRAW)
291 msg.message = message;
292 msg.flags = sent|wparam|lparam;
293 if (defwndproc_counter) msg.flags |= defwinproc;
294 msg.wParam = wParam;
295 msg.lParam = lParam;
296 msg.id = hdr->code;
297 add_message(sequences, PARENT_SEQ_INDEX, &msg);
300 switch (hdr->code)
302 case TTN_GETDISPINFOA:
303 lstrcpyA(ttnmdi->lpszText, testcallbackA);
304 break;
305 case TTN_SHOW:
306 GetWindowRect(hdr->hwndFrom, &rect);
307 ok(!EqualRect(&g_ttip_rect, &rect), "Unexpected window rectangle.\n");
308 break;
312 defwndproc_counter++;
313 if (IsWindowUnicode(hwnd))
314 ret = DefWindowProcW(hwnd, message, wParam, lParam);
315 else
316 ret = DefWindowProcA(hwnd, message, wParam, lParam);
317 defwndproc_counter--;
319 return ret;
322 static void register_parent_wnd_class(void)
324 WNDCLASSA cls;
325 BOOL ret;
327 cls.style = 0;
328 cls.lpfnWndProc = parent_wnd_proc;
329 cls.cbClsExtra = 0;
330 cls.cbWndExtra = 0;
331 cls.hInstance = GetModuleHandleA(NULL);
332 cls.hIcon = 0;
333 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
334 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
335 cls.lpszMenuName = NULL;
336 cls.lpszClassName = "Tooltips test parent class";
337 ret = RegisterClassA(&cls);
338 ok(ret, "Failed to register test parent class.\n");
341 static HWND create_parent_window(void)
343 return CreateWindowExA(0, "Tooltips test parent class",
344 "Tooltips test parent window",
345 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
346 WS_MAXIMIZEBOX | WS_VISIBLE,
347 0, 0, 100, 100,
348 GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
351 static void test_gettext(void)
353 static const CHAR testtip2A[] = "testtip\ttest2";
354 static const CHAR testtipA[] = "testtip";
355 HWND hwnd, notify;
356 TTTOOLINFOA toolinfoA;
357 TTTOOLINFOW toolinfoW;
358 LRESULT r;
359 CHAR bufA[16] = "";
360 WCHAR bufW[10] = { 0 };
361 DWORD length, style;
363 notify = create_parent_window();
364 ok(notify != NULL, "Expected notification window to be created\n");
366 /* For bug 14790 - lpszText is NULL */
367 hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
368 10, 10, 300, 100,
369 NULL, NULL, NULL, 0);
370 ok(hwnd != NULL, "failed to create tooltip wnd\n");
372 /* use sizeof(TTTOOLINFOA) instead of TTTOOLINFOA_V1_SIZE so that adding it fails on Win9x */
373 /* otherwise it crashes on the NULL lpszText */
374 toolinfoA.cbSize = sizeof(TTTOOLINFOA);
375 toolinfoA.hwnd = NULL;
376 toolinfoA.hinst = GetModuleHandleA(NULL);
377 toolinfoA.uFlags = 0;
378 toolinfoA.uId = 0x1234ABCD;
379 toolinfoA.lpszText = NULL;
380 toolinfoA.lParam = 0xdeadbeef;
381 GetClientRect(hwnd, &toolinfoA.rect);
382 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
383 ok(r, "got %ld\n", r);
385 toolinfoA.hwnd = NULL;
386 toolinfoA.uId = 0x1234abcd;
387 toolinfoA.lpszText = bufA;
388 r = SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
389 ok(!r, "got %ld\n", r);
390 ok(!*toolinfoA.lpszText, "lpszText should be empty, got %s\n", toolinfoA.lpszText);
392 toolinfoA.lpszText = bufA;
393 r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
394 todo_wine
395 ok(!r, "got %ld\n", r);
396 ok(toolinfoA.lpszText == NULL, "expected NULL, got %p\n", toolinfoA.lpszText);
398 /* NULL hinst, valid resource id for text */
399 toolinfoA.cbSize = sizeof(TTTOOLINFOA);
400 toolinfoA.hwnd = NULL;
401 toolinfoA.hinst = NULL;
402 toolinfoA.uFlags = 0;
403 toolinfoA.uId = 0x1233abcd;
404 toolinfoA.lpszText = MAKEINTRESOURCEA(IDS_TBADD1);
405 toolinfoA.lParam = 0xdeadbeef;
406 GetClientRect(hwnd, &toolinfoA.rect);
407 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
408 ok(r, "failed to add a tool\n");
410 toolinfoA.hwnd = NULL;
411 toolinfoA.uId = 0x1233abcd;
412 toolinfoA.lpszText = bufA;
413 r = SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
414 ok(!r, "got %ld\n", r);
415 ok(!strcmp(toolinfoA.lpszText, "abc"), "got wrong text, %s\n", toolinfoA.lpszText);
417 toolinfoA.hinst = (HINSTANCE)0xdeadbee;
418 r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
419 todo_wine
420 ok(!r, "got %ld\n", r);
421 ok(toolinfoA.hinst == NULL, "expected NULL, got %p\n", toolinfoA.hinst);
423 r = SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&toolinfoA);
424 ok(!r, "got %ld\n", r);
426 /* add another tool with text */
427 toolinfoA.cbSize = sizeof(TTTOOLINFOA);
428 toolinfoA.hwnd = NULL;
429 toolinfoA.hinst = GetModuleHandleA(NULL);
430 toolinfoA.uFlags = 0;
431 toolinfoA.uId = 0x1235ABCD;
432 strcpy(bufA, testtipA);
433 toolinfoA.lpszText = bufA;
434 toolinfoA.lParam = 0xdeadbeef;
435 GetClientRect(hwnd, &toolinfoA.rect);
436 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
437 ok(r, "Adding the tool to the tooltip failed\n");
439 length = SendMessageA(hwnd, WM_GETTEXTLENGTH, 0, 0);
440 ok(length == 0, "Expected 0, got %d\n", length);
442 toolinfoA.hwnd = NULL;
443 toolinfoA.uId = 0x1235abcd;
444 toolinfoA.lpszText = bufA;
445 r = SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
446 ok(!r, "got %ld\n", r);
447 ok(!strcmp(toolinfoA.lpszText, testtipA), "expected %s, got %p\n", testtipA, toolinfoA.lpszText);
449 memset(bufA, 0x1f, sizeof(bufA));
450 toolinfoA.lpszText = bufA;
451 r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
452 todo_wine
453 ok(!r, "got %ld\n", r);
454 ok(!strcmp(toolinfoA.lpszText, testtipA), "expected %s, got %p\n", testtipA, toolinfoA.lpszText);
456 length = SendMessageA(hwnd, WM_GETTEXTLENGTH, 0, 0);
457 ok(length == 0, "Expected 0, got %d\n", length);
459 /* add another with callback text */
460 toolinfoA.cbSize = sizeof(TTTOOLINFOA);
461 toolinfoA.hwnd = notify;
462 toolinfoA.hinst = GetModuleHandleA(NULL);
463 toolinfoA.uFlags = 0;
464 toolinfoA.uId = 0x1236ABCD;
465 toolinfoA.lpszText = LPSTR_TEXTCALLBACKA;
466 toolinfoA.lParam = 0xdeadbeef;
467 GetClientRect(hwnd, &toolinfoA.rect);
468 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
469 ok(r, "Adding the tool to the tooltip failed\n");
471 toolinfoA.hwnd = notify;
472 toolinfoA.uId = 0x1236abcd;
473 toolinfoA.lpszText = bufA;
474 r = SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
475 ok(!r, "got %ld\n", r);
476 ok(!strcmp(toolinfoA.lpszText, testcallbackA), "lpszText should be an (%s) string\n", testcallbackA);
478 toolinfoA.lpszText = bufA;
479 r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
480 todo_wine
481 ok(!r, "got %ld\n", r);
482 ok(toolinfoA.lpszText == LPSTR_TEXTCALLBACKA, "expected LPSTR_TEXTCALLBACKA, got %p\n", toolinfoA.lpszText);
484 DestroyWindow(hwnd);
485 DestroyWindow(notify);
487 hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0,
488 10, 10, 300, 100,
489 NULL, NULL, NULL, 0);
490 ok(hwnd != NULL, "failed to create tooltip wnd\n");
492 toolinfoW.cbSize = TTTOOLINFOW_V2_SIZE + 1;
493 toolinfoW.hwnd = NULL;
494 toolinfoW.hinst = GetModuleHandleA(NULL);
495 toolinfoW.uFlags = 0;
496 toolinfoW.uId = 0x1234ABCD;
497 toolinfoW.lpszText = NULL;
498 toolinfoW.lParam = 0xdeadbeef;
499 GetClientRect(hwnd, &toolinfoW.rect);
500 r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&toolinfoW);
501 /* Wine currently checks for V3 structure size, which matches what V6 control does.
502 Older implementation was never updated to support lpReserved field. */
503 todo_wine
504 ok(!r, "Adding the tool to the tooltip succeeded!\n");
506 if (0) /* crashes on NT4 */
508 toolinfoW.hwnd = NULL;
509 toolinfoW.uId = 0x1234ABCD;
510 toolinfoW.lpszText = bufW;
511 SendMessageW(hwnd, TTM_GETTEXTW, 0, (LPARAM)&toolinfoW);
512 ok(toolinfoW.lpszText[0] == 0, "lpszText should be an empty string\n");
515 /* text with embedded tabs */
516 toolinfoA.cbSize = sizeof(TTTOOLINFOA);
517 toolinfoA.hwnd = NULL;
518 toolinfoA.hinst = GetModuleHandleA(NULL);
519 toolinfoA.uFlags = 0;
520 toolinfoA.uId = 0x1235abce;
521 strcpy(bufA, testtip2A);
522 toolinfoA.lpszText = bufA;
523 toolinfoA.lParam = 0xdeadbeef;
524 GetClientRect(hwnd, &toolinfoA.rect);
525 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
526 ok(r, "got %ld\n", r);
528 toolinfoA.hwnd = NULL;
529 toolinfoA.uId = 0x1235abce;
530 toolinfoA.lpszText = bufA;
531 r = SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
532 ok(!r, "got %ld\n", r);
533 ok(!strcmp(toolinfoA.lpszText, testtipA), "expected %s, got %s\n", testtipA, toolinfoA.lpszText);
535 /* enable TTS_NOPREFIX, original text is retained */
536 style = GetWindowLongA(hwnd, GWL_STYLE);
537 SetWindowLongA(hwnd, GWL_STYLE, style | TTS_NOPREFIX);
539 toolinfoA.hwnd = NULL;
540 toolinfoA.uId = 0x1235abce;
541 toolinfoA.lpszText = bufA;
542 r = SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
543 ok(!r, "got %ld\n", r);
544 ok(!strcmp(toolinfoA.lpszText, testtip2A), "expected %s, got %s\n", testtip2A, toolinfoA.lpszText);
546 DestroyWindow(hwnd);
549 static void test_ttm_gettoolinfo(void)
551 TTTOOLINFOA ti;
552 TTTOOLINFOW tiW;
553 HWND hwnd;
554 DWORD r;
556 hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0, 10, 10, 300, 100, NULL, NULL, NULL, 0);
557 ok(hwnd != NULL, "Failed to create tooltip control.\n");
559 ti.cbSize = TTTOOLINFOA_V2_SIZE;
560 ti.hwnd = NULL;
561 ti.hinst = GetModuleHandleA(NULL);
562 ti.uFlags = 0;
563 ti.uId = 0x1234ABCD;
564 ti.lpszText = NULL;
565 ti.lParam = 0x1abe11ed;
566 GetClientRect(hwnd, &ti.rect);
567 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
568 ok(r, "Adding the tool to the tooltip failed\n");
570 ti.cbSize = TTTOOLINFOA_V2_SIZE;
571 ti.lParam = 0xaaaaaaaa;
572 r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&ti);
573 ok(r, "Getting tooltip info failed\n");
574 ok(0x1abe11ed == ti.lParam ||
575 broken(0x1abe11ed != ti.lParam), /* comctl32 < 5.81 */
576 "Expected 0x1abe11ed, got %lx\n", ti.lParam);
578 tiW.cbSize = TTTOOLINFOW_V2_SIZE;
579 tiW.hwnd = NULL;
580 tiW.uId = 0x1234ABCD;
581 tiW.lParam = 0xaaaaaaaa;
582 tiW.lpszText = NULL;
583 r = SendMessageA(hwnd, TTM_GETTOOLINFOW, 0, (LPARAM)&tiW);
584 ok(r, "Getting tooltip info failed\n");
585 ok(0x1abe11ed == tiW.lParam ||
586 broken(0x1abe11ed != tiW.lParam), /* comctl32 < 5.81 */
587 "Expected 0x1abe11ed, got %lx\n", tiW.lParam);
589 ti.cbSize = TTTOOLINFOA_V2_SIZE;
590 ti.uId = 0x1234ABCD;
591 ti.lParam = 0x55555555;
592 SendMessageA(hwnd, TTM_SETTOOLINFOA, 0, (LPARAM)&ti);
594 ti.cbSize = TTTOOLINFOA_V2_SIZE;
595 ti.lParam = 0xdeadbeef;
596 r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&ti);
597 ok(r, "Getting tooltip info failed\n");
598 ok(0x55555555 == ti.lParam ||
599 broken(0x55555555 != ti.lParam), /* comctl32 < 5.81 */
600 "Expected 0x55555555, got %lx\n", ti.lParam);
602 DestroyWindow(hwnd);
604 /* 1. test size parameter validation rules (ansi messages) */
605 hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
606 10, 10, 300, 100,
607 NULL, NULL, NULL, 0);
609 ti.cbSize = TTTOOLINFOA_V1_SIZE - 1;
610 ti.hwnd = NULL;
611 ti.hinst = GetModuleHandleA(NULL);
612 ti.uFlags = 0;
613 ti.uId = 0x1234ABCD;
614 ti.lpszText = NULL;
615 ti.lParam = 0xdeadbeef;
616 GetClientRect(hwnd, &ti.rect);
617 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
618 ok(r, "Adding the tool to the tooltip failed\n");
619 r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
620 expect(1, r);
622 ti.cbSize = TTTOOLINFOA_V1_SIZE - 1;
623 ti.hwnd = NULL;
624 ti.uId = 0x1234ABCD;
625 SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti);
626 r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
627 expect(0, r);
629 ti.cbSize = TTTOOLINFOA_V2_SIZE - 1;
630 ti.hwnd = NULL;
631 ti.hinst = GetModuleHandleA(NULL);
632 ti.uFlags = 0;
633 ti.uId = 0x1234ABCD;
634 ti.lpszText = NULL;
635 ti.lParam = 0xdeadbeef;
636 GetClientRect(hwnd, &ti.rect);
637 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
638 ok(r, "Adding the tool to the tooltip failed\n");
639 r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
640 expect(1, r);
642 ti.cbSize = TTTOOLINFOA_V2_SIZE - 1;
643 ti.hwnd = NULL;
644 ti.uId = 0x1234ABCD;
645 SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti);
646 r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
647 expect(0, r);
649 ti.cbSize = TTTOOLINFOA_V2_SIZE + 1;
650 ti.hwnd = NULL;
651 ti.hinst = GetModuleHandleA(NULL);
652 ti.uFlags = 0;
653 ti.uId = 0x1234ABCD;
654 ti.lpszText = NULL;
655 ti.lParam = 0xdeadbeef;
656 GetClientRect(hwnd, &ti.rect);
657 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
658 ok(r, "Adding the tool to the tooltip failed\n");
659 r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
660 expect(1, r);
662 ti.cbSize = TTTOOLINFOA_V2_SIZE + 1;
663 ti.hwnd = NULL;
664 ti.uId = 0x1234ABCD;
665 SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti);
666 r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
667 expect(0, r);
669 DestroyWindow(hwnd);
671 /* 2. test size parameter validation rules (w-messages) */
672 hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0,
673 10, 10, 300, 100,
674 NULL, NULL, NULL, 0);
675 ok(hwnd != NULL, "Failed to create tooltip window.\n");
677 tiW.cbSize = TTTOOLINFOW_V1_SIZE - 1;
678 tiW.hwnd = NULL;
679 tiW.hinst = GetModuleHandleA(NULL);
680 tiW.uFlags = 0;
681 tiW.uId = 0x1234ABCD;
682 tiW.lpszText = NULL;
683 tiW.lParam = 0xdeadbeef;
684 GetClientRect(hwnd, &tiW.rect);
685 r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&tiW);
686 ok(r, "Adding the tool to the tooltip failed\n");
687 r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
688 expect(1, r);
690 tiW.cbSize = TTTOOLINFOW_V1_SIZE - 1;
691 tiW.hwnd = NULL;
692 tiW.uId = 0x1234ABCD;
693 SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW);
694 r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
695 expect(0, r);
697 tiW.cbSize = TTTOOLINFOW_V2_SIZE - 1;
698 tiW.hwnd = NULL;
699 tiW.hinst = GetModuleHandleA(NULL);
700 tiW.uFlags = 0;
701 tiW.uId = 0x1234ABCD;
702 tiW.lpszText = NULL;
703 tiW.lParam = 0xdeadbeef;
704 GetClientRect(hwnd, &tiW.rect);
705 r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&tiW);
706 ok(r, "Adding the tool to the tooltip failed\n");
707 r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
708 expect(1, r);
710 tiW.cbSize = TTTOOLINFOW_V2_SIZE - 1;
711 tiW.hwnd = NULL;
712 tiW.uId = 0x1234ABCD;
713 SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW);
714 r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
715 expect(0, r);
717 tiW.cbSize = TTTOOLINFOW_V2_SIZE + 1;
718 tiW.hwnd = NULL;
719 tiW.hinst = GetModuleHandleA(NULL);
720 tiW.uFlags = 0;
721 tiW.uId = 0x1234ABCD;
722 tiW.lpszText = NULL;
723 tiW.lParam = 0xdeadbeef;
724 GetClientRect(hwnd, &tiW.rect);
725 r = SendMessageW(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&tiW);
726 ok(r, "Adding the tool to the tooltip failed\n");
727 r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
728 expect(1, r);
729 /* looks like TTM_DELTOOLW doesn't work with invalid size */
730 tiW.cbSize = TTTOOLINFOW_V2_SIZE + 1;
731 tiW.hwnd = NULL;
732 tiW.uId = 0x1234ABCD;
733 SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW);
734 r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
735 expect(1, r);
737 tiW.cbSize = TTTOOLINFOW_V2_SIZE;
738 tiW.hwnd = NULL;
739 tiW.uId = 0x1234ABCD;
740 SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW);
741 r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
742 expect(0, r);
744 DestroyWindow(hwnd);
747 static void test_longtextA(void)
749 static const char longtextA[] =
750 "According to MSDN, TTM_ENUMTOOLS claims that TOOLINFO's lpszText is maximum "
751 "80 chars including null. In fact, the buffer is not null-terminated.";
752 HWND hwnd;
753 TTTOOLINFOA toolinfoA = { 0 };
754 CHAR bufA[256];
755 LRESULT r;
757 hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
758 10, 10, 300, 100,
759 NULL, NULL, NULL, 0);
760 toolinfoA.cbSize = sizeof(TTTOOLINFOA);
761 toolinfoA.hwnd = NULL;
762 toolinfoA.hinst = GetModuleHandleA(NULL);
763 toolinfoA.uFlags = 0;
764 toolinfoA.uId = 0x1234ABCD;
765 strcpy(bufA, longtextA);
766 toolinfoA.lpszText = bufA;
767 toolinfoA.lParam = 0xdeadbeef;
768 GetClientRect(hwnd, &toolinfoA.rect);
769 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
770 if (r)
772 int textlen;
773 memset(bufA, 0, sizeof(bufA));
774 toolinfoA.hwnd = NULL;
775 toolinfoA.uId = 0xABCD1234;
776 toolinfoA.lpszText = bufA;
777 SendMessageA(hwnd, TTM_ENUMTOOLSA, 0, (LPARAM)&toolinfoA);
778 textlen = lstrlenA(toolinfoA.lpszText);
779 ok(textlen == 80, "lpszText has %d chars\n", textlen);
780 ok(toolinfoA.uId == 0x1234ABCD,
781 "uId should be retrieved, got %p\n", (void*)toolinfoA.uId);
783 memset(bufA, 0, sizeof(bufA));
784 toolinfoA.hwnd = NULL;
785 toolinfoA.uId = 0x1234ABCD;
786 toolinfoA.lpszText = bufA;
787 SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
788 textlen = lstrlenA(toolinfoA.lpszText);
789 ok(textlen == 80, "lpszText has %d chars\n", textlen);
791 memset(bufA, 0, sizeof(bufA));
792 toolinfoA.hwnd = NULL;
793 toolinfoA.uId = 0x1234ABCD;
794 toolinfoA.lpszText = bufA;
795 SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
796 textlen = lstrlenA(toolinfoA.lpszText);
797 ok(textlen == 80, "lpszText has %d chars\n", textlen);
800 DestroyWindow(hwnd);
803 static void test_longtextW(void)
805 static const char longtextA[] =
806 "According to MSDN, TTM_ENUMTOOLS claims that TOOLINFO's lpszText is maximum "
807 "80 chars including null. Actually, this is not applied for wide version.";
808 HWND hwnd;
809 TTTOOLINFOW toolinfoW = { 0 };
810 WCHAR bufW[256];
811 LRESULT r;
812 int lenW;
814 hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0,
815 10, 10, 300, 100,
816 NULL, NULL, NULL, 0);
817 ok(hwnd != NULL, "Failed to create tooltip window.\n");
819 toolinfoW.cbSize = TTTOOLINFOW_V2_SIZE;
820 toolinfoW.hwnd = NULL;
821 toolinfoW.hinst = GetModuleHandleW(NULL);
822 toolinfoW.uFlags = 0;
823 toolinfoW.uId = 0x1234ABCD;
824 MultiByteToWideChar(CP_ACP, 0, longtextA, -1, bufW, ARRAY_SIZE(bufW));
825 lenW = lstrlenW(bufW);
826 toolinfoW.lpszText = bufW;
827 toolinfoW.lParam = 0xdeadbeef;
828 GetClientRect(hwnd, &toolinfoW.rect);
829 r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&toolinfoW);
830 if (r)
832 int textlen;
833 memset(bufW, 0, sizeof(bufW));
834 toolinfoW.hwnd = NULL;
835 toolinfoW.uId = 0xABCD1234;
836 toolinfoW.lpszText = bufW;
837 SendMessageW(hwnd, TTM_ENUMTOOLSW, 0, (LPARAM)&toolinfoW);
838 textlen = lstrlenW(toolinfoW.lpszText);
839 ok(textlen == lenW, "lpszText has %d chars\n", textlen);
840 ok(toolinfoW.uId == 0x1234ABCD,
841 "uId should be retrieved, got %p\n", (void*)toolinfoW.uId);
843 memset(bufW, 0, sizeof(bufW));
844 toolinfoW.hwnd = NULL;
845 toolinfoW.uId = 0x1234ABCD;
846 toolinfoW.lpszText = bufW;
847 SendMessageW(hwnd, TTM_GETTOOLINFOW, 0, (LPARAM)&toolinfoW);
848 textlen = lstrlenW(toolinfoW.lpszText);
849 ok(textlen == lenW, "lpszText has %d chars\n", textlen);
851 memset(bufW, 0, sizeof(bufW));
852 toolinfoW.hwnd = NULL;
853 toolinfoW.uId = 0x1234ABCD;
854 toolinfoW.lpszText = bufW;
855 SendMessageW(hwnd, TTM_GETTEXTW, 0, (LPARAM)&toolinfoW);
856 textlen = lstrlenW(toolinfoW.lpszText);
857 ok(textlen == lenW ||
858 broken(textlen == 0 && toolinfoW.lpszText == NULL), /* nt4, kb186177 */
859 "lpszText has %d chars\n", textlen);
862 DestroyWindow(hwnd);
865 static BOOL almost_eq(int a, int b)
867 return a-5<b && a+5>b;
870 static void test_track(void)
872 WCHAR textW[] = {'t','e','x','t',0};
873 TTTOOLINFOW info = { 0 };
874 HWND parent, tt;
875 LRESULT res;
876 RECT pos;
878 parent = CreateWindowExW(0, WC_STATICW, NULL, WS_CAPTION | WS_VISIBLE,
879 50, 50, 300, 300, NULL, NULL, NULL, 0);
880 ok(parent != NULL, "creation of parent window failed\n");
882 ShowWindow(parent, SW_SHOWNORMAL);
883 flush_events(100);
885 tt = CreateWindowExW(WS_EX_TOPMOST, TOOLTIPS_CLASSW, NULL, TTS_NOPREFIX | TTS_ALWAYSTIP,
886 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
887 parent, NULL, GetModuleHandleW(NULL), 0);
888 ok(tt != NULL, "creation of tooltip window failed\n");
890 info.cbSize = TTTOOLINFOW_V1_SIZE;
891 info.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
892 info.hwnd = parent;
893 info.hinst = GetModuleHandleW(NULL);
894 info.lpszText = textW;
895 info.uId = (UINT_PTR)parent;
896 GetClientRect(parent, &info.rect);
898 res = SendMessageW(tt, TTM_ADDTOOLW, 0, (LPARAM)&info);
899 ok(res, "adding the tool to the tooltip failed\n");
901 SendMessageW(tt, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1,0));
902 SendMessageW(tt, TTM_TRACKACTIVATE, (WPARAM)TRUE, (LPARAM)&info);
903 SendMessageW(tt, TTM_TRACKPOSITION, 0, MAKELPARAM(10, 10));
905 GetWindowRect(tt, &pos);
906 ok(almost_eq(pos.left, 10), "pos.left = %d\n", pos.left);
907 ok(almost_eq(pos.top, 10), "pos.top = %d\n", pos.top);
909 info.uFlags = TTF_IDISHWND | TTF_ABSOLUTE;
910 SendMessageW(tt, TTM_SETTOOLINFOW, 0, (LPARAM)&info);
911 SendMessageW(tt, TTM_TRACKPOSITION, 0, MAKELPARAM(10, 10));
913 GetWindowRect(tt, &pos);
914 ok(!almost_eq(pos.left, 10), "pos.left = %d\n", pos.left);
915 ok(!almost_eq(pos.top, 10), "pos.top = %d\n", pos.top);
917 DestroyWindow(tt);
918 DestroyWindow(parent);
921 static LRESULT CALLBACK info_wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
923 switch(msg) {
925 case WM_DESTROY:
926 PostQuitMessage(0);
927 break;
929 default:
930 return DefWindowProcA(hWnd, msg, wParam, lParam);
932 return 0;
935 static void test_setinfo(BOOL is_v6)
937 WNDCLASSA wc;
938 LRESULT lResult;
939 HWND parent, parent2, hwndTip, hwndTip2;
940 TTTOOLINFOA toolInfo = { 0 };
941 TTTOOLINFOA toolInfo2 = { 0 };
942 WNDPROC wndProc;
944 /* Create a class to use the custom draw wndproc */
945 wc.style = CS_HREDRAW | CS_VREDRAW;
946 wc.cbClsExtra = 0;
947 wc.cbWndExtra = 0;
948 wc.hInstance = GetModuleHandleA(NULL);
949 wc.hIcon = NULL;
950 wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
951 wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
952 wc.lpszMenuName = NULL;
953 wc.lpszClassName = "SetInfoClass";
954 wc.lpfnWndProc = info_wnd_proc;
955 RegisterClassA(&wc);
957 /* Create a main window */
958 parent = CreateWindowExA(0, "SetInfoClass", NULL,
959 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
960 WS_MAXIMIZEBOX | WS_VISIBLE,
961 50, 50,
962 300, 300,
963 NULL, NULL, NULL, 0);
964 ok(parent != NULL, "Creation of main window failed\n");
966 parent2 = CreateWindowExA(0, "SetInfoClass", NULL,
967 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
968 WS_MAXIMIZEBOX | WS_VISIBLE,
969 50, 50,
970 300, 300,
971 NULL, NULL, NULL, 0);
972 ok(parent2 != NULL, "Creation of main window failed\n");
974 /* Make it show */
975 ShowWindow(parent2, SW_SHOWNORMAL);
976 flush_events(100);
978 /* Create Tooltip */
979 hwndTip = CreateWindowExA(WS_EX_TOPMOST, TOOLTIPS_CLASSA,
980 NULL, TTS_NOPREFIX | TTS_ALWAYSTIP,
981 CW_USEDEFAULT, CW_USEDEFAULT,
982 CW_USEDEFAULT, CW_USEDEFAULT,
983 parent, NULL, GetModuleHandleA(NULL), 0);
984 ok(hwndTip != NULL, "Creation of tooltip window failed\n");
986 hwndTip2 = CreateWindowExA(WS_EX_TOPMOST, TOOLTIPS_CLASSA,
987 NULL, TTS_NOPREFIX | TTS_ALWAYSTIP,
988 CW_USEDEFAULT, CW_USEDEFAULT,
989 CW_USEDEFAULT, CW_USEDEFAULT,
990 parent, NULL, GetModuleHandleA(NULL), 0);
991 ok(hwndTip2 != NULL, "Creation of tooltip window failed\n");
994 /* Make it topmost, as per the MSDN */
995 SetWindowPos(hwndTip, HWND_TOPMOST, 0, 0, 0, 0,
996 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
998 /* Create a tool */
999 toolInfo.cbSize = TTTOOLINFOA_V1_SIZE;
1000 toolInfo.hwnd = parent;
1001 toolInfo.hinst = GetModuleHandleA(NULL);
1002 toolInfo.uFlags = TTF_SUBCLASS;
1003 toolInfo.uId = 0x1234ABCD;
1004 toolInfo.lpszText = (LPSTR)"This is a test tooltip";
1005 toolInfo.lParam = 0xdeadbeef;
1006 GetClientRect (parent, &toolInfo.rect);
1007 lResult = SendMessageA(hwndTip, TTM_ADDTOOLA, 0, (LPARAM)&toolInfo);
1008 ok(lResult, "Adding the tool to the tooltip failed\n");
1010 toolInfo.cbSize = TTTOOLINFOA_V1_SIZE;
1011 toolInfo.hwnd = parent2;
1012 toolInfo.hinst = GetModuleHandleA(NULL);
1013 toolInfo.uFlags = 0;
1014 toolInfo.uId = 0x1234ABCE;
1015 toolInfo.lpszText = (LPSTR)"This is a test tooltip";
1016 toolInfo.lParam = 0xdeadbeef;
1017 GetClientRect (parent, &toolInfo.rect);
1018 lResult = SendMessageA(hwndTip, TTM_ADDTOOLA, 0, (LPARAM)&toolInfo);
1019 ok(lResult, "Adding the tool to the tooltip failed\n");
1021 /* Try to Remove Subclass */
1022 toolInfo2.cbSize = TTTOOLINFOA_V1_SIZE;
1023 toolInfo2.hwnd = parent;
1024 toolInfo2.uId = 0x1234ABCD;
1025 lResult = SendMessageA(hwndTip, TTM_GETTOOLINFOA, 0, (LPARAM)&toolInfo2);
1026 ok(lResult, "GetToolInfo failed\n");
1027 ok(toolInfo2.uFlags & TTF_SUBCLASS || broken(is_v6 && !(toolInfo2.uFlags & TTF_SUBCLASS)) /* XP */,
1028 "uFlags does not have subclass\n");
1029 wndProc = (WNDPROC)GetWindowLongPtrA(parent, GWLP_WNDPROC);
1030 ok (wndProc != info_wnd_proc, "Window Proc is wrong\n");
1032 toolInfo2.uFlags &= ~TTF_SUBCLASS;
1033 SendMessageA(hwndTip, TTM_SETTOOLINFOA, 0, (LPARAM)&toolInfo2);
1034 lResult = SendMessageA(hwndTip, TTM_GETTOOLINFOA, 0, (LPARAM)&toolInfo2);
1035 ok(lResult, "GetToolInfo failed\n");
1036 ok(!(toolInfo2.uFlags & TTF_SUBCLASS), "uFlags has subclass\n");
1037 wndProc = (WNDPROC)GetWindowLongPtrA(parent, GWLP_WNDPROC);
1038 ok (wndProc != info_wnd_proc, "Window Proc is wrong\n");
1040 /* Try to Add Subclass */
1042 /* Make it topmost, as per the MSDN */
1043 SetWindowPos(hwndTip2, HWND_TOPMOST, 0, 0, 0, 0,
1044 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
1046 toolInfo2.cbSize = TTTOOLINFOA_V1_SIZE;
1047 toolInfo2.hwnd = parent2;
1048 toolInfo2.uId = 0x1234ABCE;
1049 lResult = SendMessageA(hwndTip, TTM_GETTOOLINFOA, 0, (LPARAM)&toolInfo2);
1050 ok(lResult, "GetToolInfo failed\n");
1051 ok(!(toolInfo2.uFlags & TTF_SUBCLASS), "uFlags has subclass\n");
1052 wndProc = (WNDPROC)GetWindowLongPtrA(parent2, GWLP_WNDPROC);
1053 ok (wndProc == info_wnd_proc, "Window Proc is wrong\n");
1055 toolInfo2.uFlags |= TTF_SUBCLASS;
1056 SendMessageA(hwndTip, TTM_SETTOOLINFOA, 0, (LPARAM)&toolInfo2);
1057 lResult = SendMessageA(hwndTip, TTM_GETTOOLINFOA, 0, (LPARAM)&toolInfo2);
1058 ok(lResult, "GetToolInfo failed\n");
1059 ok(toolInfo2.uFlags & TTF_SUBCLASS, "uFlags does not have subclass\n");
1060 wndProc = (WNDPROC)GetWindowLongPtrA(parent2, GWLP_WNDPROC);
1061 ok (wndProc == info_wnd_proc, "Window Proc is wrong\n");
1063 /* Clean up */
1064 DestroyWindow(hwndTip);
1065 DestroyWindow(hwndTip2);
1066 DestroyWindow(parent);
1067 DestroyWindow(parent2);
1070 static void test_margin(void)
1072 RECT r, r1;
1073 HWND hwnd;
1074 DWORD ret;
1076 hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
1077 10, 10, 300, 100,
1078 NULL, NULL, NULL, 0);
1079 ok(hwnd != NULL, "failed to create tooltip wnd\n");
1081 ret = SendMessageA(hwnd, TTM_SETMARGIN, 0, 0);
1082 ok(!ret, "got %d\n", ret);
1084 SetRect(&r, -1, -1, 1, 1);
1085 ret = SendMessageA(hwnd, TTM_SETMARGIN, 0, (LPARAM)&r);
1086 ok(!ret, "got %d\n", ret);
1088 SetRectEmpty(&r1);
1089 ret = SendMessageA(hwnd, TTM_GETMARGIN, 0, (LPARAM)&r1);
1090 ok(!ret, "got %d\n", ret);
1091 ok(EqualRect(&r, &r1), "got %s, was %s\n", wine_dbgstr_rect(&r1), wine_dbgstr_rect(&r));
1093 ret = SendMessageA(hwnd, TTM_SETMARGIN, 0, 0);
1094 ok(!ret, "got %d\n", ret);
1096 SetRectEmpty(&r1);
1097 ret = SendMessageA(hwnd, TTM_GETMARGIN, 0, (LPARAM)&r1);
1098 ok(!ret, "got %d\n", ret);
1099 ok(EqualRect(&r, &r1), "got %s, was %s\n", wine_dbgstr_rect(&r1), wine_dbgstr_rect(&r));
1101 ret = SendMessageA(hwnd, TTM_GETMARGIN, 0, 0);
1102 ok(!ret, "got %d\n", ret);
1104 DestroyWindow(hwnd);
1107 static void test_TTM_ADDTOOL(BOOL is_v6)
1109 TTTOOLINFOW tiW;
1110 TTTOOLINFOA ti;
1111 int ret, size;
1112 HWND hwnd, parent;
1113 UINT max_size;
1115 parent = CreateWindowExA(0, "Static", NULL, WS_POPUP, 0, 0, 0, 0, NULL, NULL, NULL, 0);
1116 ok(parent != NULL, "failed to create parent wnd\n");
1118 hwnd = CreateWindowExA(WS_EX_TOPMOST, TOOLTIPS_CLASSA, NULL, TTS_NOPREFIX | TTS_ALWAYSTIP,
1119 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1120 ok(hwnd != NULL, "Failed to create tooltip window.\n");
1122 for (size = 0; size <= TTTOOLINFOW_V3_SIZE + 1; size++)
1124 ti.cbSize = size;
1125 ti.hwnd = NULL;
1126 ti.hinst = GetModuleHandleA(NULL);
1127 ti.uFlags = 0;
1128 ti.uId = 0x1234abce;
1129 ti.lpszText = (LPSTR)"Test";
1130 ti.lParam = 0xdeadbeef;
1131 GetClientRect(hwnd, &ti.rect);
1133 ret = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
1134 ok(ret, "Failed to add a tool, size %d.\n", size);
1136 ret = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
1137 ok(ret == 1, "Unexpected tool count %d, size %d.\n", ret, size);
1139 ret = SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti);
1140 ok(!ret, "Unexpected ret value %d.\n", ret);
1142 ret = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
1143 ok(ret == 0, "Unexpected tool count %d, size %d.\n", ret, size);
1146 /* W variant checks cbSize. */
1147 max_size = is_v6 ? TTTOOLINFOW_V3_SIZE : TTTOOLINFOW_V2_SIZE;
1148 for (size = 0; size <= max_size + 1; size++)
1150 tiW.cbSize = size;
1151 tiW.hwnd = NULL;
1152 tiW.hinst = GetModuleHandleA(NULL);
1153 tiW.uFlags = 0;
1154 tiW.uId = 0x1234abce;
1155 tiW.lpszText = (LPWSTR)L"Test";
1156 tiW.lParam = 0xdeadbeef;
1157 GetClientRect(hwnd, &tiW.rect);
1159 ret = SendMessageA(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&tiW);
1160 todo_wine_if(!is_v6 && size > max_size)
1161 ok(size <= max_size ? ret : !ret, "%d: Unexpected ret value %d, size %d, max size %d.\n", is_v6, ret, size, max_size);
1162 if (ret)
1164 ret = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
1165 ok(ret == 1, "Unexpected tool count %d.\n", ret);
1167 ret = SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&tiW);
1168 ok(!ret, "Unexpected ret value %d.\n", ret);
1170 ret = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
1171 ok(ret == 0, "Unexpected tool count %d.\n", ret);
1175 DestroyWindow(hwnd);
1178 static const struct message ttn_show_parent_seq[] =
1180 { WM_NOTIFY, sent|id, 0, 0, TTN_SHOW },
1181 { 0 }
1184 static void test_TTN_SHOW(void)
1186 HWND hwndTip, hwnd;
1187 TTTOOLINFOA ti;
1188 RECT rect;
1189 BOOL ret;
1191 hwnd = create_parent_window();
1192 ok(hwnd != NULL, "Failed to create parent window.\n");
1194 /* Put cursor outside the window */
1195 GetWindowRect(hwnd, &rect);
1196 SetCursorPos(rect.right + 200, 0);
1198 ShowWindow(hwnd, SW_SHOWNORMAL);
1199 flush_events(100);
1201 /* Create tooltip */
1202 hwndTip = CreateWindowExA(WS_EX_TOPMOST, TOOLTIPS_CLASSA, NULL, TTS_ALWAYSTIP, 10, 10, 300, 300,
1203 hwnd, NULL, NULL, 0);
1204 ok(hwndTip != NULL, "Failed to create tooltip window.\n");
1206 SetWindowPos(hwndTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
1208 ti.cbSize = sizeof(TTTOOLINFOA);
1209 ti.hwnd = hwnd;
1210 ti.hinst = GetModuleHandleA(NULL);
1211 ti.uFlags = TTF_SUBCLASS;
1212 ti.uId = 0x1234abcd;
1213 ti.lpszText = (LPSTR)"This is a test tooltip";
1214 ti.lParam = 0xdeadbeef;
1215 GetClientRect(hwnd, &ti.rect);
1216 ret = SendMessageA(hwndTip, TTM_ADDTOOLA, 0, (LPARAM)&ti);
1217 ok(ret, "Failed to add a tool.\n");
1219 /* Make tooltip appear quickly */
1220 SendMessageA(hwndTip, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1, 0));
1222 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1224 /* Put cursor inside window, tooltip will appear immediately */
1225 GetWindowRect(hwnd, &rect);
1226 SetCursorPos((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2);
1227 flush_events(200);
1229 ok_sequence(sequences, PARENT_SEQ_INDEX, ttn_show_parent_seq, "TTN_SHOW parent seq", FALSE);
1231 DestroyWindow(hwndTip);
1232 DestroyWindow(hwnd);
1235 START_TEST(tooltips)
1237 ULONG_PTR ctx_cookie;
1238 HANDLE hCtx;
1240 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1242 LoadLibraryA("comctl32.dll");
1244 register_parent_wnd_class();
1246 test_create_tooltip(FALSE);
1247 test_customdraw();
1248 test_gettext();
1249 test_ttm_gettoolinfo();
1250 test_longtextA();
1251 test_longtextW();
1252 test_track();
1253 test_setinfo(FALSE);
1254 test_margin();
1255 test_TTM_ADDTOOL(FALSE);
1256 test_TTN_SHOW();
1258 if (!load_v6_module(&ctx_cookie, &hCtx))
1259 return;
1261 test_create_tooltip(TRUE);
1262 test_customdraw();
1263 test_longtextW();
1264 test_track();
1265 test_setinfo(TRUE);
1266 test_margin();
1267 test_TTM_ADDTOOL(TRUE);
1268 test_TTN_SHOW();
1270 unload_v6_module(ctx_cookie, hCtx);