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