1 /* 2 * Unit tests for the pager control 3 * 4 * Copyright 2012 Alexandre Julliard 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include <windows.h> 22 #include <commctrl.h> 23 24 #include "wine/test.h" 25 #include "msg.h" 26 27 #define NUM_MSG_SEQUENCES 1 28 #define PAGER_SEQ_INDEX 0 29 30 static HWND parent_wnd, child1_wnd, child2_wnd; 31 static INT notify_format; 32 static BOOL notify_query_received; 33 static const CHAR test_a[] = "test"; 34 static const WCHAR test_w[] = L"test"; 35 /* Double zero so that it's safe to cast it to WCHAR * */ 36 static const CHAR te_a[] = {'t', 'e', 0, 0}; 37 static const CHAR large_a[] = 38 "You should have received a copy of the GNU Lesser General Public License along with this ..."; 39 static const WCHAR large_w[] = 40 L"You should have received a copy of the GNU Lesser General Public License along with this ..."; 41 static const WCHAR large_truncated_65_w[65] = 42 L"You should have received a copy of the GNU Lesser General Public"; 43 static const WCHAR large_truncated_80_w[80] = 44 L"You should have received a copy of the GNU Lesser General Public License along w"; 45 static WCHAR buffer[64]; 46 47 /* Text field conversion test behavior flags. */ 48 enum test_conversion_flags 49 { 50 CONVERT_SEND = 0x01, 51 DONT_CONVERT_SEND = 0x02, 52 CONVERT_RECEIVE = 0x04, 53 DONT_CONVERT_RECEIVE = 0x08, 54 SEND_EMPTY_IF_NULL = 0x10, 55 DONT_SEND_EMPTY_IF_NULL = 0x20, 56 SET_NULL_IF_NO_MASK = 0x40, 57 ZERO_SEND = 0x80 58 }; 59 60 enum handler_ids 61 { 62 TVITEM_NEW_HANDLER, 63 TVITEM_OLD_HANDLER 64 }; 65 66 static struct notify_test_info 67 { 68 UINT unicode; 69 UINT ansi; 70 UINT_PTR id_from; 71 HWND hwnd_from; 72 /* Whether parent received notification */ 73 BOOL received; 74 UINT test_id; 75 UINT sub_test_id; 76 UINT handler_id; 77 /* Text field conversion test behavior flag */ 78 DWORD flags; 79 } notify_test_info; 80 81 struct notify_test_send 82 { 83 /* Data sent to pager */ 84 const WCHAR *send_text; 85 INT send_text_size; 86 INT send_text_max; 87 /* Data expected by parent of pager */ 88 const void *expect_text; 89 }; 90 91 struct notify_test_receive 92 { 93 /* Data sent to pager */ 94 const WCHAR *send_text; 95 INT send_text_size; 96 INT send_text_max; 97 /* Data for parent to write */ 98 const CHAR *write_pointer; 99 const CHAR *write_text; 100 INT write_text_size; 101 INT write_text_max; 102 /* Data when message returned */ 103 const void *return_text; 104 INT return_text_max; 105 }; 106 107 struct generic_text_helper_para 108 { 109 void *ptr; 110 size_t size; 111 UINT *mask; 112 UINT required_mask; 113 WCHAR **text; 114 INT *text_max; 115 UINT code_unicode; 116 UINT code_ansi; 117 DWORD flags; 118 UINT handler_id; 119 }; 120 121 static const struct notify_test_send test_convert_send_data[] = 122 { 123 {test_w, sizeof(test_w), ARRAY_SIZE(buffer), test_a} 124 }; 125 126 static const struct notify_test_send test_dont_convert_send_data[] = 127 { 128 {test_w, sizeof(test_w), ARRAY_SIZE(buffer), test_w} 129 }; 130 131 static const struct notify_test_receive test_convert_receive_data[] = 132 { 133 {L"", sizeof(L""), ARRAY_SIZE(buffer), NULL, test_a, sizeof(test_a), -1, test_w, ARRAY_SIZE(buffer)}, 134 {L"", sizeof(L""), ARRAY_SIZE(buffer), test_a, NULL, 0, -1, test_w, ARRAY_SIZE(buffer)}, 135 {NULL, sizeof(L""), ARRAY_SIZE(buffer), test_a, NULL, 0, -1, NULL, ARRAY_SIZE(buffer)}, 136 {L"", sizeof(L""), ARRAY_SIZE(buffer), large_a, NULL, 0, -1, large_truncated_65_w, ARRAY_SIZE(buffer)}, 137 {L"", sizeof(L""), ARRAY_SIZE(buffer), "", 0, 0, 1, L"", 1}, 138 }; 139 140 static const struct notify_test_receive test_dont_convert_receive_data[] = 141 { 142 {L"", sizeof(L""), ARRAY_SIZE(buffer), NULL, test_a, sizeof(test_a), -1, test_a, ARRAY_SIZE(buffer)}, 143 {L"", sizeof(L""), ARRAY_SIZE(buffer), test_a, NULL, 0, -1, test_a, ARRAY_SIZE(buffer)}, 144 }; 145 146 static const struct notify_test_tooltip 147 { 148 /* Data for parent to write */ 149 const CHAR *write_sztext; 150 INT write_sztext_size; 151 const CHAR *write_lpsztext; 152 HMODULE write_hinst; 153 /* Data when message returned */ 154 const WCHAR *return_sztext; 155 INT return_sztext_size; 156 const WCHAR *return_lpsztext; 157 HMODULE return_hinst; 158 /* Data expected by parent */ 159 const CHAR *expect_sztext; 160 /* Data send to parent */ 161 const WCHAR *send_sztext; 162 INT send_sztext_size; 163 const WCHAR *send_lpsztext; 164 } test_tooltip_data[] = 165 { 166 {NULL, 0, NULL, NULL, L"", -1, L""}, 167 {test_a, sizeof(test_a), NULL, NULL, test_w, -1, test_w}, 168 {test_a, sizeof(test_a), test_a, NULL, test_w, -1, test_w}, 169 {test_a, sizeof(test_a), (CHAR *)1, (HMODULE)0xdeadbeef, L"", -1, (WCHAR *)1, (HMODULE)0xdeadbeef}, 170 {test_a, sizeof(test_a), test_a, (HMODULE)0xdeadbeef, test_w, -1, test_w, (HMODULE)0xdeadbeef}, 171 {NULL, 0, test_a, NULL, test_w, -1, test_w}, 172 {test_a, 2, test_a, NULL, test_w, -1, test_w}, 173 {NULL, 0, NULL, NULL, test_w, -1, test_w, NULL, test_a, test_w, sizeof(test_w)}, 174 {NULL, 0, NULL, NULL, L"", -1, L"", NULL, "", NULL, 0, test_w}, 175 {NULL, 0, large_a, NULL, large_truncated_80_w, sizeof(large_truncated_80_w), large_w} 176 }; 177 178 static const struct notify_test_datetime_format 179 { 180 /* Data send to parent */ 181 const WCHAR *send_pszformat; 182 /* Data expected by parent */ 183 const CHAR *expect_pszformat; 184 /* Data for parent to write */ 185 const CHAR *write_szdisplay; 186 INT write_szdisplay_size; 187 const CHAR *write_pszdisplay; 188 /* Data when message returned */ 189 const WCHAR *return_szdisplay; 190 INT return_szdisplay_size; 191 const WCHAR *return_pszdisplay; 192 } test_datetime_format_data[] = 193 { 194 {test_w, test_a}, 195 {NULL, NULL, NULL, 0, test_a, L"", -1, test_w}, 196 {NULL, NULL, test_a, sizeof(test_a), NULL, test_w, -1, test_w}, 197 {NULL, NULL, test_a, 2, test_a, (WCHAR *)te_a, -1, test_w}, 198 {NULL, NULL, NULL, 0, large_a, NULL, 0, large_w} 199 }; 200 201 #define CHILD1_ID 1 202 #define CHILD2_ID 2 203 204 static BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); 205 static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR); 206 207 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES]; 208 209 static const struct message set_child_seq[] = { 210 { PGM_SETCHILD, sent }, 211 { WM_WINDOWPOSCHANGING, sent }, 212 { WM_NCCALCSIZE, sent|wparam, TRUE }, 213 { WM_NOTIFY, sent|id|parent, 0, 0, PGN_CALCSIZE }, 214 { WM_WINDOWPOSCHANGED, sent }, 215 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, CHILD1_ID }, 216 { WM_NCCALCSIZE, sent|wparam|id|optional, TRUE, 0, CHILD1_ID }, 217 { WM_CHILDACTIVATE, sent|id, 0, 0, CHILD1_ID }, 218 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, CHILD1_ID }, 219 { WM_SIZE, sent|id|defwinproc|optional, 0, 0, CHILD1_ID }, 220 { 0 } 221 }; 222 223 /* This differs from the above message list only in the child window that is 224 * expected to receive the child messages. No message is sent to the old child. 225 * Also child 2 is hidden while child 1 is visible. The pager does not make the 226 * hidden child visible. */ 227 static const struct message switch_child_seq[] = { 228 { PGM_SETCHILD, sent }, 229 { WM_WINDOWPOSCHANGING, sent }, 230 { WM_NCCALCSIZE, sent|wparam, TRUE }, 231 { WM_NOTIFY, sent|id|parent, 0, 0, PGN_CALCSIZE }, 232 { WM_WINDOWPOSCHANGED, sent }, 233 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, CHILD2_ID }, 234 { WM_NCCALCSIZE, sent|wparam|id, TRUE, 0, CHILD2_ID }, 235 { WM_CHILDACTIVATE, sent|id, 0, 0, CHILD2_ID }, 236 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, CHILD2_ID }, 237 { WM_SIZE, sent|id|defwinproc, 0, 0, CHILD2_ID }, 238 { 0 } 239 }; 240 241 static const struct message set_pos_seq[] = { 242 { PGM_SETPOS, sent }, 243 { WM_WINDOWPOSCHANGING, sent }, 244 { WM_NCCALCSIZE, sent|wparam, TRUE }, 245 { WM_NOTIFY, sent|id|parent, 0, 0, PGN_CALCSIZE }, 246 { WM_WINDOWPOSCHANGED, sent }, 247 { WM_MOVE, sent|optional }, 248 /* The WM_SIZE handler sends WM_WINDOWPOSCHANGING, WM_CHILDACTIVATE 249 * and WM_WINDOWPOSCHANGED (which sends WM_MOVE) to the child. 250 * Another WM_WINDOWPOSCHANGING is sent afterwards. 251 * 252 * The 2nd WM_WINDOWPOSCHANGING is unconditional, but the comparison 253 * function is too simple to roll back an accepted message, so we have 254 * to mark the 2nd message optional. */ 255 { WM_SIZE, sent|optional }, 256 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, CHILD1_ID }, /* Actually optional. */ 257 { WM_CHILDACTIVATE, sent|id, 0, 0, CHILD1_ID }, /* Actually optional. */ 258 { WM_WINDOWPOSCHANGED, sent|id|optional, TRUE, 0, CHILD1_ID}, 259 { WM_MOVE, sent|id|optional|defwinproc, 0, 0, CHILD1_ID }, 260 { WM_WINDOWPOSCHANGING, sent|id|optional, 0, 0, CHILD1_ID }, /* Actually not optional. */ 261 { WM_CHILDACTIVATE, sent|id|optional, 0, 0, CHILD1_ID }, /* Actually not optional. */ 262 { 0 } 263 }; 264 265 static const struct message set_pos_empty_seq[] = { 266 { PGM_SETPOS, sent }, 267 { 0 } 268 }; 269 270 static CHAR *heap_strdup(const CHAR *str) 271 { 272 int len = lstrlenA(str) + 1; 273 CHAR *ret = heap_alloc(len * sizeof(CHAR)); 274 lstrcpyA(ret, str); 275 return ret; 276 } 277 278 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 279 { 280 static LONG defwndproc_counter = 0; 281 LRESULT ret; 282 struct message msg; 283 284 /* log system messages, except for painting */ 285 if (message < WM_USER && 286 message != WM_PAINT && 287 message != WM_ERASEBKGND && 288 message != WM_NCPAINT && 289 message != WM_NCHITTEST && 290 message != WM_GETTEXT && 291 message != WM_GETICON && 292 message != WM_DEVICECHANGE) 293 { 294 msg.message = message; 295 msg.flags = sent|wparam|lparam|parent; 296 if (defwndproc_counter) msg.flags |= defwinproc; 297 msg.wParam = wParam; 298 msg.lParam = lParam; 299 if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code; 300 add_message(sequences, PAGER_SEQ_INDEX, &msg); 301 } 302 303 if (message == WM_NOTIFY) 304 { 305 NMHDR *nmhdr = (NMHDR *)lParam; 306 307 switch (nmhdr->code) 308 { 309 case PGN_CALCSIZE: 310 { 311 NMPGCALCSIZE *nmpgcs = (NMPGCALCSIZE *)lParam; 312 DWORD style = GetWindowLongA(nmpgcs->hdr.hwndFrom, GWL_STYLE); 313 314 if (style & PGS_HORZ) 315 ok(nmpgcs->dwFlag == PGF_CALCWIDTH, "Unexpected flags %#x.\n", nmpgcs->dwFlag); 316 else 317 ok(nmpgcs->dwFlag == PGF_CALCHEIGHT, "Unexpected flags %#x.\n", nmpgcs->dwFlag); 318 break; 319 } 320 default: 321 ; 322 } 323 } 324 325 defwndproc_counter++; 326 ret = DefWindowProcA(hwnd, message, wParam, lParam); 327 defwndproc_counter--; 328 329 return ret; 330 } 331 332 static BOOL register_parent_wnd_class(void) 333 { 334 WNDCLASSA cls; 335 336 cls.style = 0; 337 cls.lpfnWndProc = parent_wnd_proc; 338 cls.cbClsExtra = 0; 339 cls.cbWndExtra = 0; 340 cls.hInstance = GetModuleHandleA(NULL); 341 cls.hIcon = 0; 342 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); 343 cls.hbrBackground = GetStockObject(WHITE_BRUSH); 344 cls.lpszMenuName = NULL; 345 cls.lpszClassName = "Pager test parent class"; 346 return RegisterClassA(&cls); 347 } 348 349 static HWND create_parent_window(void) 350 { 351 if (!register_parent_wnd_class()) 352 return NULL; 353 354 return CreateWindowA("Pager test parent class", "Pager test parent window", 355 WS_OVERLAPPED | WS_VISIBLE, 356 0, 0, 200, 200, 0, NULL, GetModuleHandleA(NULL), NULL ); 357 } 358 359 static LRESULT WINAPI pager_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 360 { 361 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); 362 struct message msg = { 0 }; 363 364 msg.message = message; 365 msg.flags = sent|wparam|lparam; 366 msg.wParam = wParam; 367 msg.lParam = lParam; 368 add_message(sequences, PAGER_SEQ_INDEX, &msg); 369 return CallWindowProcA(oldproc, hwnd, message, wParam, lParam); 370 } 371 372 static HWND create_pager_control( DWORD style ) 373 { 374 WNDPROC oldproc; 375 HWND hwnd; 376 RECT rect; 377 378 GetClientRect( parent_wnd, &rect ); 379 hwnd = CreateWindowA( WC_PAGESCROLLERA, "pager", WS_CHILD | WS_BORDER | WS_VISIBLE | style, 380 0, 0, 100, 100, parent_wnd, 0, GetModuleHandleA(0), 0 ); 381 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)pager_subclass_proc); 382 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc); 383 return hwnd; 384 } 385 386 static LRESULT WINAPI child_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 387 { 388 static LONG defwndproc_counter; 389 struct message msg = { 0 }; 390 LRESULT ret; 391 392 msg.message = message; 393 msg.flags = sent | wparam | lparam; 394 if (defwndproc_counter) 395 msg.flags |= defwinproc; 396 msg.wParam = wParam; 397 msg.lParam = lParam; 398 399 if (hwnd == child1_wnd) 400 msg.id = CHILD1_ID; 401 else if (hwnd == child2_wnd) 402 msg.id = CHILD2_ID; 403 else 404 msg.id = 0; 405 406 add_message(sequences, PAGER_SEQ_INDEX, &msg); 407 408 defwndproc_counter++; 409 ret = DefWindowProcA(hwnd, message, wParam, lParam); 410 defwndproc_counter--; 411 412 return ret; 413 } 414 415 static BOOL register_child_wnd_class(void) 416 { 417 WNDCLASSA cls; 418 419 cls.style = 0; 420 cls.lpfnWndProc = child_proc; 421 cls.cbClsExtra = 0; 422 cls.cbWndExtra = 0; 423 cls.hInstance = GetModuleHandleA(NULL); 424 cls.hIcon = 0; 425 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); 426 cls.hbrBackground = GetStockObject(WHITE_BRUSH); 427 cls.lpszMenuName = NULL; 428 cls.lpszClassName = "Pager test child class"; 429 return RegisterClassA(&cls); 430 } 431 432 static void test_pager(void) 433 { 434 HWND pager; 435 RECT rect, rect2; 436 437 pager = create_pager_control( PGS_HORZ ); 438 ok(pager != NULL, "Fail to create pager\n"); 439 440 register_child_wnd_class(); 441 442 child1_wnd = CreateWindowA( "Pager test child class", "button", WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 300, 300, 443 pager, 0, GetModuleHandleA(0), 0 ); 444 child2_wnd = CreateWindowA("Pager test child class", "button", WS_CHILD | WS_BORDER, 0, 0, 300, 300, 445 pager, 0, GetModuleHandleA(0), 0); 446 447 flush_sequences( sequences, NUM_MSG_SEQUENCES ); 448 SendMessageA( pager, PGM_SETCHILD, 0, (LPARAM)child1_wnd ); 449 ok_sequence(sequences, PAGER_SEQ_INDEX, set_child_seq, "set child", FALSE); 450 GetWindowRect( pager, &rect ); 451 ok( rect.right - rect.left == 100 && rect.bottom - rect.top == 100, 452 "pager resized %dx%d\n", rect.right - rect.left, rect.bottom - rect.top ); 453 454 flush_sequences(sequences, NUM_MSG_SEQUENCES); 455 SendMessageA(pager, PGM_SETCHILD, 0, (LPARAM)child2_wnd); 456 ok_sequence(sequences, PAGER_SEQ_INDEX, switch_child_seq, "switch to invisible child", FALSE); 457 GetWindowRect(pager, &rect); 458 ok(rect.right - rect.left == 100 && rect.bottom - rect.top == 100, 459 "pager resized %dx%d\n", rect.right - rect.left, rect.bottom - rect.top); 460 ok(!IsWindowVisible(child2_wnd), "Child window 2 is visible\n"); 461 462 flush_sequences(sequences, NUM_MSG_SEQUENCES); 463 SendMessageA(pager, PGM_SETCHILD, 0, (LPARAM)child1_wnd); 464 ok_sequence(sequences, PAGER_SEQ_INDEX, set_child_seq, "switch to visible child", FALSE); 465 GetWindowRect(pager, &rect); 466 ok(rect.right - rect.left == 100 && rect.bottom - rect.top == 100, 467 "pager resized %dx%d\n", rect.right - rect.left, rect.bottom - rect.top); 468 469 flush_sequences( sequences, NUM_MSG_SEQUENCES ); 470 SendMessageA( pager, PGM_SETPOS, 0, 10 ); 471 ok_sequence(sequences, PAGER_SEQ_INDEX, set_pos_seq, "set pos", TRUE); 472 GetWindowRect( pager, &rect ); 473 ok( rect.right - rect.left == 100 && rect.bottom - rect.top == 100, 474 "pager resized %dx%d\n", rect.right - rect.left, rect.bottom - rect.top ); 475 476 flush_sequences( sequences, NUM_MSG_SEQUENCES ); 477 SendMessageA( pager, PGM_SETPOS, 0, 10 ); 478 ok_sequence(sequences, PAGER_SEQ_INDEX, set_pos_empty_seq, "set pos empty", TRUE); 479 480 flush_sequences( sequences, NUM_MSG_SEQUENCES ); 481 SendMessageA( pager, PGM_SETPOS, 0, 9 ); 482 ok_sequence(sequences, PAGER_SEQ_INDEX, set_pos_seq, "set pos", TRUE); 483 484 DestroyWindow( pager ); 485 486 /* Test if resizing works */ 487 pager = create_pager_control( CCS_NORESIZE ); 488 ok(pager != NULL, "failed to create pager control\n"); 489 490 GetWindowRect( pager, &rect ); 491 MoveWindow( pager, 0, 0, 200, 100, TRUE ); 492 GetWindowRect( pager, &rect2 ); 493 ok(rect2.right - rect2.left > rect.right - rect.left, "expected pager window to resize, %s\n", 494 wine_dbgstr_rect( &rect2 )); 495 496 DestroyWindow( pager ); 497 498 pager = create_pager_control( CCS_NORESIZE | PGS_HORZ ); 499 ok(pager != NULL, "failed to create pager control\n"); 500 501 GetWindowRect( pager, &rect ); 502 MoveWindow( pager, 0, 0, 100, 200, TRUE ); 503 GetWindowRect( pager, &rect2 ); 504 ok(rect2.bottom - rect2.top > rect.bottom - rect.top, "expected pager window to resize, %s\n", 505 wine_dbgstr_rect( &rect2 )); 506 507 DestroyWindow( pager ); 508 } 509 510 static LRESULT WINAPI test_notifyformat_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 511 { 512 switch (message) 513 { 514 case WM_NOTIFYFORMAT: 515 if (lParam == NF_QUERY) 516 { 517 notify_query_received = TRUE; 518 return notify_format; 519 } 520 else if (lParam == NF_REQUERY) 521 return SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY); 522 else 523 return 0; 524 default: 525 return notify_format == NFR_UNICODE ? DefWindowProcW(hwnd, message, wParam, lParam) 526 : DefWindowProcA(hwnd, message, wParam, lParam); 527 } 528 } 529 530 static BOOL register_notifyformat_class(void) 531 { 532 static const WCHAR class_w[] = {'P', 'a', 'g', 'e', 'r', ' ', 'n', 'o', 't', 'i', 'f', 'y', 'f', 533 'o', 'r', 'm', 'a', 't', ' ', 'c', 'l', 'a', 's', 's', 0}; 534 WNDCLASSW cls = {0}; 535 536 cls.lpfnWndProc = test_notifyformat_proc; 537 cls.hInstance = GetModuleHandleW(NULL); 538 cls.lpszClassName = class_w; 539 return RegisterClassW(&cls); 540 } 541 542 static void test_wm_notifyformat(void) 543 { 544 static const WCHAR class_w[] = {'P', 'a', 'g', 'e', 'r', ' ', 'n', 'o', 't', 'i', 'f', 'y', 'f', 545 'o', 'r', 'm', 'a', 't', ' ', 'c', 'l', 'a', 's', 's', 0}; 546 static const WCHAR parent_w[] = {'p', 'a', 'r', 'e', 'n', 't', 0}; 547 static const WCHAR pager_w[] = {'p', 'a', 'g', 'e', 'r', 0}; 548 static const WCHAR child_w[] = {'c', 'h', 'i', 'l', 'd', 0}; 549 static const INT formats[] = {NFR_UNICODE, NFR_ANSI}; 550 HWND parent, pager, child; 551 LRESULT ret; 552 BOOL bret; 553 INT i; 554 555 bret = register_notifyformat_class(); 556 ok(bret, "Register test class failed, error 0x%08x\n", GetLastError()); 557 558 for (i = 0; i < ARRAY_SIZE(formats); i++) 559 { 560 notify_format = formats[i]; 561 parent = CreateWindowW(class_w, parent_w, WS_OVERLAPPED, 0, 0, 100, 100, 0, 0, GetModuleHandleW(0), 0); 562 ok(parent != NULL, "CreateWindow failed\n"); 563 pager = CreateWindowW(WC_PAGESCROLLERW, pager_w, WS_CHILD, 0, 0, 100, 100, parent, 0, GetModuleHandleW(0), 0); 564 ok(pager != NULL, "CreateWindow failed\n"); 565 child = CreateWindowW(class_w, child_w, WS_CHILD, 0, 0, 100, 100, pager, 0, GetModuleHandleW(0), 0); 566 ok(child != NULL, "CreateWindow failed\n"); 567 SendMessageW(pager, PGM_SETCHILD, 0, (LPARAM)child); 568 569 /* Test parent */ 570 notify_query_received = FALSE; 571 ret = SendMessageW(pager, WM_NOTIFYFORMAT, (WPARAM)parent, NF_REQUERY); 572 ok(ret == notify_format, "Expect %d, got %ld\n", notify_format, ret); 573 ok(notify_query_received, "Didn't receive notify\n"); 574 575 /* Send NF_QUERY directly to parent */ 576 notify_query_received = FALSE; 577 ret = SendMessageW(parent, WM_NOTIFYFORMAT, (WPARAM)pager, NF_QUERY); 578 ok(ret == notify_format, "Expect %d, got %ld\n", notify_format, ret); 579 ok(notify_query_received, "Didn't receive notify\n"); 580 581 /* Pager send notifications to its parent regardless of wParam */ 582 notify_query_received = FALSE; 583 ret = SendMessageW(pager, WM_NOTIFYFORMAT, (WPARAM)parent_wnd, NF_REQUERY); 584 ok(ret == notify_format, "Expect %d, got %ld\n", notify_format, ret); 585 ok(notify_query_received, "Didn't receive notify\n"); 586 587 /* Pager always wants Unicode notifications from children */ 588 ret = SendMessageW(child, WM_NOTIFYFORMAT, (WPARAM)pager, NF_REQUERY); 589 ok(ret == NFR_UNICODE, "Expect %d, got %ld\n", NFR_UNICODE, ret); 590 ret = SendMessageW(pager, WM_NOTIFYFORMAT, (WPARAM)child, NF_QUERY); 591 ok(ret == NFR_UNICODE, "Expect %d, got %ld\n", NFR_UNICODE, ret); 592 593 DestroyWindow(parent); 594 } 595 596 UnregisterClassW(class_w, GetModuleHandleW(NULL)); 597 } 598 599 static void notify_generic_text_handler(CHAR **text, INT *text_max) 600 { 601 const struct notify_test_send *send_data; 602 const struct notify_test_receive *receive_data; 603 604 switch (notify_test_info.test_id) 605 { 606 case CONVERT_SEND: 607 case DONT_CONVERT_SEND: 608 { 609 send_data = (notify_test_info.test_id == CONVERT_SEND ? test_convert_send_data : test_dont_convert_send_data) 610 + notify_test_info.sub_test_id; 611 if (notify_test_info.flags & ZERO_SEND) 612 ok(!*text[0], "Code 0x%08x test 0x%08x sub test %d expect empty text, got %s\n", 613 notify_test_info.unicode, notify_test_info.test_id, notify_test_info.sub_test_id, *text); 614 else if (notify_test_info.flags & CONVERT_SEND) 615 ok(!lstrcmpA(send_data->expect_text, *text), "Code 0x%08x test 0x%08x sub test %d expect %s, got %s\n", 616 notify_test_info.unicode, notify_test_info.test_id, notify_test_info.sub_test_id, 617 (CHAR *)send_data->expect_text, *text); 618 else 619 ok(!lstrcmpW((WCHAR *)send_data->expect_text, (WCHAR *)*text), 620 "Code 0x%08x test 0x%08x sub test %d expect %s, got %s\n", notify_test_info.unicode, 621 notify_test_info.test_id, notify_test_info.sub_test_id, wine_dbgstr_w((WCHAR *)send_data->expect_text), 622 wine_dbgstr_w((WCHAR *)*text)); 623 if (text_max) 624 ok(*text_max == send_data->send_text_max, "Code 0x%08x test 0x%08x sub test %d expect %d, got %d\n", 625 notify_test_info.unicode, notify_test_info.test_id, notify_test_info.sub_test_id, 626 send_data->send_text_max, *text_max); 627 break; 628 } 629 case CONVERT_RECEIVE: 630 case DONT_CONVERT_RECEIVE: 631 { 632 receive_data = (notify_test_info.test_id == CONVERT_RECEIVE ? test_convert_receive_data : test_dont_convert_receive_data) 633 + notify_test_info.sub_test_id; 634 if (text_max) 635 ok(*text_max == receive_data->send_text_max, "Code 0x%08x test 0x%08x sub test %d expect %d, got %d\n", 636 notify_test_info.unicode, notify_test_info.test_id, notify_test_info.sub_test_id, 637 receive_data->send_text_max, *text_max); 638 639 if (receive_data->write_text) 640 memcpy(*text, receive_data->write_text, receive_data->write_text_size); 641 /* 64bit Windows will try to free the text pointer even if it's application provided when handling 642 * HDN_GETDISPINFOW. Deliberate leak here. */ 643 else if(notify_test_info.unicode == HDN_GETDISPINFOW) 644 *text = heap_strdup(receive_data->write_pointer); 645 else 646 *text = (char *)receive_data->write_pointer; 647 if (text_max && receive_data->write_text_max != -1) *text_max = receive_data->write_text_max; 648 break; 649 } 650 case SEND_EMPTY_IF_NULL: 651 ok(!*text[0], "Code 0x%08x test 0x%08x sub test %d expect empty text, got %s\n", 652 notify_test_info.unicode, notify_test_info.test_id, notify_test_info.sub_test_id, *text); 653 break; 654 case DONT_SEND_EMPTY_IF_NULL: 655 ok(!*text, "Code 0x%08x test 0x%08x sub test %d expect null text\n", notify_test_info.unicode, 656 notify_test_info.test_id, notify_test_info.sub_test_id); 657 break; 658 } 659 } 660 661 static void notify_tooltip_handler(NMTTDISPINFOA *nm) 662 { 663 const struct notify_test_tooltip *data = test_tooltip_data + notify_test_info.sub_test_id; 664 ok(nm->lpszText == nm->szText, "Sub test %d expect %p, got %p\n", notify_test_info.sub_test_id, nm->szText, 665 nm->lpszText); 666 if (data->expect_sztext) 667 ok(!lstrcmpA(data->expect_sztext, nm->szText), "Sub test %d expect %s, got %s\n", notify_test_info.sub_test_id, 668 data->expect_sztext, nm->szText); 669 if (data->write_sztext) memcpy(nm->szText, data->write_sztext, data->write_sztext_size); 670 if (data->write_lpsztext) nm->lpszText = (char *)data->write_lpsztext; 671 if (data->write_hinst) nm->hinst = data->write_hinst; 672 } 673 674 static void notify_datetime_handler(NMDATETIMEFORMATA *nm) 675 { 676 const struct notify_test_datetime_format *data = test_datetime_format_data + notify_test_info.sub_test_id; 677 if (data->expect_pszformat) 678 ok(!lstrcmpA(data->expect_pszformat, nm->pszFormat), "Sub test %d expect %s, got %s\n", 679 notify_test_info.sub_test_id, data->expect_pszformat, nm->pszFormat); 680 ok(nm->pszDisplay == nm->szDisplay, "Test %d expect %p, got %p\n", notify_test_info.sub_test_id, nm->szDisplay, 681 nm->pszDisplay); 682 if (data->write_szdisplay) memcpy(nm->szDisplay, data->write_szdisplay, data->write_szdisplay_size); 683 if (data->write_pszdisplay) nm->pszDisplay = data->write_pszdisplay; 684 } 685 686 static LRESULT WINAPI test_notify_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 687 { 688 static const WCHAR test[] = {'t', 'e', 's', 't', 0}; 689 switch (message) 690 { 691 case WM_NOTIFY: 692 { 693 NMHDR *hdr = (NMHDR *)lParam; 694 695 /* Not notifications we want to test */ 696 if (!notify_test_info.unicode) break; 697 ok(!notify_test_info.received, "Extra notification received\n"); 698 699 ok(wParam == notify_test_info.id_from, "Expect %ld, got %ld\n", notify_test_info.id_from, wParam); 700 ok(hdr->code == notify_test_info.ansi, "Expect 0x%08x, got 0x%08x\n", notify_test_info.ansi, hdr->code); 701 ok(hdr->idFrom == notify_test_info.id_from, "Expect %ld, got %ld\n", notify_test_info.id_from, wParam); 702 ok(hdr->hwndFrom == notify_test_info.hwnd_from, "Expect %p, got %p\n", notify_test_info.hwnd_from, hdr->hwndFrom); 703 704 if (hdr->code != notify_test_info.ansi) 705 { 706 skip("Notification code mismatch, skipping lParam check\n"); 707 return 0; 708 } 709 switch (hdr->code) 710 { 711 /* ComboBoxEx */ 712 case CBEN_INSERTITEM: 713 case CBEN_DELETEITEM: 714 { 715 NMCOMBOBOXEXW *nmcbe = (NMCOMBOBOXEXW *)hdr; 716 notify_generic_text_handler((CHAR **)&nmcbe->ceItem.pszText, NULL); 717 break; 718 } 719 case CBEN_DRAGBEGINA: 720 { 721 NMCBEDRAGBEGINA *nmcbedb = (NMCBEDRAGBEGINA *)hdr; 722 ok(!lstrcmpA(nmcbedb->szText, test_a), "Expect %s, got %s\n", nmcbedb->szText, test_a); 723 break; 724 } 725 case CBEN_ENDEDITA: 726 { 727 NMCBEENDEDITA *nmcbeed = (NMCBEENDEDITA *)hdr; 728 ok(!lstrcmpA(nmcbeed->szText, test_a), "Expect %s, got %s\n", nmcbeed->szText, test_a); 729 break; 730 } 731 case CBEN_GETDISPINFOA: 732 { 733 NMCOMBOBOXEXA *nmcbe = (NMCOMBOBOXEXA *)hdr; 734 notify_generic_text_handler(&nmcbe->ceItem.pszText, &nmcbe->ceItem.cchTextMax); 735 break; 736 } 737 /* Date and Time Picker */ 738 case DTN_FORMATA: 739 { 740 notify_datetime_handler((NMDATETIMEFORMATA *)hdr); 741 break; 742 } 743 case DTN_FORMATQUERYA: 744 { 745 NMDATETIMEFORMATQUERYA *nmdtfq = (NMDATETIMEFORMATQUERYA *)hdr; 746 notify_generic_text_handler((CHAR **)&nmdtfq->pszFormat, NULL); 747 break; 748 } 749 case DTN_WMKEYDOWNA: 750 { 751 NMDATETIMEWMKEYDOWNA *nmdtkd = (NMDATETIMEWMKEYDOWNA *)hdr; 752 notify_generic_text_handler((CHAR **)&nmdtkd->pszFormat, NULL); 753 break; 754 } 755 case DTN_USERSTRINGA: 756 { 757 NMDATETIMESTRINGA *nmdts = (NMDATETIMESTRINGA *)hdr; 758 notify_generic_text_handler((CHAR **)&nmdts->pszUserString, NULL); 759 break; 760 } 761 /* Header */ 762 case HDN_BEGINDRAG: 763 case HDN_ENDDRAG: 764 case HDN_BEGINFILTEREDIT: 765 case HDN_ENDFILTEREDIT: 766 case HDN_DROPDOWN: 767 case HDN_FILTERCHANGE: 768 case HDN_ITEMKEYDOWN: 769 case HDN_ITEMSTATEICONCLICK: 770 case HDN_OVERFLOWCLICK: 771 { 772 NMHEADERW *nmhd = (NMHEADERW *)hdr; 773 ok(!lstrcmpW(nmhd->pitem->pszText, test_w), "Expect %s, got %s\n", wine_dbgstr_w(test_w), 774 wine_dbgstr_w(nmhd->pitem->pszText)); 775 ok(!lstrcmpW(((HD_TEXTFILTERW *)nmhd->pitem->pvFilter)->pszText, test_w), "Expect %s, got %s\n", 776 wine_dbgstr_w(test_w), wine_dbgstr_w(((HD_TEXTFILTERW *)nmhd->pitem->pvFilter)->pszText)); 777 break; 778 } 779 case HDN_BEGINTRACKA: 780 case HDN_DIVIDERDBLCLICKA: 781 case HDN_ENDTRACKA: 782 case HDN_ITEMCHANGEDA: 783 case HDN_ITEMCHANGINGA: 784 case HDN_ITEMCLICKA: 785 case HDN_ITEMDBLCLICKA: 786 case HDN_TRACKA: 787 { 788 NMHEADERA *nmhd = (NMHEADERA *)hdr; 789 ok(!lstrcmpA(nmhd->pitem->pszText, test_a), "Expect %s, got %s\n", test_a, nmhd->pitem->pszText); 790 ok(!lstrcmpA(((HD_TEXTFILTERA *)nmhd->pitem->pvFilter)->pszText, test_a), "Expect %s, got %s\n", test_a, 791 ((HD_TEXTFILTERA *)nmhd->pitem->pvFilter)->pszText); 792 break; 793 } 794 case HDN_GETDISPINFOA: 795 { 796 NMHDDISPINFOA *nmhddi = (NMHDDISPINFOA *)hdr; 797 notify_generic_text_handler(&nmhddi->pszText, &nmhddi->cchTextMax); 798 break; 799 } 800 /* List View */ 801 case LVN_BEGINLABELEDITA: 802 case LVN_ENDLABELEDITA: 803 case LVN_GETDISPINFOA: 804 case LVN_SETDISPINFOA: 805 { 806 NMLVDISPINFOA *nmlvdi = (NMLVDISPINFOA *)hdr; 807 notify_generic_text_handler(&nmlvdi->item.pszText, &nmlvdi->item.cchTextMax); 808 break; 809 } 810 case LVN_GETINFOTIPA: 811 { 812 NMLVGETINFOTIPA *nmlvgit = (NMLVGETINFOTIPA *)hdr; 813 notify_generic_text_handler(&nmlvgit->pszText, &nmlvgit->cchTextMax); 814 break; 815 } 816 case LVN_INCREMENTALSEARCHA: 817 case LVN_ODFINDITEMA: 818 { 819 NMLVFINDITEMA *nmlvfi = (NMLVFINDITEMA *)hdr; 820 notify_generic_text_handler((CHAR **)&nmlvfi->lvfi.psz, NULL); 821 break; 822 } 823 /* Toolbar */ 824 case TBN_SAVE: 825 { 826 NMTBSAVE *nmtbs = (NMTBSAVE *)hdr; 827 notify_generic_text_handler((CHAR **)&nmtbs->tbButton.iString, NULL); 828 break; 829 } 830 case TBN_RESTORE: 831 { 832 NMTBRESTORE *nmtbr = (NMTBRESTORE *)hdr; 833 notify_generic_text_handler((CHAR **)&nmtbr->tbButton.iString, NULL); 834 break; 835 } 836 case TBN_GETBUTTONINFOA: 837 { 838 NMTOOLBARA *nmtb = (NMTOOLBARA *)hdr; 839 notify_generic_text_handler(&nmtb->pszText, &nmtb->cchText); 840 break; 841 } 842 case TBN_GETDISPINFOW: 843 { 844 NMTBDISPINFOW *nmtbdi = (NMTBDISPINFOW *)hdr; 845 notify_generic_text_handler((CHAR **)&nmtbdi->pszText, &nmtbdi->cchText); 846 break; 847 } 848 case TBN_GETINFOTIPA: 849 { 850 NMTBGETINFOTIPA *nmtbgit = (NMTBGETINFOTIPA *)hdr; 851 notify_generic_text_handler(&nmtbgit->pszText, &nmtbgit->cchTextMax); 852 break; 853 } 854 /* Tooltip */ 855 case TTN_GETDISPINFOA: 856 { 857 notify_tooltip_handler((NMTTDISPINFOA *)hdr); 858 break; 859 } 860 /* Tree View */ 861 case TVN_BEGINLABELEDITA: 862 case TVN_ENDLABELEDITA: 863 case TVN_GETDISPINFOA: 864 case TVN_SETDISPINFOA: 865 { 866 NMTVDISPINFOA *nmtvdi = (NMTVDISPINFOA *)hdr; 867 notify_generic_text_handler(&nmtvdi->item.pszText, &nmtvdi->item.cchTextMax); 868 break; 869 } 870 case TVN_GETINFOTIPA: 871 { 872 NMTVGETINFOTIPA *nmtvgit = (NMTVGETINFOTIPA *)hdr; 873 notify_generic_text_handler(&nmtvgit->pszText, &nmtvgit->cchTextMax); 874 break; 875 } 876 case TVN_SINGLEEXPAND: 877 case TVN_BEGINDRAGA: 878 case TVN_BEGINRDRAGA: 879 case TVN_ITEMEXPANDEDA: 880 case TVN_ITEMEXPANDINGA: 881 case TVN_DELETEITEMA: 882 case TVN_SELCHANGINGA: 883 case TVN_SELCHANGEDA: 884 { 885 NMTREEVIEWA *nmtv = (NMTREEVIEWA *)hdr; 886 if (notify_test_info.handler_id == TVITEM_NEW_HANDLER) 887 notify_generic_text_handler((CHAR **)&nmtv->itemNew.pszText, &nmtv->itemNew.cchTextMax); 888 else 889 notify_generic_text_handler((CHAR **)&nmtv->itemOld.pszText, &nmtv->itemOld.cchTextMax); 890 break; 891 } 892 893 default: 894 ok(0, "Unexpected message 0x%08x\n", hdr->code); 895 } 896 notify_test_info.received = TRUE; 897 ok(!lstrcmpA(test_a, "test"), "test_a got modified\n"); 898 ok(!lstrcmpW(test_w, test), "test_w got modified\n"); 899 return 0; 900 } 901 case WM_NOTIFYFORMAT: 902 if (lParam == NF_QUERY) return NFR_ANSI; 903 break; 904 } 905 return DefWindowProcA(hwnd, message, wParam, lParam); 906 } 907 908 static BOOL register_test_notify_class(void) 909 { 910 WNDCLASSA cls = {0}; 911 912 cls.lpfnWndProc = test_notify_proc; 913 cls.hInstance = GetModuleHandleA(NULL); 914 cls.lpszClassName = "Pager notify class"; 915 return RegisterClassA(&cls); 916 } 917 918 static void send_notify(HWND pager, UINT unicode, UINT ansi, LPARAM lParam, BOOL code_change) 919 { 920 NMHDR *hdr = (NMHDR *)lParam; 921 922 notify_test_info.unicode = unicode; 923 notify_test_info.id_from = 1; 924 notify_test_info.hwnd_from = child1_wnd; 925 notify_test_info.ansi = ansi; 926 notify_test_info.received = FALSE; 927 928 hdr->code = unicode; 929 hdr->idFrom = 1; 930 hdr->hwndFrom = child1_wnd; 931 932 SendMessageW(pager, WM_NOTIFY, hdr->idFrom, lParam); 933 ok(notify_test_info.received, "Expect notification received\n"); 934 ok(hdr->code == code_change ? ansi : unicode, "Expect 0x%08x, got 0x%08x\n", hdr->code, 935 code_change ? ansi : unicode); 936 } 937 938 /* Send notify to test text field conversion. In parent proc notify_generic_text_handler() handles these messages */ 939 static void test_notify_generic_text_helper(HWND pager, const struct generic_text_helper_para *para) 940 { 941 const struct notify_test_send *send_data; 942 const struct notify_test_receive *receive_data; 943 INT array_size; 944 INT i; 945 946 notify_test_info.flags = para->flags; 947 notify_test_info.handler_id = para->handler_id; 948 949 if (para->flags & (CONVERT_SEND | DONT_CONVERT_SEND)) 950 { 951 if (para->flags & CONVERT_SEND) 952 { 953 notify_test_info.test_id = CONVERT_SEND; 954 send_data = test_convert_send_data; 955 array_size = ARRAY_SIZE(test_convert_send_data); 956 } 957 else 958 { 959 notify_test_info.test_id = DONT_CONVERT_SEND; 960 send_data = test_dont_convert_send_data; 961 array_size = ARRAY_SIZE(test_dont_convert_send_data); 962 } 963 964 for (i = 0; i < array_size; i++) 965 { 966 const struct notify_test_send *data = send_data + i; 967 notify_test_info.sub_test_id = i; 968 969 memset(para->ptr, 0, para->size); 970 if (para->mask) *para->mask = para->required_mask; 971 if (data->send_text) 972 { 973 memcpy(buffer, data->send_text, data->send_text_size); 974 *para->text = buffer; 975 } 976 if (para->text_max) *para->text_max = data->send_text_max; 977 send_notify(pager, para->code_unicode, para->code_ansi, (LPARAM)para->ptr, TRUE); 978 } 979 } 980 981 if (para->flags & (CONVERT_RECEIVE | DONT_CONVERT_RECEIVE)) 982 { 983 if (para->flags & CONVERT_RECEIVE) 984 { 985 notify_test_info.test_id = CONVERT_RECEIVE; 986 receive_data = test_convert_receive_data; 987 array_size = ARRAY_SIZE(test_convert_receive_data); 988 } 989 else 990 { 991 notify_test_info.test_id = DONT_CONVERT_RECEIVE; 992 receive_data = test_dont_convert_receive_data; 993 array_size = ARRAY_SIZE(test_dont_convert_receive_data); 994 } 995 996 for (i = 0; i < array_size; i++) 997 { 998 const struct notify_test_receive *data = receive_data + i; 999 notify_test_info.sub_test_id = i; 1000 1001 memset(para->ptr, 0, para->size); 1002 if (para->mask) *para->mask = para->required_mask; 1003 if (data->send_text) 1004 { 1005 memcpy(buffer, data->send_text, data->send_text_size); 1006 *para->text = buffer; 1007 } 1008 if (para->text_max) *para->text_max = data->send_text_max; 1009 send_notify(pager, para->code_unicode, para->code_ansi, (LPARAM)para->ptr, TRUE); 1010 if (data->return_text) 1011 { 1012 if (para->flags & CONVERT_RECEIVE) 1013 ok(!wcsncmp(data->return_text, *para->text, *para->text_max), 1014 "Code 0x%08x sub test %d expect %s, got %s\n", para->code_unicode, i, 1015 wine_dbgstr_w((WCHAR *)data->return_text), wine_dbgstr_w(*para->text)); 1016 else 1017 ok(!lstrcmpA(data->return_text, (CHAR *)*para->text), "Code 0x%08x sub test %d expect %s, got %s\n", 1018 para->code_unicode, i, (CHAR *)data->return_text, (CHAR *)*para->text); 1019 } 1020 if (para->text_max) 1021 ok(data->return_text_max == *para->text_max, "Code 0x%08x sub test %d expect %d, got %d\n", 1022 para->code_unicode, i, data->return_text_max, *para->text_max); 1023 } 1024 } 1025 1026 /* Extra tests for other behavior flags that are not worth it to create their own test arrays */ 1027 memset(para->ptr, 0, para->size); 1028 if (para->mask) *para->mask = para->required_mask; 1029 if (para->text_max) *para->text_max = 1; 1030 if (para->flags & SEND_EMPTY_IF_NULL) 1031 notify_test_info.test_id = SEND_EMPTY_IF_NULL; 1032 else 1033 notify_test_info.test_id = DONT_SEND_EMPTY_IF_NULL; 1034 send_notify(pager, para->code_unicode, para->code_ansi, (LPARAM)para->ptr, TRUE); 1035 1036 notify_test_info.test_id = SET_NULL_IF_NO_MASK; 1037 memset(para->ptr, 0, para->size); 1038 memset(buffer, 0, sizeof(buffer)); 1039 *para->text = buffer; 1040 if (para->text_max) *para->text_max = ARRAY_SIZE(buffer); 1041 send_notify(pager, para->code_unicode, para->code_ansi, (LPARAM)para->ptr, TRUE); 1042 if(para->flags & SET_NULL_IF_NO_MASK) 1043 ok(!*para->text, "Expect null text\n"); 1044 } 1045 1046 static void test_wm_notify_comboboxex(HWND pager) 1047 { 1048 static NMCBEDRAGBEGINW nmcbedb; 1049 static NMCBEENDEDITW nmcbeed; 1050 1051 /* CBEN_DRAGBEGIN */ 1052 memset(&nmcbedb, 0, sizeof(nmcbedb)); 1053 memcpy(nmcbedb.szText, test_w, sizeof(test_w)); 1054 send_notify(pager, CBEN_DRAGBEGINW, CBEN_DRAGBEGINA, (LPARAM)&nmcbedb, FALSE); 1055 ok(!lstrcmpW(nmcbedb.szText, test_w), "Expect %s, got %s\n", wine_dbgstr_w(test_w), wine_dbgstr_w(nmcbedb.szText)); 1056 1057 /* CBEN_ENDEDIT */ 1058 memset(&nmcbeed, 0, sizeof(nmcbeed)); 1059 memcpy(nmcbeed.szText, test_w, sizeof(test_w)); 1060 send_notify(pager, CBEN_ENDEDITW, CBEN_ENDEDITA, (LPARAM)&nmcbeed, FALSE); 1061 ok(!lstrcmpW(nmcbeed.szText, test_w), "Expect %s, got %s\n", wine_dbgstr_w(test_w), wine_dbgstr_w(nmcbeed.szText)); 1062 } 1063 1064 static void test_wm_notify_datetime(HWND pager) 1065 { 1066 const struct notify_test_datetime_format *data; 1067 NMDATETIMEFORMATW nmdtf; 1068 INT i; 1069 1070 for (i = 0; i < ARRAY_SIZE(test_datetime_format_data); i++) 1071 { 1072 data = test_datetime_format_data + i; 1073 notify_test_info.sub_test_id = i; 1074 1075 memset(&nmdtf, 0, sizeof(nmdtf)); 1076 if(data->send_pszformat) nmdtf.pszFormat = data->send_pszformat; 1077 nmdtf.pszDisplay = nmdtf.szDisplay; 1078 send_notify(pager, DTN_FORMATW, DTN_FORMATA, (LPARAM)&nmdtf, TRUE); 1079 if (data->return_szdisplay) 1080 ok(!lstrcmpW(nmdtf.szDisplay, data->return_szdisplay), "Sub test %d expect %s, got %s\n", i, 1081 wine_dbgstr_w(data->return_szdisplay), wine_dbgstr_w(nmdtf.szDisplay)); 1082 if (data->return_pszdisplay) 1083 ok(!lstrcmpW(nmdtf.pszDisplay, data->return_pszdisplay), "Sub test %d expect %s, got %s\n", i, 1084 wine_dbgstr_w(data->return_pszdisplay), wine_dbgstr_w(nmdtf.pszDisplay)); 1085 } 1086 } 1087 1088 static void test_wm_notify_header(HWND pager) 1089 { 1090 NMHEADERW nmh = {{0}}; 1091 HDITEMW hdi = {0}; 1092 HD_TEXTFILTERW hdtf = {0}; 1093 1094 hdi.mask = HDI_TEXT | HDI_FILTER; 1095 hdi.pszText = (WCHAR *)test_w; 1096 hdtf.pszText = (WCHAR *)test_w; 1097 nmh.pitem = &hdi; 1098 nmh.pitem->pvFilter = &hdtf; 1099 send_notify(pager, HDN_BEGINDRAG, HDN_BEGINDRAG, (LPARAM)&nmh, TRUE); 1100 send_notify(pager, HDN_ENDDRAG, HDN_ENDDRAG, (LPARAM)&nmh, TRUE); 1101 send_notify(pager, HDN_BEGINFILTEREDIT, HDN_BEGINFILTEREDIT, (LPARAM)&nmh, TRUE); 1102 send_notify(pager, HDN_ENDFILTEREDIT, HDN_ENDFILTEREDIT, (LPARAM)&nmh, TRUE); 1103 send_notify(pager, HDN_DROPDOWN, HDN_DROPDOWN, (LPARAM)&nmh, TRUE); 1104 send_notify(pager, HDN_FILTERCHANGE, HDN_FILTERCHANGE, (LPARAM)&nmh, TRUE); 1105 send_notify(pager, HDN_ITEMKEYDOWN, HDN_ITEMKEYDOWN, (LPARAM)&nmh, TRUE); 1106 send_notify(pager, HDN_ITEMSTATEICONCLICK, HDN_ITEMSTATEICONCLICK, (LPARAM)&nmh, TRUE); 1107 send_notify(pager, HDN_OVERFLOWCLICK, HDN_OVERFLOWCLICK, (LPARAM)&nmh, TRUE); 1108 send_notify(pager, HDN_BEGINTRACKW, HDN_BEGINTRACKA, (LPARAM)&nmh, TRUE); 1109 send_notify(pager, HDN_DIVIDERDBLCLICKW, HDN_DIVIDERDBLCLICKA, (LPARAM)&nmh, TRUE); 1110 send_notify(pager, HDN_ENDTRACKW, HDN_ENDTRACKA, (LPARAM)&nmh, TRUE); 1111 send_notify(pager, HDN_ITEMCHANGEDW, HDN_ITEMCHANGEDA, (LPARAM)&nmh, TRUE); 1112 send_notify(pager, HDN_ITEMCHANGINGW, HDN_ITEMCHANGINGA, (LPARAM)&nmh, TRUE); 1113 send_notify(pager, HDN_ITEMCLICKW, HDN_ITEMCLICKA, (LPARAM)&nmh, TRUE); 1114 send_notify(pager, HDN_ITEMDBLCLICKW, HDN_ITEMDBLCLICKA, (LPARAM)&nmh, TRUE); 1115 send_notify(pager, HDN_TRACKW, HDN_TRACKA, (LPARAM)&nmh, TRUE); 1116 } 1117 1118 static void test_wm_notify_tooltip(HWND pager) 1119 { 1120 NMTTDISPINFOW nmttdi; 1121 const struct notify_test_tooltip *data; 1122 INT i; 1123 1124 for (i = 0; i < ARRAY_SIZE(test_tooltip_data); i++) 1125 { 1126 data = test_tooltip_data + i; 1127 notify_test_info.sub_test_id = i; 1128 1129 memset(&nmttdi, 0, sizeof(nmttdi)); 1130 if (data->send_sztext) memcpy(nmttdi.szText, data->send_sztext, data->send_sztext_size); 1131 if (data->send_lpsztext) nmttdi.lpszText = (WCHAR *)data->send_lpsztext; 1132 send_notify(pager, TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE); 1133 if (data->return_sztext) 1134 { 1135 if (data->return_sztext_size == -1) 1136 ok(!lstrcmpW(nmttdi.szText, data->return_sztext), "Sub test %d expect %s, got %s\n", i, 1137 wine_dbgstr_w(data->return_sztext), wine_dbgstr_w(nmttdi.szText)); 1138 else 1139 ok(!memcmp(nmttdi.szText, data->return_sztext, data->return_sztext_size), "Wrong szText content\n"); 1140 } 1141 if (data->return_lpsztext) 1142 { 1143 if (IS_INTRESOURCE(data->return_lpsztext)) 1144 ok(nmttdi.lpszText == data->return_lpsztext, "Sub test %d expect %s, got %s\n", i, 1145 wine_dbgstr_w(data->return_lpsztext), wine_dbgstr_w(nmttdi.lpszText)); 1146 else 1147 ok(!lstrcmpW(nmttdi.lpszText, data->return_lpsztext), "Test %d expect %s, got %s\n", i, 1148 wine_dbgstr_w(data->return_lpsztext), wine_dbgstr_w(nmttdi.lpszText)); 1149 } 1150 if (data->return_hinst) 1151 ok(nmttdi.hinst == data->return_hinst, "Sub test %d expect %p, got %p\n", i, data->return_hinst, 1152 nmttdi.hinst); 1153 } 1154 } 1155 1156 static void test_wm_notify(void) 1157 { 1158 static const CHAR *class = "Pager notify class"; 1159 HWND parent, pager; 1160 /* Combo Box Ex */ 1161 static NMCOMBOBOXEXW nmcbe; 1162 /* Date and Time Picker */ 1163 static NMDATETIMEFORMATQUERYW nmdtfq; 1164 static NMDATETIMEWMKEYDOWNW nmdtkd; 1165 static NMDATETIMESTRINGW nmdts; 1166 /* Header */ 1167 static NMHDDISPINFOW nmhddi; 1168 /* List View */ 1169 static NMLVDISPINFOW nmlvdi; 1170 static NMLVGETINFOTIPW nmlvgit; 1171 static NMLVFINDITEMW nmlvfi; 1172 /* Tool Bar */ 1173 static NMTBRESTORE nmtbr; 1174 static NMTBSAVE nmtbs; 1175 static NMTOOLBARW nmtb; 1176 static NMTBDISPINFOW nmtbdi; 1177 static NMTBGETINFOTIPW nmtbgit; 1178 /* Tree View */ 1179 static NMTVDISPINFOW nmtvdi; 1180 static NMTVGETINFOTIPW nmtvgit; 1181 static NMTREEVIEWW nmtv; 1182 static const struct generic_text_helper_para paras[] = 1183 { 1184 /* Combo Box Ex */ 1185 {&nmcbe, sizeof(nmcbe), &nmcbe.ceItem.mask, CBEIF_TEXT, &nmcbe.ceItem.pszText, &nmcbe.ceItem.cchTextMax, 1186 CBEN_INSERTITEM, CBEN_INSERTITEM, DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE}, 1187 {&nmcbe, sizeof(nmcbe), &nmcbe.ceItem.mask, CBEIF_TEXT, &nmcbe.ceItem.pszText, &nmcbe.ceItem.cchTextMax, 1188 CBEN_DELETEITEM, CBEN_DELETEITEM, DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE}, 1189 {&nmcbe, sizeof(nmcbe), &nmcbe.ceItem.mask, CBEIF_TEXT, &nmcbe.ceItem.pszText, &nmcbe.ceItem.cchTextMax, 1190 CBEN_GETDISPINFOW, CBEN_GETDISPINFOA, ZERO_SEND | SET_NULL_IF_NO_MASK | DONT_CONVERT_SEND | CONVERT_RECEIVE}, 1191 /* Date and Time Picker */ 1192 {&nmdtfq, sizeof(nmdtfq), NULL, 0, (WCHAR **)&nmdtfq.pszFormat, NULL, DTN_FORMATQUERYW, DTN_FORMATQUERYA, 1193 CONVERT_SEND}, 1194 {&nmdtkd, sizeof(nmdtkd), NULL, 0, (WCHAR **)&nmdtkd.pszFormat, NULL, DTN_WMKEYDOWNW, DTN_WMKEYDOWNA, 1195 CONVERT_SEND}, 1196 {&nmdts, sizeof(nmdts), NULL, 0, (WCHAR **)&nmdts.pszUserString, NULL, DTN_USERSTRINGW, DTN_USERSTRINGA, 1197 CONVERT_SEND}, 1198 /* Header */ 1199 {&nmhddi, sizeof(nmhddi), &nmhddi.mask, HDI_TEXT, &nmhddi.pszText, &nmhddi.cchTextMax, HDN_GETDISPINFOW, 1200 HDN_GETDISPINFOA, SEND_EMPTY_IF_NULL | CONVERT_SEND | CONVERT_RECEIVE}, 1201 /* List View */ 1202 {&nmlvfi, sizeof(nmlvfi), &nmlvfi.lvfi.flags, LVFI_STRING, (WCHAR **)&nmlvfi.lvfi.psz, NULL, 1203 LVN_INCREMENTALSEARCHW, LVN_INCREMENTALSEARCHA, CONVERT_SEND}, 1204 {&nmlvfi, sizeof(nmlvfi), &nmlvfi.lvfi.flags, LVFI_SUBSTRING, (WCHAR **)&nmlvfi.lvfi.psz, NULL, LVN_ODFINDITEMW, 1205 LVN_ODFINDITEMA, CONVERT_SEND}, 1206 {&nmlvdi, sizeof(nmlvdi), &nmlvdi.item.mask, LVIF_TEXT, &nmlvdi.item.pszText, &nmlvdi.item.cchTextMax, 1207 LVN_BEGINLABELEDITW, LVN_BEGINLABELEDITA, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE}, 1208 {&nmlvdi, sizeof(nmlvdi), &nmlvdi.item.mask, LVIF_TEXT, &nmlvdi.item.pszText, &nmlvdi.item.cchTextMax, 1209 LVN_ENDLABELEDITW, LVN_ENDLABELEDITA, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE}, 1210 {&nmlvdi, sizeof(nmlvdi), &nmlvdi.item.mask, LVIF_TEXT, &nmlvdi.item.pszText, &nmlvdi.item.cchTextMax, 1211 LVN_GETDISPINFOW, LVN_GETDISPINFOA, DONT_CONVERT_SEND | CONVERT_RECEIVE}, 1212 {&nmlvdi, sizeof(nmlvdi), &nmlvdi.item.mask, LVIF_TEXT, &nmlvdi.item.pszText, &nmlvdi.item.cchTextMax, 1213 LVN_SETDISPINFOW, LVN_SETDISPINFOA, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE}, 1214 {&nmlvgit, sizeof(nmlvgit), NULL, 0, &nmlvgit.pszText, &nmlvgit.cchTextMax, LVN_GETINFOTIPW, LVN_GETINFOTIPA, 1215 CONVERT_SEND | CONVERT_RECEIVE}, 1216 /* Tool Bar */ 1217 {&nmtbs, sizeof(nmtbs), NULL, 0, (WCHAR **)&nmtbs.tbButton.iString, NULL, TBN_SAVE, TBN_SAVE, 1218 DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE}, 1219 {&nmtbr, sizeof(nmtbr), NULL, 0, (WCHAR **)&nmtbr.tbButton.iString, NULL, TBN_RESTORE, TBN_RESTORE, 1220 DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE}, 1221 {&nmtbdi, sizeof(nmtbdi), &nmtbdi.dwMask, TBNF_TEXT, &nmtbdi.pszText, &nmtbdi.cchText, TBN_GETDISPINFOW, 1222 TBN_GETDISPINFOW, DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE}, 1223 {&nmtb, sizeof(nmtb), NULL, 0, &nmtb.pszText, &nmtb.cchText, TBN_GETBUTTONINFOW, TBN_GETBUTTONINFOA, 1224 SEND_EMPTY_IF_NULL | CONVERT_SEND | CONVERT_RECEIVE}, 1225 {&nmtbgit, sizeof(nmtbgit), NULL, 0, &nmtbgit.pszText, &nmtbgit.cchTextMax, TBN_GETINFOTIPW, TBN_GETINFOTIPA, 1226 DONT_CONVERT_SEND | CONVERT_RECEIVE}, 1227 /* Tree View */ 1228 {&nmtvdi, sizeof(nmtvdi), &nmtvdi.item.mask, TVIF_TEXT, &nmtvdi.item.pszText, &nmtvdi.item.cchTextMax, 1229 TVN_BEGINLABELEDITW, TVN_BEGINLABELEDITA, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE}, 1230 {&nmtvdi, sizeof(nmtvdi), &nmtvdi.item.mask, TVIF_TEXT, &nmtvdi.item.pszText, &nmtvdi.item.cchTextMax, 1231 TVN_ENDLABELEDITW, TVN_ENDLABELEDITA, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE}, 1232 {&nmtvdi, sizeof(nmtvdi), &nmtvdi.item.mask, TVIF_TEXT, &nmtvdi.item.pszText, &nmtvdi.item.cchTextMax, 1233 TVN_GETDISPINFOW, TVN_GETDISPINFOA, ZERO_SEND | DONT_CONVERT_SEND| CONVERT_RECEIVE}, 1234 {&nmtvdi, sizeof(nmtvdi), &nmtvdi.item.mask, TVIF_TEXT, &nmtvdi.item.pszText, &nmtvdi.item.cchTextMax, 1235 TVN_SETDISPINFOW, TVN_SETDISPINFOA, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE}, 1236 {&nmtvgit, sizeof(nmtvgit), NULL, 0, &nmtvgit.pszText, &nmtvgit.cchTextMax, TVN_GETINFOTIPW, TVN_GETINFOTIPA, 1237 DONT_CONVERT_SEND | CONVERT_RECEIVE}, 1238 {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax, 1239 TVN_SINGLEEXPAND, TVN_SINGLEEXPAND, DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE, TVITEM_NEW_HANDLER}, 1240 {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax, 1241 TVN_SINGLEEXPAND, TVN_SINGLEEXPAND, DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE, TVITEM_OLD_HANDLER}, 1242 {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax, 1243 TVN_BEGINDRAGW, TVN_BEGINDRAGA, CONVERT_SEND, TVITEM_NEW_HANDLER}, 1244 {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax, 1245 TVN_BEGINDRAGW, TVN_BEGINDRAGA, DONT_CONVERT_SEND, TVITEM_OLD_HANDLER}, 1246 {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax, 1247 TVN_BEGINRDRAGW, TVN_BEGINRDRAGA, CONVERT_SEND, TVITEM_NEW_HANDLER}, 1248 {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax, 1249 TVN_BEGINRDRAGW, TVN_BEGINRDRAGA, DONT_CONVERT_SEND, TVITEM_OLD_HANDLER}, 1250 {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax, 1251 TVN_ITEMEXPANDEDW, TVN_ITEMEXPANDEDA, CONVERT_SEND, TVITEM_NEW_HANDLER}, 1252 {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax, 1253 TVN_ITEMEXPANDEDW, TVN_ITEMEXPANDEDA, DONT_CONVERT_SEND, TVITEM_OLD_HANDLER}, 1254 {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax, 1255 TVN_ITEMEXPANDINGW, TVN_ITEMEXPANDINGA, CONVERT_SEND, TVITEM_NEW_HANDLER}, 1256 {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax, 1257 TVN_ITEMEXPANDINGW, TVN_ITEMEXPANDINGA, DONT_CONVERT_SEND, TVITEM_OLD_HANDLER}, 1258 {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax, 1259 TVN_DELETEITEMW, TVN_DELETEITEMA, DONT_CONVERT_SEND, TVITEM_NEW_HANDLER}, 1260 {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax, 1261 TVN_DELETEITEMW, TVN_DELETEITEMA, CONVERT_SEND, TVITEM_OLD_HANDLER}, 1262 {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax, 1263 TVN_SELCHANGINGW, TVN_SELCHANGINGA, CONVERT_SEND, TVITEM_NEW_HANDLER}, 1264 {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax, 1265 TVN_SELCHANGINGW, TVN_SELCHANGINGA, CONVERT_SEND, TVITEM_OLD_HANDLER}, 1266 {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax, 1267 TVN_SELCHANGEDW, TVN_SELCHANGEDA, CONVERT_SEND, TVITEM_NEW_HANDLER}, 1268 {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax, 1269 TVN_SELCHANGEDW, TVN_SELCHANGEDA, CONVERT_SEND, TVITEM_OLD_HANDLER} 1270 }; 1271 BOOL bret; 1272 INT i; 1273 1274 bret = register_test_notify_class(); 1275 ok(bret, "Register test class failed, error 0x%08x\n", GetLastError()); 1276 1277 parent = CreateWindowA(class, "parent", WS_OVERLAPPED, 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), 0); 1278 ok(parent != NULL, "CreateWindow failed\n"); 1279 pager = CreateWindowA(WC_PAGESCROLLERA, "pager", WS_CHILD, 0, 0, 100, 100, parent, 0, GetModuleHandleA(0), 0); 1280 ok(pager != NULL, "CreateWindow failed\n"); 1281 child1_wnd = CreateWindowA(class, "child", WS_CHILD, 0, 0, 100, 100, pager, (HMENU)1, GetModuleHandleA(0), 0); 1282 ok(child1_wnd != NULL, "CreateWindow failed\n"); 1283 SendMessageW(pager, PGM_SETCHILD, 0, (LPARAM)child1_wnd); 1284 1285 for (i = 0; i < ARRAY_SIZE(paras); i++) 1286 test_notify_generic_text_helper(pager, paras + i); 1287 1288 /* Tests for those that can't be covered by generic text test helper */ 1289 test_wm_notify_comboboxex(pager); 1290 test_wm_notify_datetime(pager); 1291 test_wm_notify_header(pager); 1292 test_wm_notify_tooltip(pager); 1293 1294 DestroyWindow(parent); 1295 UnregisterClassA(class, GetModuleHandleA(NULL)); 1296 } 1297 1298 static void init_functions(void) 1299 { 1300 HMODULE mod = LoadLibraryA("comctl32.dll"); 1301 1302 #define X(f) p##f = (void*)GetProcAddress(mod, #f); 1303 X(InitCommonControlsEx); 1304 #undef X 1305 1306 pSetWindowSubclass = (void*)GetProcAddress(mod, (LPSTR)410); 1307 } 1308 1309 START_TEST(pager) 1310 { 1311 INITCOMMONCONTROLSEX iccex; 1312 1313 init_functions(); 1314 1315 iccex.dwSize = sizeof(iccex); 1316 iccex.dwICC = ICC_PAGESCROLLER_CLASS; 1317 pInitCommonControlsEx(&iccex); 1318 1319 init_msg_sequences(sequences, NUM_MSG_SEQUENCES); 1320 1321 parent_wnd = create_parent_window(); 1322 ok(parent_wnd != NULL, "Failed to create parent window!\n"); 1323 1324 test_pager(); 1325 test_wm_notifyformat(); 1326 test_wm_notify(); 1327 1328 DestroyWindow(parent_wnd); 1329 } 1330