ddraw: Return early in d3d_device7_DrawIndexedPrimitiveStrided() with a 0 vertex...
[wine.git] / dlls / comctl32 / tests / tooltips.c
blob3382fcef76b21c9d23192aff04a30efbd105d963
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 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
29 static void test_create_tooltip(void)
31 HWND parent, hwnd;
32 DWORD style, exp_style;
34 parent = CreateWindowExA(0, "static", NULL, WS_POPUP,
35 0, 0, 0, 0,
36 NULL, NULL, NULL, 0);
37 ok(parent != NULL, "failed to create parent wnd\n");
39 hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0x7fffffff | WS_POPUP,
40 10, 10, 300, 100,
41 parent, NULL, NULL, 0);
42 ok(hwnd != NULL, "failed to create tooltip wnd\n");
44 style = GetWindowLongA(hwnd, GWL_STYLE);
45 trace("style = %08x\n", style);
46 exp_style = 0x7fffffff | WS_POPUP;
47 exp_style &= ~(WS_CHILD | WS_MAXIMIZE | WS_BORDER | WS_DLGFRAME);
48 ok(style == exp_style || broken(style == (exp_style | WS_BORDER)), /* nt4 */
49 "wrong style %08x/%08x\n", style, exp_style);
51 DestroyWindow(hwnd);
53 hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
54 10, 10, 300, 100,
55 parent, NULL, NULL, 0);
56 ok(hwnd != NULL, "failed to create tooltip wnd\n");
58 style = GetWindowLongA(hwnd, GWL_STYLE);
59 trace("style = %08x\n", style);
60 ok(style == (WS_POPUP | WS_CLIPSIBLINGS | WS_BORDER),
61 "wrong style %08x\n", style);
63 DestroyWindow(hwnd);
65 DestroyWindow(parent);
68 /* try to make sure pending X events have been processed before continuing */
69 static void flush_events(int waitTime)
71 MSG msg;
72 int diff = waitTime;
73 DWORD time = GetTickCount() + waitTime;
75 while (diff > 0)
77 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min(100,diff), QS_ALLEVENTS) == WAIT_TIMEOUT) break;
78 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
79 diff = time - GetTickCount();
83 static int CD_Stages;
84 static LRESULT CD_Result;
85 static HWND g_hwnd;
87 #define TEST_CDDS_PREPAINT 0x00000001
88 #define TEST_CDDS_POSTPAINT 0x00000002
89 #define TEST_CDDS_PREERASE 0x00000004
90 #define TEST_CDDS_POSTERASE 0x00000008
91 #define TEST_CDDS_ITEMPREPAINT 0x00000010
92 #define TEST_CDDS_ITEMPOSTPAINT 0x00000020
93 #define TEST_CDDS_ITEMPREERASE 0x00000040
94 #define TEST_CDDS_ITEMPOSTERASE 0x00000080
95 #define TEST_CDDS_SUBITEM 0x00000100
97 static LRESULT CALLBACK custom_draw_wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
99 switch(msg) {
101 case WM_DESTROY:
102 PostQuitMessage(0);
103 break;
105 case WM_NOTIFY:
106 if (((NMHDR *)lParam)->code == NM_CUSTOMDRAW) {
107 NMTTCUSTOMDRAW *ttcd = (NMTTCUSTOMDRAW*) lParam;
108 ok(ttcd->nmcd.hdr.hwndFrom == g_hwnd, "Unexpected hwnd source %p (%p)\n",
109 ttcd->nmcd.hdr.hwndFrom, g_hwnd);
110 ok(ttcd->nmcd.hdr.idFrom == 0x1234ABCD, "Unexpected id %x\n", (int)ttcd->nmcd.hdr.idFrom);
112 switch (ttcd->nmcd.dwDrawStage) {
113 case CDDS_PREPAINT : CD_Stages |= TEST_CDDS_PREPAINT; break;
114 case CDDS_POSTPAINT : CD_Stages |= TEST_CDDS_POSTPAINT; break;
115 case CDDS_PREERASE : CD_Stages |= TEST_CDDS_PREERASE; break;
116 case CDDS_POSTERASE : CD_Stages |= TEST_CDDS_POSTERASE; break;
117 case CDDS_ITEMPREPAINT : CD_Stages |= TEST_CDDS_ITEMPREPAINT; break;
118 case CDDS_ITEMPOSTPAINT: CD_Stages |= TEST_CDDS_ITEMPOSTPAINT; break;
119 case CDDS_ITEMPREERASE : CD_Stages |= TEST_CDDS_ITEMPREERASE; break;
120 case CDDS_ITEMPOSTERASE: CD_Stages |= TEST_CDDS_ITEMPOSTERASE; break;
121 case CDDS_SUBITEM : CD_Stages |= TEST_CDDS_SUBITEM; break;
122 default: CD_Stages = -1;
125 if (ttcd->nmcd.dwDrawStage == CDDS_PREPAINT) return CD_Result;
127 /* drop through */
129 default:
130 return DefWindowProcA(hWnd, msg, wParam, lParam);
133 return 0L;
136 static void test_customdraw(void) {
137 static struct {
138 LRESULT FirstReturnValue;
139 int ExpectedCalls;
140 } expectedResults[] = {
141 /* Valid notification responses */
142 {CDRF_DODEFAULT, TEST_CDDS_PREPAINT},
143 {CDRF_SKIPDEFAULT, TEST_CDDS_PREPAINT},
144 {CDRF_NOTIFYPOSTPAINT, TEST_CDDS_PREPAINT | TEST_CDDS_POSTPAINT},
146 /* Invalid notification responses */
147 {CDRF_NOTIFYITEMDRAW, TEST_CDDS_PREPAINT},
148 {CDRF_NOTIFYPOSTERASE, TEST_CDDS_PREPAINT},
149 {CDRF_NEWFONT, TEST_CDDS_PREPAINT}
152 DWORD iterationNumber;
153 WNDCLASSA wc;
154 LRESULT lResult;
156 /* Create a class to use the custom draw wndproc */
157 wc.style = CS_HREDRAW | CS_VREDRAW;
158 wc.cbClsExtra = 0;
159 wc.cbWndExtra = 0;
160 wc.hInstance = GetModuleHandleA(NULL);
161 wc.hIcon = NULL;
162 wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
163 wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
164 wc.lpszMenuName = NULL;
165 wc.lpszClassName = "CustomDrawClass";
166 wc.lpfnWndProc = custom_draw_wnd_proc;
167 RegisterClassA(&wc);
169 for (iterationNumber = 0;
170 iterationNumber < sizeof(expectedResults)/sizeof(expectedResults[0]);
171 iterationNumber++) {
173 HWND parent, hwndTip;
174 RECT rect;
175 TTTOOLINFOA toolInfo = { 0 };
177 /* Create a main window */
178 parent = CreateWindowExA(0, "CustomDrawClass", NULL,
179 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
180 WS_MAXIMIZEBOX | WS_VISIBLE,
181 50, 50,
182 300, 300,
183 NULL, NULL, NULL, 0);
184 ok(parent != NULL, "Creation of main window failed\n");
186 /* Make it show */
187 ShowWindow(parent, SW_SHOWNORMAL);
188 flush_events(100);
190 /* Create Tooltip */
191 hwndTip = CreateWindowExA(WS_EX_TOPMOST, TOOLTIPS_CLASSA,
192 NULL, TTS_NOPREFIX | TTS_ALWAYSTIP,
193 CW_USEDEFAULT, CW_USEDEFAULT,
194 CW_USEDEFAULT, CW_USEDEFAULT,
195 parent, NULL, GetModuleHandleA(NULL), 0);
196 ok(hwndTip != NULL, "Creation of tooltip window failed\n");
198 /* Set up parms for the wndproc to handle */
199 CD_Stages = 0;
200 CD_Result = expectedResults[iterationNumber].FirstReturnValue;
201 g_hwnd = hwndTip;
203 /* Make it topmost, as per the MSDN */
204 SetWindowPos(hwndTip, HWND_TOPMOST, 0, 0, 0, 0,
205 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
207 /* Create a tool */
208 toolInfo.cbSize = TTTOOLINFOA_V1_SIZE;
209 toolInfo.hwnd = parent;
210 toolInfo.hinst = GetModuleHandleA(NULL);
211 toolInfo.uFlags = TTF_SUBCLASS;
212 toolInfo.uId = 0x1234ABCD;
213 toolInfo.lpszText = (LPSTR)"This is a test tooltip";
214 toolInfo.lParam = 0xdeadbeef;
215 GetClientRect (parent, &toolInfo.rect);
216 lResult = SendMessageA(hwndTip, TTM_ADDTOOLA, 0, (LPARAM)&toolInfo);
217 ok(lResult, "Adding the tool to the tooltip failed\n");
219 /* Make tooltip appear quickly */
220 SendMessageA(hwndTip, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1,0));
222 /* Put cursor inside window, tooltip will appear immediately */
223 GetWindowRect( parent, &rect );
224 SetCursorPos( (rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2 );
225 flush_events(200);
227 if (CD_Stages)
229 /* Check CustomDraw results */
230 ok(CD_Stages == expectedResults[iterationNumber].ExpectedCalls ||
231 broken(CD_Stages == (expectedResults[iterationNumber].ExpectedCalls & ~TEST_CDDS_POSTPAINT)), /* nt4 */
232 "CustomDraw run %d stages %x, expected %x\n", iterationNumber, CD_Stages,
233 expectedResults[iterationNumber].ExpectedCalls);
236 /* Clean up */
237 DestroyWindow(hwndTip);
238 DestroyWindow(parent);
244 static const CHAR testcallbackA[] = "callback";
246 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
248 if (message == WM_NOTIFY && lParam)
250 NMTTDISPINFOA *ttnmdi = (NMTTDISPINFOA*)lParam;
252 if (ttnmdi->hdr.code == TTN_GETDISPINFOA)
253 lstrcpyA(ttnmdi->lpszText, testcallbackA);
256 return DefWindowProcA(hwnd, message, wParam, lParam);
259 static BOOL register_parent_wnd_class(void)
261 WNDCLASSA cls;
263 cls.style = 0;
264 cls.lpfnWndProc = parent_wnd_proc;
265 cls.cbClsExtra = 0;
266 cls.cbWndExtra = 0;
267 cls.hInstance = GetModuleHandleA(NULL);
268 cls.hIcon = 0;
269 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
270 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
271 cls.lpszMenuName = NULL;
272 cls.lpszClassName = "Tooltips test parent class";
273 return RegisterClassA(&cls);
276 static HWND create_parent_window(void)
278 if (!register_parent_wnd_class())
279 return NULL;
281 return CreateWindowExA(0, "Tooltips test parent class",
282 "Tooltips test parent window",
283 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
284 WS_MAXIMIZEBOX | WS_VISIBLE,
285 0, 0, 100, 100,
286 GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
289 static void test_gettext(void)
291 HWND hwnd, notify;
292 TTTOOLINFOA toolinfoA;
293 TTTOOLINFOW toolinfoW;
294 LRESULT r;
295 CHAR bufA[10] = "";
296 WCHAR bufW[10] = { 0 };
297 static const CHAR testtipA[] = "testtip";
299 notify = create_parent_window();
300 ok(notify != NULL, "Expected notification window to be created\n");
302 /* For bug 14790 - lpszText is NULL */
303 hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
304 10, 10, 300, 100,
305 NULL, NULL, NULL, 0);
306 ok(hwnd != NULL, "failed to create tooltip wnd\n");
308 /* use sizeof(TTTOOLINFOA) instead of TTTOOLINFOA_V1_SIZE so that adding it fails on Win9x */
309 /* otherwise it crashes on the NULL lpszText */
310 toolinfoA.cbSize = sizeof(TTTOOLINFOA);
311 toolinfoA.hwnd = NULL;
312 toolinfoA.hinst = GetModuleHandleA(NULL);
313 toolinfoA.uFlags = 0;
314 toolinfoA.uId = 0x1234ABCD;
315 toolinfoA.lpszText = NULL;
316 toolinfoA.lParam = 0xdeadbeef;
317 GetClientRect(hwnd, &toolinfoA.rect);
318 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
319 if (r)
321 toolinfoA.hwnd = NULL;
322 toolinfoA.uId = 0x1234ABCD;
323 toolinfoA.lpszText = bufA;
324 SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
325 ok(strcmp(toolinfoA.lpszText, "") == 0, "lpszText should be an empty string\n");
327 toolinfoA.lpszText = bufA;
328 SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
329 ok(toolinfoA.lpszText == NULL,
330 "expected NULL, got %p\n", toolinfoA.lpszText);
332 /* NULL hinst, valid resource id for text */
333 toolinfoA.cbSize = sizeof(TTTOOLINFOA);
334 toolinfoA.hwnd = NULL;
335 toolinfoA.hinst = NULL;
336 toolinfoA.uFlags = 0;
337 toolinfoA.uId = 0x1233ABCD;
338 toolinfoA.lpszText = MAKEINTRESOURCEA(IDS_TBADD1);
339 toolinfoA.lParam = 0xdeadbeef;
340 GetClientRect(hwnd, &toolinfoA.rect);
341 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
342 ok(r, "failed to add a tool\n");
344 toolinfoA.hwnd = NULL;
345 toolinfoA.uId = 0x1233ABCD;
346 toolinfoA.lpszText = bufA;
347 SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
348 ok(strcmp(toolinfoA.lpszText, "abc") == 0, "lpszText should be an empty string\n");
350 toolinfoA.hinst = (HINSTANCE)0xdeadbee;
351 SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
352 ok(toolinfoA.hinst == NULL, "expected NULL, got %p\n", toolinfoA.hinst);
354 SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&toolinfoA);
356 else
358 win_skip( "Old comctl32, not testing NULL text\n" );
359 DestroyWindow( hwnd );
360 return;
363 /* add another tool with text */
364 toolinfoA.cbSize = sizeof(TTTOOLINFOA);
365 toolinfoA.hwnd = NULL;
366 toolinfoA.hinst = GetModuleHandleA(NULL);
367 toolinfoA.uFlags = 0;
368 toolinfoA.uId = 0x1235ABCD;
369 strcpy(bufA, testtipA);
370 toolinfoA.lpszText = bufA;
371 toolinfoA.lParam = 0xdeadbeef;
372 GetClientRect(hwnd, &toolinfoA.rect);
373 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
374 ok(r, "Adding the tool to the tooltip failed\n");
375 if (r)
377 DWORD length;
379 length = SendMessageA(hwnd, WM_GETTEXTLENGTH, 0, 0);
380 ok(length == 0, "Expected 0, got %d\n", length);
382 toolinfoA.hwnd = NULL;
383 toolinfoA.uId = 0x1235ABCD;
384 toolinfoA.lpszText = bufA;
385 SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
386 ok(strcmp(toolinfoA.lpszText, testtipA) == 0, "lpszText should be an empty string\n");
388 memset(bufA, 0x1f, sizeof(bufA));
389 toolinfoA.lpszText = bufA;
390 SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
391 ok(strcmp(toolinfoA.lpszText, testtipA) == 0,
392 "expected %s, got %p\n", testtipA, toolinfoA.lpszText);
394 length = SendMessageA(hwnd, WM_GETTEXTLENGTH, 0, 0);
395 ok(length == 0, "Expected 0, got %d\n", length);
398 /* add another with callback text */
399 toolinfoA.cbSize = sizeof(TTTOOLINFOA);
400 toolinfoA.hwnd = notify;
401 toolinfoA.hinst = GetModuleHandleA(NULL);
402 toolinfoA.uFlags = 0;
403 toolinfoA.uId = 0x1236ABCD;
404 toolinfoA.lpszText = LPSTR_TEXTCALLBACKA;
405 toolinfoA.lParam = 0xdeadbeef;
406 GetClientRect(hwnd, &toolinfoA.rect);
407 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
408 ok(r, "Adding the tool to the tooltip failed\n");
409 if (r)
411 toolinfoA.hwnd = notify;
412 toolinfoA.uId = 0x1236ABCD;
413 toolinfoA.lpszText = bufA;
414 SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
415 ok(strcmp(toolinfoA.lpszText, testcallbackA) == 0,
416 "lpszText should be an (%s) string\n", testcallbackA);
418 toolinfoA.lpszText = bufA;
419 SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
420 ok(toolinfoA.lpszText == LPSTR_TEXTCALLBACKA,
421 "expected LPSTR_TEXTCALLBACKA, got %p\n", toolinfoA.lpszText);
424 DestroyWindow(hwnd);
425 DestroyWindow(notify);
427 SetLastError(0xdeadbeef);
428 hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0,
429 10, 10, 300, 100,
430 NULL, NULL, NULL, 0);
432 if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
433 win_skip("CreateWindowExW is not implemented\n");
434 return;
436 ok(hwnd != NULL, "failed to create tooltip wnd\n");
438 toolinfoW.cbSize = sizeof(TTTOOLINFOW);
439 toolinfoW.hwnd = NULL;
440 toolinfoW.hinst = GetModuleHandleA(NULL);
441 toolinfoW.uFlags = 0;
442 toolinfoW.uId = 0x1234ABCD;
443 toolinfoW.lpszText = NULL;
444 toolinfoW.lParam = 0xdeadbeef;
445 GetClientRect(hwnd, &toolinfoW.rect);
446 r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&toolinfoW);
447 ok(!r, "Adding the tool to the tooltip succeeded!\n");
449 if (0) /* crashes on NT4 */
451 toolinfoW.hwnd = NULL;
452 toolinfoW.uId = 0x1234ABCD;
453 toolinfoW.lpszText = bufW;
454 SendMessageW(hwnd, TTM_GETTEXTW, 0, (LPARAM)&toolinfoW);
455 ok(toolinfoW.lpszText[0] == 0, "lpszText should be an empty string\n");
458 DestroyWindow(hwnd);
461 static void test_ttm_gettoolinfo(void)
463 TTTOOLINFOA ti;
464 TTTOOLINFOW tiW;
465 HWND hwnd;
466 DWORD r;
468 hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
469 10, 10, 300, 100,
470 NULL, NULL, NULL, 0);
472 ti.cbSize = TTTOOLINFOA_V2_SIZE;
473 ti.hwnd = NULL;
474 ti.hinst = GetModuleHandleA(NULL);
475 ti.uFlags = 0;
476 ti.uId = 0x1234ABCD;
477 ti.lpszText = NULL;
478 ti.lParam = 0x1abe11ed;
479 GetClientRect(hwnd, &ti.rect);
480 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
481 ok(r, "Adding the tool to the tooltip failed\n");
483 ti.cbSize = TTTOOLINFOA_V2_SIZE;
484 ti.lParam = 0xaaaaaaaa;
485 r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&ti);
486 ok(r, "Getting tooltip info failed\n");
487 ok(0x1abe11ed == ti.lParam ||
488 broken(0x1abe11ed != ti.lParam), /* comctl32 < 5.81 */
489 "Expected 0x1abe11ed, got %lx\n", ti.lParam);
491 tiW.cbSize = TTTOOLINFOW_V2_SIZE;
492 tiW.hwnd = NULL;
493 tiW.uId = 0x1234ABCD;
494 tiW.lParam = 0xaaaaaaaa;
495 tiW.lpszText = NULL;
496 r = SendMessageA(hwnd, TTM_GETTOOLINFOW, 0, (LPARAM)&tiW);
497 ok(r, "Getting tooltip info failed\n");
498 ok(0x1abe11ed == tiW.lParam ||
499 broken(0x1abe11ed != tiW.lParam), /* comctl32 < 5.81 */
500 "Expected 0x1abe11ed, got %lx\n", tiW.lParam);
502 ti.cbSize = TTTOOLINFOA_V2_SIZE;
503 ti.uId = 0x1234ABCD;
504 ti.lParam = 0x55555555;
505 SendMessageA(hwnd, TTM_SETTOOLINFOA, 0, (LPARAM)&ti);
507 ti.cbSize = TTTOOLINFOA_V2_SIZE;
508 ti.lParam = 0xdeadbeef;
509 r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&ti);
510 ok(r, "Getting tooltip info failed\n");
511 ok(0x55555555 == ti.lParam ||
512 broken(0x55555555 != ti.lParam), /* comctl32 < 5.81 */
513 "Expected 0x55555555, got %lx\n", ti.lParam);
515 DestroyWindow(hwnd);
517 /* 1. test size parameter validation rules (ansi messages) */
518 hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
519 10, 10, 300, 100,
520 NULL, NULL, NULL, 0);
522 ti.cbSize = TTTOOLINFOA_V1_SIZE - 1;
523 ti.hwnd = NULL;
524 ti.hinst = GetModuleHandleA(NULL);
525 ti.uFlags = 0;
526 ti.uId = 0x1234ABCD;
527 ti.lpszText = NULL;
528 ti.lParam = 0xdeadbeef;
529 GetClientRect(hwnd, &ti.rect);
530 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
531 ok(r, "Adding the tool to the tooltip failed\n");
532 r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
533 expect(1, r);
535 ti.cbSize = TTTOOLINFOA_V1_SIZE - 1;
536 ti.hwnd = NULL;
537 ti.uId = 0x1234ABCD;
538 SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti);
539 r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
540 expect(0, r);
542 ti.cbSize = TTTOOLINFOA_V2_SIZE - 1;
543 ti.hwnd = NULL;
544 ti.hinst = GetModuleHandleA(NULL);
545 ti.uFlags = 0;
546 ti.uId = 0x1234ABCD;
547 ti.lpszText = NULL;
548 ti.lParam = 0xdeadbeef;
549 GetClientRect(hwnd, &ti.rect);
550 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
551 ok(r, "Adding the tool to the tooltip failed\n");
552 r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
553 expect(1, r);
555 ti.cbSize = TTTOOLINFOA_V2_SIZE - 1;
556 ti.hwnd = NULL;
557 ti.uId = 0x1234ABCD;
558 SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti);
559 r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
560 expect(0, r);
562 ti.cbSize = TTTOOLINFOA_V2_SIZE + 1;
563 ti.hwnd = NULL;
564 ti.hinst = GetModuleHandleA(NULL);
565 ti.uFlags = 0;
566 ti.uId = 0x1234ABCD;
567 ti.lpszText = NULL;
568 ti.lParam = 0xdeadbeef;
569 GetClientRect(hwnd, &ti.rect);
570 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
571 ok(r, "Adding the tool to the tooltip failed\n");
572 r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
573 expect(1, r);
575 ti.cbSize = TTTOOLINFOA_V2_SIZE + 1;
576 ti.hwnd = NULL;
577 ti.uId = 0x1234ABCD;
578 SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti);
579 r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
580 expect(0, r);
582 DestroyWindow(hwnd);
584 /* 2. test size parameter validation rules (w-messages) */
585 hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0,
586 10, 10, 300, 100,
587 NULL, NULL, NULL, 0);
588 if(!hwnd)
590 win_skip("CreateWindowExW() not supported. Skipping.\n");
591 return;
594 tiW.cbSize = TTTOOLINFOW_V1_SIZE - 1;
595 tiW.hwnd = NULL;
596 tiW.hinst = GetModuleHandleA(NULL);
597 tiW.uFlags = 0;
598 tiW.uId = 0x1234ABCD;
599 tiW.lpszText = NULL;
600 tiW.lParam = 0xdeadbeef;
601 GetClientRect(hwnd, &tiW.rect);
602 r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&tiW);
603 ok(r, "Adding the tool to the tooltip failed\n");
604 r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
605 expect(1, r);
607 tiW.cbSize = TTTOOLINFOW_V1_SIZE - 1;
608 tiW.hwnd = NULL;
609 tiW.uId = 0x1234ABCD;
610 SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW);
611 r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
612 expect(0, r);
614 tiW.cbSize = TTTOOLINFOW_V2_SIZE - 1;
615 tiW.hwnd = NULL;
616 tiW.hinst = GetModuleHandleA(NULL);
617 tiW.uFlags = 0;
618 tiW.uId = 0x1234ABCD;
619 tiW.lpszText = NULL;
620 tiW.lParam = 0xdeadbeef;
621 GetClientRect(hwnd, &tiW.rect);
622 r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&tiW);
623 ok(r, "Adding the tool to the tooltip failed\n");
624 r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
625 expect(1, r);
627 tiW.cbSize = TTTOOLINFOW_V2_SIZE - 1;
628 tiW.hwnd = NULL;
629 tiW.uId = 0x1234ABCD;
630 SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW);
631 r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
632 expect(0, r);
634 tiW.cbSize = TTTOOLINFOW_V2_SIZE + 1;
635 tiW.hwnd = NULL;
636 tiW.hinst = GetModuleHandleA(NULL);
637 tiW.uFlags = 0;
638 tiW.uId = 0x1234ABCD;
639 tiW.lpszText = NULL;
640 tiW.lParam = 0xdeadbeef;
641 GetClientRect(hwnd, &tiW.rect);
642 r = SendMessageW(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&tiW);
643 ok(r, "Adding the tool to the tooltip failed\n");
644 r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
645 expect(1, r);
646 /* looks like TTM_DELTOOLW doesn't work with invalid size */
647 tiW.cbSize = TTTOOLINFOW_V2_SIZE + 1;
648 tiW.hwnd = NULL;
649 tiW.uId = 0x1234ABCD;
650 SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW);
651 r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
652 expect(1, r);
654 tiW.cbSize = TTTOOLINFOW_V2_SIZE;
655 tiW.hwnd = NULL;
656 tiW.uId = 0x1234ABCD;
657 SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW);
658 r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
659 expect(0, r);
661 DestroyWindow(hwnd);
664 static void test_longtextA(void)
666 static const char longtextA[] =
667 "According to MSDN, TTM_ENUMTOOLS claims that TOOLINFO's lpszText is maximum "
668 "80 chars including null. In fact, the buffer is not null-terminated.";
669 HWND hwnd;
670 TTTOOLINFOA toolinfoA = { 0 };
671 CHAR bufA[256];
672 LRESULT r;
674 hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
675 10, 10, 300, 100,
676 NULL, NULL, NULL, 0);
677 toolinfoA.cbSize = sizeof(TTTOOLINFOA);
678 toolinfoA.hwnd = NULL;
679 toolinfoA.hinst = GetModuleHandleA(NULL);
680 toolinfoA.uFlags = 0;
681 toolinfoA.uId = 0x1234ABCD;
682 strcpy(bufA, longtextA);
683 toolinfoA.lpszText = bufA;
684 toolinfoA.lParam = 0xdeadbeef;
685 GetClientRect(hwnd, &toolinfoA.rect);
686 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
687 if (r)
689 int textlen;
690 memset(bufA, 0, sizeof(bufA));
691 toolinfoA.hwnd = NULL;
692 toolinfoA.uId = 0xABCD1234;
693 toolinfoA.lpszText = bufA;
694 SendMessageA(hwnd, TTM_ENUMTOOLSA, 0, (LPARAM)&toolinfoA);
695 textlen = lstrlenA(toolinfoA.lpszText);
696 ok(textlen == 80, "lpszText has %d chars\n", textlen);
697 ok(toolinfoA.uId == 0x1234ABCD,
698 "uId should be retrieved, got %p\n", (void*)toolinfoA.uId);
700 memset(bufA, 0, sizeof(bufA));
701 toolinfoA.hwnd = NULL;
702 toolinfoA.uId = 0x1234ABCD;
703 toolinfoA.lpszText = bufA;
704 SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
705 textlen = lstrlenA(toolinfoA.lpszText);
706 ok(textlen == 80, "lpszText has %d chars\n", textlen);
708 memset(bufA, 0, sizeof(bufA));
709 toolinfoA.hwnd = NULL;
710 toolinfoA.uId = 0x1234ABCD;
711 toolinfoA.lpszText = bufA;
712 SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
713 textlen = lstrlenA(toolinfoA.lpszText);
714 ok(textlen == 80, "lpszText has %d chars\n", textlen);
717 DestroyWindow(hwnd);
720 static void test_longtextW(void)
722 static const char longtextA[] =
723 "According to MSDN, TTM_ENUMTOOLS claims that TOOLINFO's lpszText is maximum "
724 "80 chars including null. Actually, this is not applied for wide version.";
725 HWND hwnd;
726 TTTOOLINFOW toolinfoW = { 0 };
727 WCHAR bufW[256];
728 LRESULT r;
729 int lenW;
731 hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0,
732 10, 10, 300, 100,
733 NULL, NULL, NULL, 0);
734 if(!hwnd)
736 win_skip("CreateWindowExW() not supported. Skipping.\n");
737 return;
740 toolinfoW.cbSize = TTTOOLINFOW_V2_SIZE;
741 toolinfoW.hwnd = NULL;
742 toolinfoW.hinst = GetModuleHandleW(NULL);
743 toolinfoW.uFlags = 0;
744 toolinfoW.uId = 0x1234ABCD;
745 MultiByteToWideChar(CP_ACP, 0, longtextA, -1, bufW, sizeof(bufW)/sizeof(bufW[0]));
746 lenW = lstrlenW(bufW);
747 toolinfoW.lpszText = bufW;
748 toolinfoW.lParam = 0xdeadbeef;
749 GetClientRect(hwnd, &toolinfoW.rect);
750 r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&toolinfoW);
751 if (r)
753 int textlen;
754 memset(bufW, 0, sizeof(bufW));
755 toolinfoW.hwnd = NULL;
756 toolinfoW.uId = 0xABCD1234;
757 toolinfoW.lpszText = bufW;
758 SendMessageW(hwnd, TTM_ENUMTOOLSW, 0, (LPARAM)&toolinfoW);
759 textlen = lstrlenW(toolinfoW.lpszText);
760 ok(textlen == lenW, "lpszText has %d chars\n", textlen);
761 ok(toolinfoW.uId == 0x1234ABCD,
762 "uId should be retrieved, got %p\n", (void*)toolinfoW.uId);
764 memset(bufW, 0, sizeof(bufW));
765 toolinfoW.hwnd = NULL;
766 toolinfoW.uId = 0x1234ABCD;
767 toolinfoW.lpszText = bufW;
768 SendMessageW(hwnd, TTM_GETTOOLINFOW, 0, (LPARAM)&toolinfoW);
769 textlen = lstrlenW(toolinfoW.lpszText);
770 ok(textlen == lenW, "lpszText has %d chars\n", textlen);
772 memset(bufW, 0, sizeof(bufW));
773 toolinfoW.hwnd = NULL;
774 toolinfoW.uId = 0x1234ABCD;
775 toolinfoW.lpszText = bufW;
776 SendMessageW(hwnd, TTM_GETTEXTW, 0, (LPARAM)&toolinfoW);
777 textlen = lstrlenW(toolinfoW.lpszText);
778 ok(textlen == lenW ||
779 broken(textlen == 0 && toolinfoW.lpszText == NULL), /* nt4, kb186177 */
780 "lpszText has %d chars\n", textlen);
783 DestroyWindow(hwnd);
786 static BOOL almost_eq(int a, int b)
788 return a-5<b && a+5>b;
791 static void test_track(void)
793 WCHAR textW[] = {'t','e','x','t',0};
794 TTTOOLINFOW info = { 0 };
795 HWND parent, tt;
796 LRESULT res;
797 RECT pos;
799 parent = CreateWindowExW(0, WC_STATICW, NULL, WS_CAPTION | WS_VISIBLE,
800 50, 50, 300, 300, NULL, NULL, NULL, 0);
801 ok(parent != NULL, "creation of parent window failed\n");
803 ShowWindow(parent, SW_SHOWNORMAL);
804 flush_events(100);
806 tt = CreateWindowExW(WS_EX_TOPMOST, TOOLTIPS_CLASSW, NULL, TTS_NOPREFIX | TTS_ALWAYSTIP,
807 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
808 parent, NULL, GetModuleHandleW(NULL), 0);
809 ok(tt != NULL, "creation of tooltip window failed\n");
811 info.cbSize = TTTOOLINFOW_V1_SIZE;
812 info.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
813 info.hwnd = parent;
814 info.hinst = GetModuleHandleW(NULL);
815 info.lpszText = textW;
816 info.uId = (UINT_PTR)parent;
817 GetClientRect(parent, &info.rect);
819 res = SendMessageW(tt, TTM_ADDTOOLW, 0, (LPARAM)&info);
820 ok(res, "adding the tool to the tooltip failed\n");
822 SendMessageW(tt, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1,0));
823 SendMessageW(tt, TTM_TRACKACTIVATE, (WPARAM)TRUE, (LPARAM)&info);
824 SendMessageW(tt, TTM_TRACKPOSITION, 0, MAKELPARAM(10, 10));
826 GetWindowRect(tt, &pos);
827 ok(almost_eq(pos.left, 10), "pos.left = %d\n", pos.left);
828 ok(almost_eq(pos.top, 10), "pos.top = %d\n", pos.top);
830 info.uFlags = TTF_IDISHWND | TTF_ABSOLUTE;
831 SendMessageW(tt, TTM_SETTOOLINFOW, 0, (LPARAM)&info);
832 SendMessageW(tt, TTM_TRACKPOSITION, 0, MAKELPARAM(10, 10));
834 GetWindowRect(tt, &pos);
835 ok(!almost_eq(pos.left, 10), "pos.left = %d\n", pos.left);
836 ok(!almost_eq(pos.top, 10), "pos.top = %d\n", pos.top);
838 DestroyWindow(tt);
839 DestroyWindow(parent);
842 static LRESULT CALLBACK info_wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
844 switch(msg) {
846 case WM_DESTROY:
847 PostQuitMessage(0);
848 break;
850 default:
851 return DefWindowProcA(hWnd, msg, wParam, lParam);
853 return 0;
856 static void test_setinfo(void)
858 WNDCLASSA wc;
859 LRESULT lResult;
860 HWND parent, parent2, hwndTip, hwndTip2;
861 TTTOOLINFOA toolInfo = { 0 };
862 TTTOOLINFOA toolInfo2 = { 0 };
863 WNDPROC wndProc;
865 /* Create a class to use the custom draw wndproc */
866 wc.style = CS_HREDRAW | CS_VREDRAW;
867 wc.cbClsExtra = 0;
868 wc.cbWndExtra = 0;
869 wc.hInstance = GetModuleHandleA(NULL);
870 wc.hIcon = NULL;
871 wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
872 wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
873 wc.lpszMenuName = NULL;
874 wc.lpszClassName = "SetInfoClass";
875 wc.lpfnWndProc = info_wnd_proc;
876 RegisterClassA(&wc);
878 /* Create a main window */
879 parent = CreateWindowExA(0, "SetInfoClass", NULL,
880 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
881 WS_MAXIMIZEBOX | WS_VISIBLE,
882 50, 50,
883 300, 300,
884 NULL, NULL, NULL, 0);
885 ok(parent != NULL, "Creation of main window failed\n");
887 parent2 = CreateWindowExA(0, "SetInfoClass", NULL,
888 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
889 WS_MAXIMIZEBOX | WS_VISIBLE,
890 50, 50,
891 300, 300,
892 NULL, NULL, NULL, 0);
893 ok(parent2 != NULL, "Creation of main window failed\n");
895 /* Make it show */
896 ShowWindow(parent2, SW_SHOWNORMAL);
897 flush_events(100);
899 /* Create Tooltip */
900 hwndTip = CreateWindowExA(WS_EX_TOPMOST, TOOLTIPS_CLASSA,
901 NULL, TTS_NOPREFIX | TTS_ALWAYSTIP,
902 CW_USEDEFAULT, CW_USEDEFAULT,
903 CW_USEDEFAULT, CW_USEDEFAULT,
904 parent, NULL, GetModuleHandleA(NULL), 0);
905 ok(hwndTip != NULL, "Creation of tooltip window failed\n");
907 hwndTip2 = CreateWindowExA(WS_EX_TOPMOST, TOOLTIPS_CLASSA,
908 NULL, TTS_NOPREFIX | TTS_ALWAYSTIP,
909 CW_USEDEFAULT, CW_USEDEFAULT,
910 CW_USEDEFAULT, CW_USEDEFAULT,
911 parent, NULL, GetModuleHandleA(NULL), 0);
912 ok(hwndTip2 != NULL, "Creation of tooltip window failed\n");
915 /* Make it topmost, as per the MSDN */
916 SetWindowPos(hwndTip, HWND_TOPMOST, 0, 0, 0, 0,
917 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
919 /* Create a tool */
920 toolInfo.cbSize = TTTOOLINFOA_V1_SIZE;
921 toolInfo.hwnd = parent;
922 toolInfo.hinst = GetModuleHandleA(NULL);
923 toolInfo.uFlags = TTF_SUBCLASS;
924 toolInfo.uId = 0x1234ABCD;
925 toolInfo.lpszText = (LPSTR)"This is a test tooltip";
926 toolInfo.lParam = 0xdeadbeef;
927 GetClientRect (parent, &toolInfo.rect);
928 lResult = SendMessageA(hwndTip, TTM_ADDTOOLA, 0, (LPARAM)&toolInfo);
929 ok(lResult, "Adding the tool to the tooltip failed\n");
931 toolInfo.cbSize = TTTOOLINFOA_V1_SIZE;
932 toolInfo.hwnd = parent2;
933 toolInfo.hinst = GetModuleHandleA(NULL);
934 toolInfo.uFlags = 0;
935 toolInfo.uId = 0x1234ABCE;
936 toolInfo.lpszText = (LPSTR)"This is a test tooltip";
937 toolInfo.lParam = 0xdeadbeef;
938 GetClientRect (parent, &toolInfo.rect);
939 lResult = SendMessageA(hwndTip, TTM_ADDTOOLA, 0, (LPARAM)&toolInfo);
940 ok(lResult, "Adding the tool to the tooltip failed\n");
942 /* Try to Remove Subclass */
943 toolInfo2.cbSize = TTTOOLINFOA_V1_SIZE;
944 toolInfo2.hwnd = parent;
945 toolInfo2.uId = 0x1234ABCD;
946 lResult = SendMessageA(hwndTip, TTM_GETTOOLINFOA, 0, (LPARAM)&toolInfo2);
947 ok(lResult, "GetToolInfo failed\n");
948 ok(toolInfo2.uFlags & TTF_SUBCLASS, "uFlags does not have subclass\n");
949 wndProc = (WNDPROC)GetWindowLongPtrA(parent, GWLP_WNDPROC);
950 ok (wndProc != info_wnd_proc, "Window Proc is wrong\n");
952 toolInfo2.uFlags &= ~TTF_SUBCLASS;
953 SendMessageA(hwndTip, TTM_SETTOOLINFOA, 0, (LPARAM)&toolInfo2);
954 lResult = SendMessageA(hwndTip, TTM_GETTOOLINFOA, 0, (LPARAM)&toolInfo2);
955 ok(lResult, "GetToolInfo failed\n");
956 ok(!(toolInfo2.uFlags & TTF_SUBCLASS), "uFlags has subclass\n");
957 wndProc = (WNDPROC)GetWindowLongPtrA(parent, GWLP_WNDPROC);
958 ok (wndProc != info_wnd_proc, "Window Proc is wrong\n");
960 /* Try to Add Subclass */
962 /* Make it topmost, as per the MSDN */
963 SetWindowPos(hwndTip2, HWND_TOPMOST, 0, 0, 0, 0,
964 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
966 toolInfo2.cbSize = TTTOOLINFOA_V1_SIZE;
967 toolInfo2.hwnd = parent2;
968 toolInfo2.uId = 0x1234ABCE;
969 lResult = SendMessageA(hwndTip, TTM_GETTOOLINFOA, 0, (LPARAM)&toolInfo2);
970 ok(lResult, "GetToolInfo failed\n");
971 ok(!(toolInfo2.uFlags & TTF_SUBCLASS), "uFlags has subclass\n");
972 wndProc = (WNDPROC)GetWindowLongPtrA(parent2, GWLP_WNDPROC);
973 ok (wndProc == info_wnd_proc, "Window Proc is wrong\n");
975 toolInfo2.uFlags |= TTF_SUBCLASS;
976 SendMessageA(hwndTip, TTM_SETTOOLINFOA, 0, (LPARAM)&toolInfo2);
977 lResult = SendMessageA(hwndTip, TTM_GETTOOLINFOA, 0, (LPARAM)&toolInfo2);
978 ok(lResult, "GetToolInfo failed\n");
979 ok(toolInfo2.uFlags & TTF_SUBCLASS, "uFlags does not have subclass\n");
980 wndProc = (WNDPROC)GetWindowLongPtrA(parent2, GWLP_WNDPROC);
981 ok (wndProc == info_wnd_proc, "Window Proc is wrong\n");
983 /* Clean up */
984 DestroyWindow(hwndTip);
985 DestroyWindow(hwndTip2);
986 DestroyWindow(parent);
987 DestroyWindow(parent2);
990 START_TEST(tooltips)
992 InitCommonControls();
994 test_create_tooltip();
995 test_customdraw();
996 test_gettext();
997 test_ttm_gettoolinfo();
998 test_longtextA();
999 test_longtextW();
1000 test_track();
1001 test_setinfo();