[COMCTL32_WINETEST] Sync with Wine Staging 4.0. CORE-15682
[reactos.git] / modules / rostests / winetests / comctl32 / tooltips.c
1 /*
2 * Copyright 2005 Dmitry Timoshkov
3 * Copyright 2008 Jason Edmeades
4 *
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.
9 *
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.
14 *
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
18 */
19
20 #include <windows.h>
21 #include <commctrl.h>
22
23 #include "resources.h"
24
25 #include "wine/test.h"
26
27 #include "v6util.h"
28 #include "msg.h"
29
30 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
31
32 enum seq_index
33 {
34 PARENT_SEQ_INDEX = 0,
35 NUM_MSG_SEQUENCES
36 };
37
38 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
39
40 static void test_create_tooltip(BOOL is_v6)
41 {
42 HWND parent, hwnd;
43 DWORD style, exp_style;
44
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");
49
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");
54
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);
60
61 DestroyWindow(hwnd);
62
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");
67
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);
75
76 DestroyWindow(hwnd);
77
78 DestroyWindow(parent);
79 }
80
81 /* try to make sure pending X events have been processed before continuing */
82 static void flush_events(int waitTime)
83 {
84 MSG msg;
85 int diff = waitTime;
86 DWORD time = GetTickCount() + waitTime;
87
88 while (diff > 0)
89 {
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();
93 }
94 }
95
96 static int CD_Stages;
97 static LRESULT CD_Result;
98 static HWND g_hwnd;
99
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
109
110 static LRESULT CALLBACK custom_draw_wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
111 {
112 switch(msg) {
113
114 case WM_DESTROY:
115 PostQuitMessage(0);
116 break;
117
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);
124
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;
136 }
137
138 if (ttcd->nmcd.dwDrawStage == CDDS_PREPAINT) return CD_Result;
139 }
140 /* drop through */
141
142 default:
143 return DefWindowProcA(hWnd, msg, wParam, lParam);
144 }
145
146 return 0L;
147 }
148
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},
158
159 /* Invalid notification responses */
160 {CDRF_NOTIFYITEMDRAW, TEST_CDDS_PREPAINT},
161 {CDRF_NOTIFYPOSTERASE, TEST_CDDS_PREPAINT},
162 {CDRF_NEWFONT, TEST_CDDS_PREPAINT}
163 };
164
165 DWORD iterationNumber;
166 WNDCLASSA wc;
167 POINT orig_pos;
168 LRESULT ret;
169
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);
182
183 GetCursorPos(&orig_pos);
184
185 for (iterationNumber = 0;
186 iterationNumber < ARRAY_SIZE(expectedResults);
187 iterationNumber++) {
188
189 HWND parent, hwndTip;
190 RECT rect;
191 TTTOOLINFOA toolInfo = { 0 };
192
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, "Creation of main window failed\n");
201
202 /* Make it show */
203 ShowWindow(parent, SW_SHOWNORMAL);
204 flush_events(100);
205
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, "Creation of tooltip window failed\n");
213
214 /* Set up parms for the wndproc to handle */
215 CD_Stages = 0;
216 CD_Result = expectedResults[iterationNumber].FirstReturnValue;
217 g_hwnd = hwndTip;
218
219 /* Make it topmost, as per the MSDN */
220 SetWindowPos(hwndTip, HWND_TOPMOST, 0, 0, 0, 0,
221 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
222
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, "Failed to add the tool.\n");
234
235 /* Make tooltip appear quickly */
236 SendMessageA(hwndTip, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1,0));
237
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);
242
243 if (CD_Stages)
244 {
245 /* Check CustomDraw results */
246 ok(CD_Stages == expectedResults[iterationNumber].ExpectedCalls ||
247 broken(CD_Stages == (expectedResults[iterationNumber].ExpectedCalls & ~TEST_CDDS_POSTPAINT)), /* nt4 */
248 "CustomDraw run %d stages %x, expected %x\n", iterationNumber, CD_Stages,
249 expectedResults[iterationNumber].ExpectedCalls);
250 }
251
252 ret = SendMessageA(hwndTip, TTM_GETCURRENTTOOLA, 0, 0);
253 ok(ret, "Failed to get current tool %#lx.\n", ret);
254
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, "Unexpected hwnd %p.\n", toolInfo.hwnd);
261 ok(toolInfo.hinst == GetModuleHandleA(NULL), "Unexpected hinst %p.\n", toolInfo.hinst);
262 ok(toolInfo.uId == 0x1234abcd, "Unexpected uId %lx.\n", toolInfo.uId);
263 ok(toolInfo.lParam == 0, "Unexpected lParam %lx.\n", toolInfo.lParam);
264 ok(toolInfo.lpReserved == (void *)0xdeadbeef, "Unexpected lpReserved %p.\n", toolInfo.lpReserved);
265
266 /* Clean up */
267 DestroyWindow(hwndTip);
268 DestroyWindow(parent);
269 }
270
271 SetCursorPos(orig_pos.x, orig_pos.y);
272 }
273
274 static const CHAR testcallbackA[] = "callback";
275
276 static RECT g_ttip_rect;
277 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
278 {
279 static LONG defwndproc_counter = 0;
280 struct message msg;
281 LRESULT ret;
282
283 if (message == WM_NOTIFY && lParam)
284 {
285 NMTTDISPINFOA *ttnmdi = (NMTTDISPINFOA*)lParam;
286 NMHDR *hdr = (NMHDR *)lParam;
287 RECT rect;
288
289 if (hdr->code != NM_CUSTOMDRAW)
290 {
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);
298 }
299
300 switch (hdr->code)
301 {
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;
309 }
310 }
311
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--;
318
319 return ret;
320 }
321
322 static void register_parent_wnd_class(void)
323 {
324 WNDCLASSA cls;
325 BOOL ret;
326
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");
339 }
340
341 static HWND create_parent_window(void)
342 {
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);
349 }
350
351 static void test_gettext(void)
352 {
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;
362
363 notify = create_parent_window();
364 ok(notify != NULL, "Expected notification window to be created\n");
365
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");
371
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);
384
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);
391
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);
397
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");
409
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);
416
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);
422
423 r = SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&toolinfoA);
424 ok(!r, "got %ld\n", r);
425
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");
438
439 length = SendMessageA(hwnd, WM_GETTEXTLENGTH, 0, 0);
440 ok(length == 0, "Expected 0, got %d\n", length);
441
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);
448
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);
455
456 length = SendMessageA(hwnd, WM_GETTEXTLENGTH, 0, 0);
457 ok(length == 0, "Expected 0, got %d\n", length);
458
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");
470
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);
477
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);
483
484 DestroyWindow(hwnd);
485 DestroyWindow(notify);
486
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");
491
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");
505
506 if (0) /* crashes on NT4 */
507 {
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");
513 }
514
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);
527
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);
534
535 /* enable TTS_NOPREFIX, original text is retained */
536 style = GetWindowLongA(hwnd, GWL_STYLE);
537 SetWindowLongA(hwnd, GWL_STYLE, style | TTS_NOPREFIX);
538
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);
545
546 DestroyWindow(hwnd);
547 }
548
549 static void test_ttm_gettoolinfo(void)
550 {
551 TTTOOLINFOA ti;
552 TTTOOLINFOW tiW;
553 HWND hwnd;
554 DWORD r;
555
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");
558
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");
569
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);
577
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);
588
589 ti.cbSize = TTTOOLINFOA_V2_SIZE;
590 ti.uId = 0x1234ABCD;
591 ti.lParam = 0x55555555;
592 SendMessageA(hwnd, TTM_SETTOOLINFOA, 0, (LPARAM)&ti);
593
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);
601
602 DestroyWindow(hwnd);
603
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);
608
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);
621
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);
628
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);
641
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);
648
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);
661
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);
668
669 DestroyWindow(hwnd);
670
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");
676
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);
689
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);
696
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);
709
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);
716
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);
736
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);
743
744 DestroyWindow(hwnd);
745 }
746
747 static void test_longtextA(void)
748 {
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;
756
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)
771 {
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);
782
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);
790
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);
798 }
799
800 DestroyWindow(hwnd);
801 }
802
803 static void test_longtextW(void)
804 {
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;
813
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");
818
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)
831 {
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);
842
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);
850
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);
860 }
861
862 DestroyWindow(hwnd);
863 }
864
865 static BOOL almost_eq(int a, int b)
866 {
867 return a-5<b && a+5>b;
868 }
869
870 static void test_track(void)
871 {
872 WCHAR textW[] = {'t','e','x','t',0};
873 TTTOOLINFOW info = { 0 };
874 HWND parent, tt;
875 LRESULT res;
876 RECT pos;
877
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");
881
882 ShowWindow(parent, SW_SHOWNORMAL);
883 flush_events(100);
884
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");
889
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);
897
898 res = SendMessageW(tt, TTM_ADDTOOLW, 0, (LPARAM)&info);
899 ok(res, "adding the tool to the tooltip failed\n");
900
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));
904
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);
908
909 info.uFlags = TTF_IDISHWND | TTF_ABSOLUTE;
910 SendMessageW(tt, TTM_SETTOOLINFOW, 0, (LPARAM)&info);
911 SendMessageW(tt, TTM_TRACKPOSITION, 0, MAKELPARAM(10, 10));
912
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);
916
917 DestroyWindow(tt);
918 DestroyWindow(parent);
919 }
920
921 static LRESULT CALLBACK info_wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
922 {
923 switch(msg) {
924
925 case WM_DESTROY:
926 PostQuitMessage(0);
927 break;
928
929 default:
930 return DefWindowProcA(hWnd, msg, wParam, lParam);
931 }
932 return 0;
933 }
934
935 static void test_setinfo(BOOL is_v6)
936 {
937 WNDCLASSA wc;
938 LRESULT lResult;
939 HWND parent, parent2, hwndTip, hwndTip2;
940 TTTOOLINFOA toolInfo = { 0 };
941 TTTOOLINFOA toolInfo2 = { 0 };
942 WNDPROC wndProc;
943
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);
956
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");
965
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");
973
974 /* Make it show */
975 ShowWindow(parent2, SW_SHOWNORMAL);
976 flush_events(100);
977
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");
985
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");
992
993
994 /* Make it topmost, as per the MSDN */
995 SetWindowPos(hwndTip, HWND_TOPMOST, 0, 0, 0, 0,
996 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
997
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");
1009
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");
1020
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");
1031
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");
1039
1040 /* Try to Add Subclass */
1041
1042 /* Make it topmost, as per the MSDN */
1043 SetWindowPos(hwndTip2, HWND_TOPMOST, 0, 0, 0, 0,
1044 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
1045
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");
1054
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");
1062
1063 /* Clean up */
1064 DestroyWindow(hwndTip);
1065 DestroyWindow(hwndTip2);
1066 DestroyWindow(parent);
1067 DestroyWindow(parent2);
1068 }
1069
1070 static void test_margin(void)
1071 {
1072 RECT r, r1;
1073 HWND hwnd;
1074 DWORD ret;
1075
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");
1080
1081 ret = SendMessageA(hwnd, TTM_SETMARGIN, 0, 0);
1082 ok(!ret, "got %d\n", ret);
1083
1084 SetRect(&r, -1, -1, 1, 1);
1085 ret = SendMessageA(hwnd, TTM_SETMARGIN, 0, (LPARAM)&r);
1086 ok(!ret, "got %d\n", ret);
1087
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));
1092
1093 ret = SendMessageA(hwnd, TTM_SETMARGIN, 0, 0);
1094 ok(!ret, "got %d\n", ret);
1095
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));
1100
1101 ret = SendMessageA(hwnd, TTM_GETMARGIN, 0, 0);
1102 ok(!ret, "got %d\n", ret);
1103
1104 DestroyWindow(hwnd);
1105 }
1106
1107 static void test_TTM_ADDTOOL(BOOL is_v6)
1108 {
1109 static const WCHAR testW[] = {'T','e','s','t',0};
1110 TTTOOLINFOW tiW;
1111 TTTOOLINFOA ti;
1112 int ret, size;
1113 HWND hwnd, parent;
1114 UINT max_size;
1115
1116 parent = CreateWindowExA(0, "Static", NULL, WS_POPUP, 0, 0, 0, 0, NULL, NULL, NULL, 0);
1117 ok(parent != NULL, "failed to create parent wnd\n");
1118
1119 hwnd = CreateWindowExA(WS_EX_TOPMOST, TOOLTIPS_CLASSA, NULL, TTS_NOPREFIX | TTS_ALWAYSTIP,
1120 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1121 ok(hwnd != NULL, "Failed to create tooltip window.\n");
1122
1123 for (size = 0; size <= TTTOOLINFOW_V3_SIZE + 1; size++)
1124 {
1125 ti.cbSize = size;
1126 ti.hwnd = NULL;
1127 ti.hinst = GetModuleHandleA(NULL);
1128 ti.uFlags = 0;
1129 ti.uId = 0x1234abce;
1130 ti.lpszText = (LPSTR)"Test";
1131 ti.lParam = 0xdeadbeef;
1132 GetClientRect(hwnd, &ti.rect);
1133
1134 ret = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
1135 ok(ret, "Failed to add a tool, size %d.\n", size);
1136
1137 ret = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
1138 ok(ret == 1, "Unexpected tool count %d, size %d.\n", ret, size);
1139
1140 ret = SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti);
1141 ok(!ret, "Unexpected ret value %d.\n", ret);
1142
1143 ret = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
1144 ok(ret == 0, "Unexpected tool count %d, size %d.\n", ret, size);
1145 }
1146
1147 /* W variant checks cbSize. */
1148 max_size = is_v6 ? TTTOOLINFOW_V3_SIZE : TTTOOLINFOW_V2_SIZE;
1149 for (size = 0; size <= max_size + 1; size++)
1150 {
1151 tiW.cbSize = size;
1152 tiW.hwnd = NULL;
1153 tiW.hinst = GetModuleHandleA(NULL);
1154 tiW.uFlags = 0;
1155 tiW.uId = 0x1234abce;
1156 tiW.lpszText = (LPWSTR)testW;
1157 tiW.lParam = 0xdeadbeef;
1158 GetClientRect(hwnd, &tiW.rect);
1159
1160 ret = SendMessageA(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&tiW);
1161 todo_wine_if(!is_v6 && size > max_size)
1162 ok(size <= max_size ? ret : !ret, "%d: Unexpected ret value %d, size %d, max size %d.\n", is_v6, ret, size, max_size);
1163 if (ret)
1164 {
1165 ret = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
1166 ok(ret == 1, "Unexpected tool count %d.\n", ret);
1167
1168 ret = SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&tiW);
1169 ok(!ret, "Unexpected ret value %d.\n", ret);
1170
1171 ret = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
1172 ok(ret == 0, "Unexpected tool count %d.\n", ret);
1173 }
1174 }
1175
1176 DestroyWindow(hwnd);
1177 }
1178
1179 static const struct message ttn_show_parent_seq[] =
1180 {
1181 { WM_NOTIFY, sent|id, 0, 0, TTN_SHOW },
1182 { 0 }
1183 };
1184
1185 static void test_TTN_SHOW(void)
1186 {
1187 HWND hwndTip, hwnd;
1188 TTTOOLINFOA ti;
1189 RECT rect;
1190 BOOL ret;
1191
1192 hwnd = create_parent_window();
1193 ok(hwnd != NULL, "Failed to create parent window.\n");
1194
1195 /* Put cursor outside the window */
1196 GetWindowRect(hwnd, &rect);
1197 SetCursorPos(rect.right + 200, 0);
1198
1199 ShowWindow(hwnd, SW_SHOWNORMAL);
1200 flush_events(100);
1201
1202 /* Create tooltip */
1203 hwndTip = CreateWindowExA(WS_EX_TOPMOST, TOOLTIPS_CLASSA, NULL, TTS_ALWAYSTIP, 10, 10, 300, 300,
1204 hwnd, NULL, NULL, 0);
1205 ok(hwndTip != NULL, "Failed to create tooltip window.\n");
1206
1207 SetWindowPos(hwndTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
1208
1209 ti.cbSize = sizeof(TTTOOLINFOA);
1210 ti.hwnd = hwnd;
1211 ti.hinst = GetModuleHandleA(NULL);
1212 ti.uFlags = TTF_SUBCLASS;
1213 ti.uId = 0x1234abcd;
1214 ti.lpszText = (LPSTR)"This is a test tooltip";
1215 ti.lParam = 0xdeadbeef;
1216 GetClientRect(hwnd, &ti.rect);
1217 ret = SendMessageA(hwndTip, TTM_ADDTOOLA, 0, (LPARAM)&ti);
1218 ok(ret, "Failed to add a tool.\n");
1219
1220 /* Make tooltip appear quickly */
1221 SendMessageA(hwndTip, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1, 0));
1222
1223 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1224
1225 /* Put cursor inside window, tooltip will appear immediately */
1226 GetWindowRect(hwnd, &rect);
1227 SetCursorPos((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2);
1228 flush_events(200);
1229
1230 ok_sequence(sequences, PARENT_SEQ_INDEX, ttn_show_parent_seq, "TTN_SHOW parent seq", FALSE);
1231
1232 DestroyWindow(hwndTip);
1233 DestroyWindow(hwnd);
1234 }
1235
1236 START_TEST(tooltips)
1237 {
1238 ULONG_PTR ctx_cookie;
1239 HANDLE hCtx;
1240
1241 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1242
1243 LoadLibraryA("comctl32.dll");
1244
1245 register_parent_wnd_class();
1246
1247 test_create_tooltip(FALSE);
1248 test_customdraw();
1249 test_gettext();
1250 test_ttm_gettoolinfo();
1251 test_longtextA();
1252 test_longtextW();
1253 test_track();
1254 test_setinfo(FALSE);
1255 test_margin();
1256 test_TTM_ADDTOOL(FALSE);
1257 test_TTN_SHOW();
1258
1259 if (!load_v6_module(&ctx_cookie, &hCtx))
1260 return;
1261
1262 test_create_tooltip(TRUE);
1263 test_customdraw();
1264 test_longtextW();
1265 test_track();
1266 test_setinfo(TRUE);
1267 test_margin();
1268 test_TTM_ADDTOOL(TRUE);
1269 test_TTN_SHOW();
1270
1271 unload_v6_module(ctx_cookie, hCtx);
1272 }