ole32: Make CoCreateInstance hookable for Steam.
[wine/multimedia.git] / dlls / comctl32 / tests / tooltips.c
blob2766354c3ec83a6f87e0f46683fa2fa658fcf400
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 "wine/test.h"
25 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
27 static void test_create_tooltip(void)
29 HWND parent, hwnd;
30 DWORD style, exp_style;
32 parent = CreateWindowExA(0, "static", NULL, WS_POPUP,
33 0, 0, 0, 0,
34 NULL, NULL, NULL, 0);
35 ok(parent != NULL, "failed to create parent wnd\n");
37 hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0x7fffffff | WS_POPUP,
38 10, 10, 300, 100,
39 parent, NULL, NULL, 0);
40 ok(hwnd != NULL, "failed to create tooltip wnd\n");
42 style = GetWindowLongA(hwnd, GWL_STYLE);
43 trace("style = %08x\n", style);
44 exp_style = 0x7fffffff | WS_POPUP;
45 exp_style &= ~(WS_CHILD | WS_MAXIMIZE | WS_BORDER | WS_DLGFRAME);
46 ok(style == exp_style || broken(style == (exp_style | WS_BORDER)), /* nt4 */
47 "wrong style %08x/%08x\n", style, exp_style);
49 DestroyWindow(hwnd);
51 hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
52 10, 10, 300, 100,
53 parent, NULL, NULL, 0);
54 ok(hwnd != NULL, "failed to create tooltip wnd\n");
56 style = GetWindowLongA(hwnd, GWL_STYLE);
57 trace("style = %08x\n", style);
58 ok(style == (WS_POPUP | WS_CLIPSIBLINGS | WS_BORDER),
59 "wrong style %08x\n", style);
61 DestroyWindow(hwnd);
63 DestroyWindow(parent);
66 /* try to make sure pending X events have been processed before continuing */
67 static void flush_events(int waitTime)
69 MSG msg;
70 int diff = waitTime;
71 DWORD time = GetTickCount() + waitTime;
73 while (diff > 0)
75 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min(100,diff), QS_ALLEVENTS) == WAIT_TIMEOUT) break;
76 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
77 diff = time - GetTickCount();
81 static int CD_Stages;
82 static LRESULT CD_Result;
83 static HWND g_hwnd;
85 #define TEST_CDDS_PREPAINT 0x00000001
86 #define TEST_CDDS_POSTPAINT 0x00000002
87 #define TEST_CDDS_PREERASE 0x00000004
88 #define TEST_CDDS_POSTERASE 0x00000008
89 #define TEST_CDDS_ITEMPREPAINT 0x00000010
90 #define TEST_CDDS_ITEMPOSTPAINT 0x00000020
91 #define TEST_CDDS_ITEMPREERASE 0x00000040
92 #define TEST_CDDS_ITEMPOSTERASE 0x00000080
93 #define TEST_CDDS_SUBITEM 0x00000100
95 static LRESULT CALLBACK custom_draw_wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
97 switch(msg) {
99 case WM_DESTROY:
100 PostQuitMessage(0);
101 break;
103 case WM_NOTIFY:
104 if (((NMHDR *)lParam)->code == NM_CUSTOMDRAW) {
105 NMTTCUSTOMDRAW *ttcd = (NMTTCUSTOMDRAW*) lParam;
106 ok(ttcd->nmcd.hdr.hwndFrom == g_hwnd, "Unexpected hwnd source %p (%p)\n",
107 ttcd->nmcd.hdr.hwndFrom, g_hwnd);
108 ok(ttcd->nmcd.hdr.idFrom == 0x1234ABCD, "Unexpected id %x\n", (int)ttcd->nmcd.hdr.idFrom);
110 switch (ttcd->nmcd.dwDrawStage) {
111 case CDDS_PREPAINT : CD_Stages |= TEST_CDDS_PREPAINT; break;
112 case CDDS_POSTPAINT : CD_Stages |= TEST_CDDS_POSTPAINT; break;
113 case CDDS_PREERASE : CD_Stages |= TEST_CDDS_PREERASE; break;
114 case CDDS_POSTERASE : CD_Stages |= TEST_CDDS_POSTERASE; break;
115 case CDDS_ITEMPREPAINT : CD_Stages |= TEST_CDDS_ITEMPREPAINT; break;
116 case CDDS_ITEMPOSTPAINT: CD_Stages |= TEST_CDDS_ITEMPOSTPAINT; break;
117 case CDDS_ITEMPREERASE : CD_Stages |= TEST_CDDS_ITEMPREERASE; break;
118 case CDDS_ITEMPOSTERASE: CD_Stages |= TEST_CDDS_ITEMPOSTERASE; break;
119 case CDDS_SUBITEM : CD_Stages |= TEST_CDDS_SUBITEM; break;
120 default: CD_Stages = -1;
123 if (ttcd->nmcd.dwDrawStage == CDDS_PREPAINT) return CD_Result;
125 /* drop through */
127 default:
128 return DefWindowProcA(hWnd, msg, wParam, lParam);
131 return 0L;
134 static void test_customdraw(void) {
135 static struct {
136 LRESULT FirstReturnValue;
137 int ExpectedCalls;
138 } expectedResults[] = {
139 /* Valid notification responses */
140 {CDRF_DODEFAULT, TEST_CDDS_PREPAINT},
141 {CDRF_SKIPDEFAULT, TEST_CDDS_PREPAINT},
142 {CDRF_NOTIFYPOSTPAINT, TEST_CDDS_PREPAINT | TEST_CDDS_POSTPAINT},
144 /* Invalid notification responses */
145 {CDRF_NOTIFYITEMDRAW, TEST_CDDS_PREPAINT},
146 {CDRF_NOTIFYPOSTERASE, TEST_CDDS_PREPAINT},
147 {CDRF_NEWFONT, TEST_CDDS_PREPAINT}
150 DWORD iterationNumber;
151 WNDCLASSA wc;
152 LRESULT lResult;
154 /* Create a class to use the custom draw wndproc */
155 wc.style = CS_HREDRAW | CS_VREDRAW;
156 wc.cbClsExtra = 0;
157 wc.cbWndExtra = 0;
158 wc.hInstance = GetModuleHandleA(NULL);
159 wc.hIcon = NULL;
160 wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
161 wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
162 wc.lpszMenuName = NULL;
163 wc.lpszClassName = "CustomDrawClass";
164 wc.lpfnWndProc = custom_draw_wnd_proc;
165 RegisterClassA(&wc);
167 for (iterationNumber = 0;
168 iterationNumber < sizeof(expectedResults)/sizeof(expectedResults[0]);
169 iterationNumber++) {
171 HWND parent, hwndTip;
172 RECT rect;
173 TTTOOLINFOA toolInfo = { 0 };
175 /* Create a main window */
176 parent = CreateWindowExA(0, "CustomDrawClass", NULL,
177 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
178 WS_MAXIMIZEBOX | WS_VISIBLE,
179 50, 50,
180 300, 300,
181 NULL, NULL, NULL, 0);
182 ok(parent != NULL, "Creation of main window failed\n");
184 /* Make it show */
185 ShowWindow(parent, SW_SHOWNORMAL);
186 flush_events(100);
188 /* Create Tooltip */
189 hwndTip = CreateWindowExA(WS_EX_TOPMOST, TOOLTIPS_CLASSA,
190 NULL, TTS_NOPREFIX | TTS_ALWAYSTIP,
191 CW_USEDEFAULT, CW_USEDEFAULT,
192 CW_USEDEFAULT, CW_USEDEFAULT,
193 parent, NULL, GetModuleHandleA(NULL), 0);
194 ok(hwndTip != NULL, "Creation of tooltip window failed\n");
196 /* Set up parms for the wndproc to handle */
197 CD_Stages = 0;
198 CD_Result = expectedResults[iterationNumber].FirstReturnValue;
199 g_hwnd = hwndTip;
201 /* Make it topmost, as per the MSDN */
202 SetWindowPos(hwndTip, HWND_TOPMOST, 0, 0, 0, 0,
203 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
205 /* Create a tool */
206 toolInfo.cbSize = TTTOOLINFOA_V1_SIZE;
207 toolInfo.hwnd = parent;
208 toolInfo.hinst = GetModuleHandleA(NULL);
209 toolInfo.uFlags = TTF_SUBCLASS;
210 toolInfo.uId = 0x1234ABCD;
211 toolInfo.lpszText = (LPSTR)"This is a test tooltip";
212 toolInfo.lParam = 0xdeadbeef;
213 GetClientRect (parent, &toolInfo.rect);
214 lResult = SendMessageA(hwndTip, TTM_ADDTOOLA, 0, (LPARAM)&toolInfo);
215 ok(lResult, "Adding the tool to the tooltip failed\n");
217 /* Make tooltip appear quickly */
218 SendMessageA(hwndTip, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1,0));
220 /* Put cursor inside window, tooltip will appear immediately */
221 GetWindowRect( parent, &rect );
222 SetCursorPos( (rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2 );
223 flush_events(200);
225 if (CD_Stages)
227 /* Check CustomDraw results */
228 ok(CD_Stages == expectedResults[iterationNumber].ExpectedCalls ||
229 broken(CD_Stages == (expectedResults[iterationNumber].ExpectedCalls & ~TEST_CDDS_POSTPAINT)), /* nt4 */
230 "CustomDraw run %d stages %x, expected %x\n", iterationNumber, CD_Stages,
231 expectedResults[iterationNumber].ExpectedCalls);
234 /* Clean up */
235 DestroyWindow(hwndTip);
236 DestroyWindow(parent);
242 static const CHAR testcallbackA[] = "callback";
244 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
246 if (message == WM_NOTIFY && lParam)
248 NMTTDISPINFOA *ttnmdi = (NMTTDISPINFOA*)lParam;
250 if (ttnmdi->hdr.code == TTN_GETDISPINFOA)
251 lstrcpyA(ttnmdi->lpszText, testcallbackA);
254 return DefWindowProcA(hwnd, message, wParam, lParam);
257 static BOOL register_parent_wnd_class(void)
259 WNDCLASSA cls;
261 cls.style = 0;
262 cls.lpfnWndProc = parent_wnd_proc;
263 cls.cbClsExtra = 0;
264 cls.cbWndExtra = 0;
265 cls.hInstance = GetModuleHandleA(NULL);
266 cls.hIcon = 0;
267 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
268 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
269 cls.lpszMenuName = NULL;
270 cls.lpszClassName = "Tooltips test parent class";
271 return RegisterClassA(&cls);
274 static HWND create_parent_window(void)
276 if (!register_parent_wnd_class())
277 return NULL;
279 return CreateWindowExA(0, "Tooltips test parent class",
280 "Tooltips test parent window",
281 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
282 WS_MAXIMIZEBOX | WS_VISIBLE,
283 0, 0, 100, 100,
284 GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
287 static void test_gettext(void)
289 HWND hwnd, notify;
290 TTTOOLINFOA toolinfoA;
291 TTTOOLINFOW toolinfoW;
292 LRESULT r;
293 CHAR bufA[10] = "";
294 WCHAR bufW[10] = { 0 };
295 static const CHAR testtipA[] = "testtip";
297 notify = create_parent_window();
298 ok(notify != NULL, "Expected notification window to be created\n");
300 /* For bug 14790 - lpszText is NULL */
301 hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
302 10, 10, 300, 100,
303 NULL, NULL, NULL, 0);
304 ok(hwnd != NULL, "failed to create tooltip wnd\n");
306 /* use sizeof(TTTOOLINFOA) instead of TTTOOLINFOA_V1_SIZE so that adding it fails on Win9x */
307 /* otherwise it crashes on the NULL lpszText */
308 toolinfoA.cbSize = sizeof(TTTOOLINFOA);
309 toolinfoA.hwnd = NULL;
310 toolinfoA.hinst = GetModuleHandleA(NULL);
311 toolinfoA.uFlags = 0;
312 toolinfoA.uId = 0x1234ABCD;
313 toolinfoA.lpszText = NULL;
314 toolinfoA.lParam = 0xdeadbeef;
315 GetClientRect(hwnd, &toolinfoA.rect);
316 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
317 if (r)
319 toolinfoA.hwnd = NULL;
320 toolinfoA.uId = 0x1234ABCD;
321 toolinfoA.lpszText = bufA;
322 SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
323 ok(strcmp(toolinfoA.lpszText, "") == 0, "lpszText should be an empty string\n");
325 toolinfoA.lpszText = bufA;
326 SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
327 ok(toolinfoA.lpszText == NULL,
328 "expected NULL, got %p\n", toolinfoA.lpszText);
330 else
332 win_skip( "Old comctl32, not testing NULL text\n" );
333 DestroyWindow( hwnd );
334 return;
337 /* add another tool with text */
338 toolinfoA.cbSize = sizeof(TTTOOLINFOA);
339 toolinfoA.hwnd = NULL;
340 toolinfoA.hinst = GetModuleHandleA(NULL);
341 toolinfoA.uFlags = 0;
342 toolinfoA.uId = 0x1235ABCD;
343 strcpy(bufA, testtipA);
344 toolinfoA.lpszText = bufA;
345 toolinfoA.lParam = 0xdeadbeef;
346 GetClientRect(hwnd, &toolinfoA.rect);
347 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
348 ok(r, "Adding the tool to the tooltip failed\n");
349 if (r)
351 DWORD length;
353 length = SendMessageA(hwnd, WM_GETTEXTLENGTH, 0, 0);
354 ok(length == 0, "Expected 0, got %d\n", length);
356 toolinfoA.hwnd = NULL;
357 toolinfoA.uId = 0x1235ABCD;
358 toolinfoA.lpszText = bufA;
359 SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
360 ok(strcmp(toolinfoA.lpszText, testtipA) == 0, "lpszText should be an empty string\n");
362 memset(bufA, 0x1f, sizeof(bufA));
363 toolinfoA.lpszText = bufA;
364 SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
365 ok(strcmp(toolinfoA.lpszText, testtipA) == 0,
366 "expected %s, got %p\n", testtipA, toolinfoA.lpszText);
368 length = SendMessageA(hwnd, WM_GETTEXTLENGTH, 0, 0);
369 ok(length == 0, "Expected 0, got %d\n", length);
372 /* add another with callback text */
373 toolinfoA.cbSize = sizeof(TTTOOLINFOA);
374 toolinfoA.hwnd = notify;
375 toolinfoA.hinst = GetModuleHandleA(NULL);
376 toolinfoA.uFlags = 0;
377 toolinfoA.uId = 0x1236ABCD;
378 toolinfoA.lpszText = LPSTR_TEXTCALLBACKA;
379 toolinfoA.lParam = 0xdeadbeef;
380 GetClientRect(hwnd, &toolinfoA.rect);
381 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
382 ok(r, "Adding the tool to the tooltip failed\n");
383 if (r)
385 toolinfoA.hwnd = notify;
386 toolinfoA.uId = 0x1236ABCD;
387 toolinfoA.lpszText = bufA;
388 SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
389 ok(strcmp(toolinfoA.lpszText, testcallbackA) == 0,
390 "lpszText should be an (%s) string\n", testcallbackA);
392 toolinfoA.lpszText = bufA;
393 SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
394 ok(toolinfoA.lpszText == LPSTR_TEXTCALLBACKA,
395 "expected LPSTR_TEXTCALLBACKA, got %p\n", toolinfoA.lpszText);
398 DestroyWindow(hwnd);
399 DestroyWindow(notify);
401 SetLastError(0xdeadbeef);
402 hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0,
403 10, 10, 300, 100,
404 NULL, NULL, NULL, 0);
406 if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
407 win_skip("CreateWindowExW is not implemented\n");
408 return;
410 ok(hwnd != NULL, "failed to create tooltip wnd\n");
412 toolinfoW.cbSize = sizeof(TTTOOLINFOW);
413 toolinfoW.hwnd = NULL;
414 toolinfoW.hinst = GetModuleHandleA(NULL);
415 toolinfoW.uFlags = 0;
416 toolinfoW.uId = 0x1234ABCD;
417 toolinfoW.lpszText = NULL;
418 toolinfoW.lParam = 0xdeadbeef;
419 GetClientRect(hwnd, &toolinfoW.rect);
420 r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&toolinfoW);
421 ok(!r, "Adding the tool to the tooltip succeeded!\n");
423 if (0) /* crashes on NT4 */
425 toolinfoW.hwnd = NULL;
426 toolinfoW.uId = 0x1234ABCD;
427 toolinfoW.lpszText = bufW;
428 SendMessageW(hwnd, TTM_GETTEXTW, 0, (LPARAM)&toolinfoW);
429 ok(toolinfoW.lpszText[0] == 0, "lpszText should be an empty string\n");
432 DestroyWindow(hwnd);
435 static void test_ttm_gettoolinfo(void)
437 TTTOOLINFOA ti;
438 TTTOOLINFOW tiW;
439 HWND hwnd;
440 DWORD r;
442 hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
443 10, 10, 300, 100,
444 NULL, NULL, NULL, 0);
446 ti.cbSize = TTTOOLINFOA_V2_SIZE;
447 ti.hwnd = NULL;
448 ti.hinst = GetModuleHandleA(NULL);
449 ti.uFlags = 0;
450 ti.uId = 0x1234ABCD;
451 ti.lpszText = NULL;
452 ti.lParam = 0x1abe11ed;
453 GetClientRect(hwnd, &ti.rect);
454 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
455 ok(r, "Adding the tool to the tooltip failed\n");
457 ti.cbSize = TTTOOLINFOA_V2_SIZE;
458 ti.lParam = 0xaaaaaaaa;
459 r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&ti);
460 ok(r, "Getting tooltip info failed\n");
461 ok(0x1abe11ed == ti.lParam ||
462 broken(0x1abe11ed != ti.lParam), /* comctl32 < 5.81 */
463 "Expected 0x1abe11ed, got %lx\n", ti.lParam);
465 tiW.cbSize = TTTOOLINFOW_V2_SIZE;
466 tiW.hwnd = NULL;
467 tiW.uId = 0x1234ABCD;
468 tiW.lParam = 0xaaaaaaaa;
469 r = SendMessageA(hwnd, TTM_GETTOOLINFOW, 0, (LPARAM)&tiW);
470 ok(r, "Getting tooltip info failed\n");
471 ok(0x1abe11ed == tiW.lParam ||
472 broken(0x1abe11ed != tiW.lParam), /* comctl32 < 5.81 */
473 "Expected 0x1abe11ed, got %lx\n", tiW.lParam);
475 ti.cbSize = TTTOOLINFOA_V2_SIZE;
476 ti.uId = 0x1234ABCD;
477 ti.lParam = 0x55555555;
478 SendMessageA(hwnd, TTM_SETTOOLINFOA, 0, (LPARAM)&ti);
480 ti.cbSize = TTTOOLINFOA_V2_SIZE;
481 ti.lParam = 0xdeadbeef;
482 r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&ti);
483 ok(r, "Getting tooltip info failed\n");
484 ok(0x55555555 == ti.lParam ||
485 broken(0x55555555 != ti.lParam), /* comctl32 < 5.81 */
486 "Expected 0x55555555, got %lx\n", ti.lParam);
488 DestroyWindow(hwnd);
490 /* 1. test size parameter validation rules (ansi messages) */
491 hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
492 10, 10, 300, 100,
493 NULL, NULL, NULL, 0);
495 ti.cbSize = TTTOOLINFOA_V1_SIZE - 1;
496 ti.hwnd = NULL;
497 ti.hinst = GetModuleHandleA(NULL);
498 ti.uFlags = 0;
499 ti.uId = 0x1234ABCD;
500 ti.lpszText = NULL;
501 ti.lParam = 0xdeadbeef;
502 GetClientRect(hwnd, &ti.rect);
503 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
504 ok(r, "Adding the tool to the tooltip failed\n");
505 r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
506 expect(1, r);
508 ti.cbSize = TTTOOLINFOA_V1_SIZE - 1;
509 ti.hwnd = NULL;
510 ti.uId = 0x1234ABCD;
511 SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti);
512 r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
513 expect(0, r);
515 ti.cbSize = TTTOOLINFOA_V2_SIZE - 1;
516 ti.hwnd = NULL;
517 ti.hinst = GetModuleHandleA(NULL);
518 ti.uFlags = 0;
519 ti.uId = 0x1234ABCD;
520 ti.lpszText = NULL;
521 ti.lParam = 0xdeadbeef;
522 GetClientRect(hwnd, &ti.rect);
523 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
524 ok(r, "Adding the tool to the tooltip failed\n");
525 r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
526 expect(1, r);
528 ti.cbSize = TTTOOLINFOA_V2_SIZE - 1;
529 ti.hwnd = NULL;
530 ti.uId = 0x1234ABCD;
531 SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti);
532 r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
533 expect(0, r);
535 ti.cbSize = TTTOOLINFOA_V2_SIZE + 1;
536 ti.hwnd = NULL;
537 ti.hinst = GetModuleHandleA(NULL);
538 ti.uFlags = 0;
539 ti.uId = 0x1234ABCD;
540 ti.lpszText = NULL;
541 ti.lParam = 0xdeadbeef;
542 GetClientRect(hwnd, &ti.rect);
543 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
544 ok(r, "Adding the tool to the tooltip failed\n");
545 r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
546 expect(1, r);
548 ti.cbSize = TTTOOLINFOA_V2_SIZE + 1;
549 ti.hwnd = NULL;
550 ti.uId = 0x1234ABCD;
551 SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti);
552 r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
553 expect(0, r);
555 DestroyWindow(hwnd);
557 /* 2. test size parameter validation rules (w-messages) */
558 hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0,
559 10, 10, 300, 100,
560 NULL, NULL, NULL, 0);
561 if(!hwnd)
563 win_skip("CreateWindowExW() not supported. Skipping.\n");
564 return;
567 tiW.cbSize = TTTOOLINFOW_V1_SIZE - 1;
568 tiW.hwnd = NULL;
569 tiW.hinst = GetModuleHandleA(NULL);
570 tiW.uFlags = 0;
571 tiW.uId = 0x1234ABCD;
572 tiW.lpszText = NULL;
573 tiW.lParam = 0xdeadbeef;
574 GetClientRect(hwnd, &tiW.rect);
575 r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&tiW);
576 ok(r, "Adding the tool to the tooltip failed\n");
577 r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
578 expect(1, r);
580 tiW.cbSize = TTTOOLINFOW_V1_SIZE - 1;
581 tiW.hwnd = NULL;
582 tiW.uId = 0x1234ABCD;
583 SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW);
584 r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
585 expect(0, r);
587 tiW.cbSize = TTTOOLINFOW_V2_SIZE - 1;
588 tiW.hwnd = NULL;
589 tiW.hinst = GetModuleHandleA(NULL);
590 tiW.uFlags = 0;
591 tiW.uId = 0x1234ABCD;
592 tiW.lpszText = NULL;
593 tiW.lParam = 0xdeadbeef;
594 GetClientRect(hwnd, &tiW.rect);
595 r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&tiW);
596 ok(r, "Adding the tool to the tooltip failed\n");
597 r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
598 expect(1, r);
600 tiW.cbSize = TTTOOLINFOW_V2_SIZE - 1;
601 tiW.hwnd = NULL;
602 tiW.uId = 0x1234ABCD;
603 SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW);
604 r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
605 expect(0, r);
607 tiW.cbSize = TTTOOLINFOW_V2_SIZE + 1;
608 tiW.hwnd = NULL;
609 tiW.hinst = GetModuleHandleA(NULL);
610 tiW.uFlags = 0;
611 tiW.uId = 0x1234ABCD;
612 tiW.lpszText = NULL;
613 tiW.lParam = 0xdeadbeef;
614 GetClientRect(hwnd, &tiW.rect);
615 r = SendMessageW(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&tiW);
616 ok(r, "Adding the tool to the tooltip failed\n");
617 r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
618 expect(1, r);
619 /* looks like TTM_DELTOOLW doesn't work with invalid size */
620 tiW.cbSize = TTTOOLINFOW_V2_SIZE + 1;
621 tiW.hwnd = NULL;
622 tiW.uId = 0x1234ABCD;
623 SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW);
624 r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
625 expect(1, r);
627 tiW.cbSize = TTTOOLINFOW_V2_SIZE;
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 DestroyWindow(hwnd);
637 static void test_longtextA(void)
639 static const char longtextA[] =
640 "According to MSDN, TTM_ENUMTOOLS claims that TOOLINFO's lpszText is maximum "
641 "80 chars including null. In fact, the buffer is not null-terminated.";
642 HWND hwnd;
643 TTTOOLINFOA toolinfoA = { 0 };
644 CHAR bufA[256];
645 LRESULT r;
647 hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
648 10, 10, 300, 100,
649 NULL, NULL, NULL, 0);
650 toolinfoA.cbSize = sizeof(TTTOOLINFOA);
651 toolinfoA.hwnd = NULL;
652 toolinfoA.hinst = GetModuleHandleA(NULL);
653 toolinfoA.uFlags = 0;
654 toolinfoA.uId = 0x1234ABCD;
655 strcpy(bufA, longtextA);
656 toolinfoA.lpszText = bufA;
657 toolinfoA.lParam = 0xdeadbeef;
658 GetClientRect(hwnd, &toolinfoA.rect);
659 r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
660 if (r)
662 int textlen;
663 memset(bufA, 0, sizeof(bufA));
664 toolinfoA.hwnd = NULL;
665 toolinfoA.uId = 0xABCD1234;
666 toolinfoA.lpszText = bufA;
667 SendMessageA(hwnd, TTM_ENUMTOOLSA, 0, (LPARAM)&toolinfoA);
668 textlen = lstrlenA(toolinfoA.lpszText);
669 ok(textlen == 80, "lpszText has %d chars\n", textlen);
670 ok(toolinfoA.uId == 0x1234ABCD,
671 "uId should be retrieved, got %p\n", (void*)toolinfoA.uId);
673 memset(bufA, 0, sizeof(bufA));
674 toolinfoA.hwnd = NULL;
675 toolinfoA.uId = 0x1234ABCD;
676 toolinfoA.lpszText = bufA;
677 SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
678 textlen = lstrlenA(toolinfoA.lpszText);
679 ok(textlen == 80, "lpszText has %d chars\n", textlen);
681 memset(bufA, 0, sizeof(bufA));
682 toolinfoA.hwnd = NULL;
683 toolinfoA.uId = 0x1234ABCD;
684 toolinfoA.lpszText = bufA;
685 SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
686 textlen = lstrlenA(toolinfoA.lpszText);
687 ok(textlen == 80, "lpszText has %d chars\n", textlen);
690 DestroyWindow(hwnd);
693 static void test_longtextW(void)
695 static const char longtextA[] =
696 "According to MSDN, TTM_ENUMTOOLS claims that TOOLINFO's lpszText is maximum "
697 "80 chars including null. Actually, this is not applied for wide version.";
698 HWND hwnd;
699 TTTOOLINFOW toolinfoW = { 0 };
700 WCHAR bufW[256];
701 LRESULT r;
702 int lenW;
704 hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0,
705 10, 10, 300, 100,
706 NULL, NULL, NULL, 0);
707 if(!hwnd)
709 win_skip("CreateWindowExW() not supported. Skipping.\n");
710 return;
713 toolinfoW.cbSize = TTTOOLINFOW_V2_SIZE;
714 toolinfoW.hwnd = NULL;
715 toolinfoW.hinst = GetModuleHandleW(NULL);
716 toolinfoW.uFlags = 0;
717 toolinfoW.uId = 0x1234ABCD;
718 MultiByteToWideChar(CP_ACP, 0, longtextA, -1, bufW, sizeof(bufW)/sizeof(bufW[0]));
719 lenW = lstrlenW(bufW);
720 toolinfoW.lpszText = bufW;
721 toolinfoW.lParam = 0xdeadbeef;
722 GetClientRect(hwnd, &toolinfoW.rect);
723 r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&toolinfoW);
724 if (r)
726 int textlen;
727 memset(bufW, 0, sizeof(bufW));
728 toolinfoW.hwnd = NULL;
729 toolinfoW.uId = 0xABCD1234;
730 toolinfoW.lpszText = bufW;
731 SendMessageW(hwnd, TTM_ENUMTOOLSW, 0, (LPARAM)&toolinfoW);
732 textlen = lstrlenW(toolinfoW.lpszText);
733 ok(textlen == lenW, "lpszText has %d chars\n", textlen);
734 ok(toolinfoW.uId == 0x1234ABCD,
735 "uId should be retrieved, got %p\n", (void*)toolinfoW.uId);
737 memset(bufW, 0, sizeof(bufW));
738 toolinfoW.hwnd = NULL;
739 toolinfoW.uId = 0x1234ABCD;
740 toolinfoW.lpszText = bufW;
741 SendMessageW(hwnd, TTM_GETTOOLINFOW, 0, (LPARAM)&toolinfoW);
742 textlen = lstrlenW(toolinfoW.lpszText);
743 ok(textlen == lenW, "lpszText has %d chars\n", textlen);
745 memset(bufW, 0, sizeof(bufW));
746 toolinfoW.hwnd = NULL;
747 toolinfoW.uId = 0x1234ABCD;
748 toolinfoW.lpszText = bufW;
749 SendMessageW(hwnd, TTM_GETTEXTW, 0, (LPARAM)&toolinfoW);
750 textlen = lstrlenW(toolinfoW.lpszText);
751 ok(textlen == lenW ||
752 broken(textlen == 0 && toolinfoW.lpszText == NULL), /* nt4, kb186177 */
753 "lpszText has %d chars\n", textlen);
756 DestroyWindow(hwnd);
759 static BOOL almost_eq(int a, int b)
761 return a-5<b && a+5>b;
764 static void test_track(void)
766 WCHAR textW[] = {'t','e','x','t',0};
767 TTTOOLINFOW info = { 0 };
768 HWND parent, tt;
769 LRESULT res;
770 RECT pos;
772 parent = CreateWindowExW(0, WC_STATICW, NULL, WS_CAPTION | WS_VISIBLE,
773 50, 50, 300, 300, NULL, NULL, NULL, 0);
774 ok(parent != NULL, "creation of parent window failed\n");
776 ShowWindow(parent, SW_SHOWNORMAL);
777 flush_events(100);
779 tt = CreateWindowExW(WS_EX_TOPMOST, TOOLTIPS_CLASSW, NULL, TTS_NOPREFIX | TTS_ALWAYSTIP,
780 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
781 parent, NULL, GetModuleHandleW(NULL), 0);
782 ok(tt != NULL, "creation of tooltip window failed\n");
784 info.cbSize = TTTOOLINFOW_V1_SIZE;
785 info.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
786 info.hwnd = parent;
787 info.hinst = GetModuleHandleW(NULL);
788 info.lpszText = textW;
789 info.uId = (UINT_PTR)parent;
790 GetClientRect(parent, &info.rect);
792 res = SendMessageW(tt, TTM_ADDTOOLW, 0, (LPARAM)&info);
793 ok(res, "adding the tool to the tooltip failed\n");
795 SendMessageW(tt, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1,0));
796 SendMessageW(tt, TTM_TRACKACTIVATE, (WPARAM)TRUE, (LPARAM)&info);
797 SendMessageW(tt, TTM_TRACKPOSITION, 0, MAKELPARAM(10, 10));
799 GetWindowRect(tt, &pos);
800 ok(almost_eq(pos.left, 10), "pos.left = %d\n", pos.left);
801 ok(almost_eq(pos.top, 10), "pos.top = %d\n", pos.top);
803 info.uFlags = TTF_IDISHWND | TTF_ABSOLUTE;
804 SendMessageW(tt, TTM_SETTOOLINFOW, 0, (LPARAM)&info);
805 SendMessageW(tt, TTM_TRACKPOSITION, 0, MAKELPARAM(10, 10));
807 GetWindowRect(tt, &pos);
808 ok(!almost_eq(pos.left, 10), "pos.left = %d\n", pos.left);
809 ok(!almost_eq(pos.top, 10), "pos.top = %d\n", pos.top);
811 DestroyWindow(tt);
812 DestroyWindow(parent);
815 START_TEST(tooltips)
817 InitCommonControls();
819 test_create_tooltip();
820 test_customdraw();
821 test_gettext();
822 test_ttm_gettoolinfo();
823 test_longtextA();
824 test_longtextW();
825 test_track();