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 < sizeof(expectedResults)/sizeof(expectedResults[0]); 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, sizeof(bufW)/sizeof(bufW[0])); 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 } 1273