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 BOOL bret; 568 INT i; 569 570 bret = register_notifyformat_class(); 571 ok(bret, "Register test class failed, error 0x%08x\n", GetLastError()); 572 573 for (i = 0; i < ARRAY_SIZE(formats); i++) 574 { 575 notify_format = formats[i]; 576 parent = CreateWindowW(class_w, parent_w, WS_OVERLAPPED, 0, 0, 100, 100, 0, 0, GetModuleHandleW(0), 0); 577 ok(parent != NULL, "CreateWindow failed\n"); 578 pager = CreateWindowW(WC_PAGESCROLLERW, pager_w, WS_CHILD, 0, 0, 100, 100, parent, 0, GetModuleHandleW(0), 0); 579 ok(pager != NULL, "CreateWindow failed\n"); 580 child = CreateWindowW(class_w, child_w, WS_CHILD, 0, 0, 100, 100, pager, 0, GetModuleHandleW(0), 0); 581 ok(child != NULL, "CreateWindow failed\n"); 582 SendMessageW(pager, PGM_SETCHILD, 0, (LPARAM)child); 583 584 /* Test parent */ 585 notify_query_received = FALSE; 586 ret = SendMessageW(pager, WM_NOTIFYFORMAT, (WPARAM)parent, NF_REQUERY); 587 ok(ret == notify_format, "Expect %d, got %ld\n", notify_format, ret); 588 ok(notify_query_received, "Didn't receive notify\n"); 589 590 /* Send NF_QUERY directly to parent */ 591 notify_query_received = FALSE; 592 ret = SendMessageW(parent, WM_NOTIFYFORMAT, (WPARAM)pager, NF_QUERY); 593 ok(ret == notify_format, "Expect %d, got %ld\n", notify_format, ret); 594 ok(notify_query_received, "Didn't receive notify\n"); 595 596 /* Pager send notifications to its parent regardless of wParam */ 597 notify_query_received = FALSE; 598 ret = SendMessageW(pager, WM_NOTIFYFORMAT, (WPARAM)parent_wnd, NF_REQUERY); 599 ok(ret == notify_format, "Expect %d, got %ld\n", notify_format, ret); 600 ok(notify_query_received, "Didn't receive notify\n"); 601 602 /* Pager always wants Unicode notifications from children */ 603 ret = SendMessageW(child, WM_NOTIFYFORMAT, (WPARAM)pager, NF_REQUERY); 604 ok(ret == NFR_UNICODE, "Expect %d, got %ld\n", NFR_UNICODE, ret); 605 ret = SendMessageW(pager, WM_NOTIFYFORMAT, (WPARAM)child, NF_QUERY); 606 ok(ret == NFR_UNICODE, "Expect %d, got %ld\n", NFR_UNICODE, ret); 607 608 DestroyWindow(parent); 609 } 610 611 UnregisterClassW(class_w, GetModuleHandleW(NULL)); 612 } 613 614 static void notify_generic_text_handler(CHAR **text, INT *text_max) 615 { 616 const struct notify_test_send *send_data; 617 const struct notify_test_receive *receive_data; 618 619 switch (notify_test_info.test_id) 620 { 621 case CONVERT_SEND: 622 case DONT_CONVERT_SEND: 623 { 624 send_data = (notify_test_info.test_id == CONVERT_SEND ? test_convert_send_data : test_dont_convert_send_data) 625 + notify_test_info.sub_test_id; 626 if (notify_test_info.flags & ZERO_SEND) 627 ok(!lstrcmpA(*text, empty_a), "Code 0x%08x test 0x%08x sub test %d expect empty text, got %s\n", 628 notify_test_info.unicode, notify_test_info.test_id, notify_test_info.sub_test_id, *text); 629 else if (notify_test_info.flags & CONVERT_SEND) 630 ok(!lstrcmpA(send_data->expect_text, *text), "Code 0x%08x test 0x%08x sub test %d expect %s, got %s\n", 631 notify_test_info.unicode, notify_test_info.test_id, notify_test_info.sub_test_id, 632 (CHAR *)send_data->expect_text, *text); 633 else 634 ok(!lstrcmpW((WCHAR *)send_data->expect_text, (WCHAR *)*text), 635 "Code 0x%08x test 0x%08x sub test %d expect %s, got %s\n", notify_test_info.unicode, 636 notify_test_info.test_id, notify_test_info.sub_test_id, wine_dbgstr_w((WCHAR *)send_data->expect_text), 637 wine_dbgstr_w((WCHAR *)*text)); 638 if (text_max) 639 ok(*text_max == send_data->send_text_max, "Code 0x%08x test 0x%08x sub test %d expect %d, got %d\n", 640 notify_test_info.unicode, notify_test_info.test_id, notify_test_info.sub_test_id, 641 send_data->send_text_max, *text_max); 642 break; 643 } 644 case CONVERT_RECEIVE: 645 case DONT_CONVERT_RECEIVE: 646 { 647 receive_data = (notify_test_info.test_id == CONVERT_RECEIVE ? test_convert_receive_data : test_dont_convert_receive_data) 648 + notify_test_info.sub_test_id; 649 if (text_max) 650 ok(*text_max == receive_data->send_text_max, "Code 0x%08x test 0x%08x sub test %d expect %d, got %d\n", 651 notify_test_info.unicode, notify_test_info.test_id, notify_test_info.sub_test_id, 652 receive_data->send_text_max, *text_max); 653 654 if (receive_data->write_text) 655 memcpy(*text, receive_data->write_text, receive_data->write_text_size); 656 /* 64bit Windows will try to free the text pointer even if it's application provided when handling 657 * HDN_GETDISPINFOW. Deliberate leak here. */ 658 else if(notify_test_info.unicode == HDN_GETDISPINFOW) 659 *text = heap_strdup(receive_data->write_pointer); 660 else 661 *text = receive_data->write_pointer; 662 if (text_max && receive_data->write_text_max != -1) *text_max = receive_data->write_text_max; 663 break; 664 } 665 case SEND_EMPTY_IF_NULL: 666 ok(!lstrcmpA(*text, empty_a), "Code 0x%08x test 0x%08x sub test %d expect empty text, got %s\n", 667 notify_test_info.unicode, notify_test_info.test_id, notify_test_info.sub_test_id, *text); 668 break; 669 case DONT_SEND_EMPTY_IF_NULL: 670 ok(!*text, "Code 0x%08x test 0x%08x sub test %d expect null text\n", notify_test_info.unicode, 671 notify_test_info.test_id, notify_test_info.sub_test_id); 672 break; 673 } 674 } 675 676 static void notify_tooltip_handler(NMTTDISPINFOA *nm) 677 { 678 const struct notify_test_tooltip *data = test_tooltip_data + notify_test_info.sub_test_id; 679 ok(nm->lpszText == nm->szText, "Sub test %d expect %p, got %p\n", notify_test_info.sub_test_id, nm->szText, 680 nm->lpszText); 681 if (data->expect_sztext) 682 ok(!lstrcmpA(data->expect_sztext, nm->szText), "Sub test %d expect %s, got %s\n", notify_test_info.sub_test_id, 683 data->expect_sztext, nm->szText); 684 if (data->write_sztext) memcpy(nm->szText, data->write_sztext, data->write_sztext_size); 685 if (data->write_lpsztext) nm->lpszText = data->write_lpsztext; 686 if (data->write_hinst) nm->hinst = data->write_hinst; 687 } 688 689 static void notify_datetime_handler(NMDATETIMEFORMATA *nm) 690 { 691 const struct notify_test_datetime_format *data = test_datetime_format_data + notify_test_info.sub_test_id; 692 if (data->expect_pszformat) 693 ok(!lstrcmpA(data->expect_pszformat, nm->pszFormat), "Sub test %d expect %s, got %s\n", 694 notify_test_info.sub_test_id, data->expect_pszformat, nm->pszFormat); 695 ok(nm->pszDisplay == nm->szDisplay, "Test %d expect %p, got %p\n", notify_test_info.sub_test_id, nm->szDisplay, 696 nm->pszDisplay); 697 if (data->write_szdisplay) memcpy(nm->szDisplay, data->write_szdisplay, data->write_szdisplay_size); 698 if (data->write_pszdisplay) nm->pszDisplay = data->write_pszdisplay; 699 } 700 701 static LRESULT WINAPI test_notify_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 702 { 703 static const WCHAR test[] = {'t', 'e', 's', 't', 0}; 704 switch (message) 705 { 706 case WM_NOTIFY: 707 { 708 NMHDR *hdr = (NMHDR *)lParam; 709 710 /* Not notifications we want to test */ 711 if (!notify_test_info.unicode) break; 712 ok(!notify_test_info.received, "Extra notification received\n"); 713 714 ok(wParam == notify_test_info.id_from, "Expect %ld, got %ld\n", notify_test_info.id_from, wParam); 715 ok(hdr->code == notify_test_info.ansi, "Expect 0x%08x, got 0x%08x\n", notify_test_info.ansi, hdr->code); 716 ok(hdr->idFrom == notify_test_info.id_from, "Expect %ld, got %ld\n", notify_test_info.id_from, wParam); 717 ok(hdr->hwndFrom == notify_test_info.hwnd_from, "Expect %p, got %p\n", notify_test_info.hwnd_from, hdr->hwndFrom); 718 719 if (hdr->code != notify_test_info.ansi) 720 { 721 skip("Notification code mismatch, skipping lParam check\n"); 722 return 0; 723 } 724 switch (hdr->code) 725 { 726 /* ComboBoxEx */ 727 case CBEN_INSERTITEM: 728 case CBEN_DELETEITEM: 729 { 730 NMCOMBOBOXEXW *nmcbe = (NMCOMBOBOXEXW *)hdr; 731 notify_generic_text_handler((CHAR **)&nmcbe->ceItem.pszText, NULL); 732 break; 733 } 734 case CBEN_DRAGBEGINA: 735 { 736 NMCBEDRAGBEGINA *nmcbedb = (NMCBEDRAGBEGINA *)hdr; 737 ok(!lstrcmpA(nmcbedb->szText, test_a), "Expect %s, got %s\n", nmcbedb->szText, test_a); 738 break; 739 } 740 case CBEN_ENDEDITA: 741 { 742 NMCBEENDEDITA *nmcbeed = (NMCBEENDEDITA *)hdr; 743 ok(!lstrcmpA(nmcbeed->szText, test_a), "Expect %s, got %s\n", nmcbeed->szText, test_a); 744 break; 745 } 746 case CBEN_GETDISPINFOA: 747 { 748 NMCOMBOBOXEXA *nmcbe = (NMCOMBOBOXEXA *)hdr; 749 notify_generic_text_handler(&nmcbe->ceItem.pszText, &nmcbe->ceItem.cchTextMax); 750 break; 751 } 752 /* Date and Time Picker */ 753 case DTN_FORMATA: 754 { 755 notify_datetime_handler((NMDATETIMEFORMATA *)hdr); 756 break; 757 } 758 case DTN_FORMATQUERYA: 759 { 760 NMDATETIMEFORMATQUERYA *nmdtfq = (NMDATETIMEFORMATQUERYA *)hdr; 761 notify_generic_text_handler((CHAR **)&nmdtfq->pszFormat, NULL); 762 break; 763 } 764 case DTN_WMKEYDOWNA: 765 { 766 NMDATETIMEWMKEYDOWNA *nmdtkd = (NMDATETIMEWMKEYDOWNA *)hdr; 767 notify_generic_text_handler((CHAR **)&nmdtkd->pszFormat, NULL); 768 break; 769 } 770 case DTN_USERSTRINGA: 771 { 772 NMDATETIMESTRINGA *nmdts = (NMDATETIMESTRINGA *)hdr; 773 notify_generic_text_handler((CHAR **)&nmdts->pszUserString, NULL); 774 break; 775 } 776 /* Header */ 777 case HDN_BEGINDRAG: 778 case HDN_ENDDRAG: 779 case HDN_BEGINFILTEREDIT: 780 case HDN_ENDFILTEREDIT: 781 case HDN_DROPDOWN: 782 case HDN_FILTERCHANGE: 783 case HDN_ITEMKEYDOWN: 784 case HDN_ITEMSTATEICONCLICK: 785 case HDN_OVERFLOWCLICK: 786 { 787 NMHEADERW *nmhd = (NMHEADERW *)hdr; 788 ok(!lstrcmpW(nmhd->pitem->pszText, test_w), "Expect %s, got %s\n", wine_dbgstr_w(test_w), 789 wine_dbgstr_w(nmhd->pitem->pszText)); 790 ok(!lstrcmpW(((HD_TEXTFILTERW *)nmhd->pitem->pvFilter)->pszText, test_w), "Expect %s, got %s\n", 791 wine_dbgstr_w(test_w), wine_dbgstr_w(((HD_TEXTFILTERW *)nmhd->pitem->pvFilter)->pszText)); 792 break; 793 } 794 case HDN_BEGINTRACKA: 795 case HDN_DIVIDERDBLCLICKA: 796 case HDN_ENDTRACKA: 797 case HDN_ITEMCHANGEDA: 798 case HDN_ITEMCHANGINGA: 799 case HDN_ITEMCLICKA: 800 case HDN_ITEMDBLCLICKA: 801 case HDN_TRACKA: 802 { 803 NMHEADERA *nmhd = (NMHEADERA *)hdr; 804 ok(!lstrcmpA(nmhd->pitem->pszText, test_a), "Expect %s, got %s\n", test_a, nmhd->pitem->pszText); 805 ok(!lstrcmpA(((HD_TEXTFILTERA *)nmhd->pitem->pvFilter)->pszText, test_a), "Expect %s, got %s\n", test_a, 806 ((HD_TEXTFILTERA *)nmhd->pitem->pvFilter)->pszText); 807 break; 808 } 809 case HDN_GETDISPINFOA: 810 { 811 NMHDDISPINFOA *nmhddi = (NMHDDISPINFOA *)hdr; 812 notify_generic_text_handler(&nmhddi->pszText, &nmhddi->cchTextMax); 813 break; 814 } 815 /* List View */ 816 case LVN_BEGINLABELEDITA: 817 case LVN_ENDLABELEDITA: 818 case LVN_GETDISPINFOA: 819 case LVN_SETDISPINFOA: 820 { 821 NMLVDISPINFOA *nmlvdi = (NMLVDISPINFOA *)hdr; 822 notify_generic_text_handler(&nmlvdi->item.pszText, &nmlvdi->item.cchTextMax); 823 break; 824 } 825 case LVN_GETINFOTIPA: 826 { 827 NMLVGETINFOTIPA *nmlvgit = (NMLVGETINFOTIPA *)hdr; 828 notify_generic_text_handler(&nmlvgit->pszText, &nmlvgit->cchTextMax); 829 break; 830 } 831 case LVN_INCREMENTALSEARCHA: 832 case LVN_ODFINDITEMA: 833 { 834 NMLVFINDITEMA *nmlvfi = (NMLVFINDITEMA *)hdr; 835 notify_generic_text_handler((CHAR **)&nmlvfi->lvfi.psz, NULL); 836 break; 837 } 838 /* Toolbar */ 839 case TBN_SAVE: 840 { 841 NMTBSAVE *nmtbs = (NMTBSAVE *)hdr; 842 notify_generic_text_handler((CHAR **)&nmtbs->tbButton.iString, NULL); 843 break; 844 } 845 case TBN_RESTORE: 846 { 847 NMTBRESTORE *nmtbr = (NMTBRESTORE *)hdr; 848 notify_generic_text_handler((CHAR **)&nmtbr->tbButton.iString, NULL); 849 break; 850 } 851 case TBN_GETBUTTONINFOA: 852 { 853 NMTOOLBARA *nmtb = (NMTOOLBARA *)hdr; 854 notify_generic_text_handler(&nmtb->pszText, &nmtb->cchText); 855 break; 856 } 857 case TBN_GETDISPINFOW: 858 { 859 NMTBDISPINFOW *nmtbdi = (NMTBDISPINFOW *)hdr; 860 notify_generic_text_handler((CHAR **)&nmtbdi->pszText, &nmtbdi->cchText); 861 break; 862 } 863 case TBN_GETINFOTIPA: 864 { 865 NMTBGETINFOTIPA *nmtbgit = (NMTBGETINFOTIPA *)hdr; 866 notify_generic_text_handler(&nmtbgit->pszText, &nmtbgit->cchTextMax); 867 break; 868 } 869 /* Tooltip */ 870 case TTN_GETDISPINFOA: 871 { 872 notify_tooltip_handler((NMTTDISPINFOA *)hdr); 873 break; 874 } 875 /* Tree View */ 876 case TVN_BEGINLABELEDITA: 877 case TVN_ENDLABELEDITA: 878 case TVN_GETDISPINFOA: 879 case TVN_SETDISPINFOA: 880 { 881 NMTVDISPINFOA *nmtvdi = (NMTVDISPINFOA *)hdr; 882 notify_generic_text_handler(&nmtvdi->item.pszText, &nmtvdi->item.cchTextMax); 883 break; 884 } 885 case TVN_GETINFOTIPA: 886 { 887 NMTVGETINFOTIPA *nmtvgit = (NMTVGETINFOTIPA *)hdr; 888 notify_generic_text_handler(&nmtvgit->pszText, &nmtvgit->cchTextMax); 889 break; 890 } 891 case TVN_SINGLEEXPAND: 892 case TVN_BEGINDRAGA: 893 case TVN_BEGINRDRAGA: 894 case TVN_ITEMEXPANDEDA: 895 case TVN_ITEMEXPANDINGA: 896 case TVN_DELETEITEMA: 897 case TVN_SELCHANGINGA: 898 case TVN_SELCHANGEDA: 899 { 900 NMTREEVIEWA *nmtv = (NMTREEVIEWA *)hdr; 901 if (notify_test_info.handler_id == TVITEM_NEW_HANDLER) 902 notify_generic_text_handler((CHAR **)&nmtv->itemNew.pszText, &nmtv->itemNew.cchTextMax); 903 else 904 notify_generic_text_handler((CHAR **)&nmtv->itemOld.pszText, &nmtv->itemOld.cchTextMax); 905 break; 906 } 907 908 default: 909 ok(0, "Unexpected message 0x%08x\n", hdr->code); 910 } 911 notify_test_info.received = TRUE; 912 ok(!lstrcmpA(test_a, "test"), "test_a got modified\n"); 913 ok(!lstrcmpW(test_w, test), "test_w got modified\n"); 914 return 0; 915 } 916 case WM_NOTIFYFORMAT: 917 if (lParam == NF_QUERY) return NFR_ANSI; 918 break; 919 } 920 return DefWindowProcA(hwnd, message, wParam, lParam); 921 } 922 923 static BOOL register_test_notify_class(void) 924 { 925 WNDCLASSA cls = {0}; 926 927 cls.lpfnWndProc = test_notify_proc; 928 cls.hInstance = GetModuleHandleA(NULL); 929 cls.lpszClassName = "Pager notify class"; 930 return RegisterClassA(&cls); 931 } 932 933 static void send_notify(HWND pager, UINT unicode, UINT ansi, LPARAM lParam, BOOL code_change) 934 { 935 NMHDR *hdr = (NMHDR *)lParam; 936 937 notify_test_info.unicode = unicode; 938 notify_test_info.id_from = 1; 939 notify_test_info.hwnd_from = child1_wnd; 940 notify_test_info.ansi = ansi; 941 notify_test_info.received = FALSE; 942 943 hdr->code = unicode; 944 hdr->idFrom = 1; 945 hdr->hwndFrom = child1_wnd; 946 947 SendMessageW(pager, WM_NOTIFY, hdr->idFrom, lParam); 948 ok(notify_test_info.received, "Expect notification received\n"); 949 ok(hdr->code == code_change ? ansi : unicode, "Expect 0x%08x, got 0x%08x\n", hdr->code, 950 code_change ? ansi : unicode); 951 } 952 953 /* Send notify to test text field conversion. In parent proc notify_generic_text_handler() handles these messages */ 954 static void test_notify_generic_text_helper(HWND pager, const struct generic_text_helper_para *para) 955 { 956 const struct notify_test_send *send_data; 957 const struct notify_test_receive *receive_data; 958 INT array_size; 959 INT i; 960 961 notify_test_info.flags = para->flags; 962 notify_test_info.handler_id = para->handler_id; 963 964 if (para->flags & (CONVERT_SEND | DONT_CONVERT_SEND)) 965 { 966 if (para->flags & CONVERT_SEND) 967 { 968 notify_test_info.test_id = CONVERT_SEND; 969 send_data = test_convert_send_data; 970 array_size = ARRAY_SIZE(test_convert_send_data); 971 } 972 else 973 { 974 notify_test_info.test_id = DONT_CONVERT_SEND; 975 send_data = test_dont_convert_send_data; 976 array_size = ARRAY_SIZE(test_dont_convert_send_data); 977 } 978 979 for (i = 0; i < array_size; i++) 980 { 981 const struct notify_test_send *data = send_data + i; 982 notify_test_info.sub_test_id = i; 983 984 memset(para->ptr, 0, para->size); 985 if (para->mask) *para->mask = para->required_mask; 986 if (data->send_text) 987 { 988 memcpy(buffer, data->send_text, data->send_text_size); 989 *para->text = buffer; 990 } 991 if (para->text_max) *para->text_max = data->send_text_max; 992 send_notify(pager, para->code_unicode, para->code_ansi, (LPARAM)para->ptr, TRUE); 993 } 994 } 995 996 if (para->flags & (CONVERT_RECEIVE | DONT_CONVERT_RECEIVE)) 997 { 998 if (para->flags & CONVERT_RECEIVE) 999 { 1000 notify_test_info.test_id = CONVERT_RECEIVE; 1001 receive_data = test_convert_receive_data; 1002 array_size = ARRAY_SIZE(test_convert_receive_data); 1003 } 1004 else 1005 { 1006 notify_test_info.test_id = DONT_CONVERT_RECEIVE; 1007 receive_data = test_dont_convert_receive_data; 1008 array_size = ARRAY_SIZE(test_dont_convert_receive_data); 1009 } 1010 1011 for (i = 0; i < array_size; i++) 1012 { 1013 const struct notify_test_receive *data = receive_data + i; 1014 notify_test_info.sub_test_id = i; 1015 1016 memset(para->ptr, 0, para->size); 1017 if (para->mask) *para->mask = para->required_mask; 1018 if (data->send_text) 1019 { 1020 memcpy(buffer, data->send_text, data->send_text_size); 1021 *para->text = buffer; 1022 } 1023 if (para->text_max) *para->text_max = data->send_text_max; 1024 send_notify(pager, para->code_unicode, para->code_ansi, (LPARAM)para->ptr, TRUE); 1025 if (data->return_text) 1026 { 1027 if (para->flags & CONVERT_RECEIVE) 1028 ok(!lstrcmpW(data->return_text, *para->text), "Code 0x%08x sub test %d expect %s, got %s\n", 1029 para->code_unicode, i, wine_dbgstr_w((WCHAR *)data->return_text), wine_dbgstr_w(*para->text)); 1030 else 1031 ok(!lstrcmpA(data->return_text, (CHAR *)*para->text), "Code 0x%08x sub test %d expect %s, got %s\n", 1032 para->code_unicode, i, (CHAR *)data->return_text, (CHAR *)*para->text); 1033 } 1034 if (para->text_max) 1035 ok(data->return_text_max == *para->text_max, "Code 0x%08x sub test %d expect %d, got %d\n", 1036 para->code_unicode, i, data->return_text_max, *para->text_max); 1037 } 1038 } 1039 1040 /* Extra tests for other behavior flags that are not worth it to create their own test arrays */ 1041 memset(para->ptr, 0, para->size); 1042 if (para->mask) *para->mask = para->required_mask; 1043 if (para->text_max) *para->text_max = 1; 1044 if (para->flags & SEND_EMPTY_IF_NULL) 1045 notify_test_info.test_id = SEND_EMPTY_IF_NULL; 1046 else 1047 notify_test_info.test_id = DONT_SEND_EMPTY_IF_NULL; 1048 send_notify(pager, para->code_unicode, para->code_ansi, (LPARAM)para->ptr, TRUE); 1049 1050 notify_test_info.test_id = SET_NULL_IF_NO_MASK; 1051 memset(para->ptr, 0, para->size); 1052 memset(buffer, 0, sizeof(buffer)); 1053 *para->text = buffer; 1054 if (para->text_max) *para->text_max = ARRAY_SIZE(buffer); 1055 send_notify(pager, para->code_unicode, para->code_ansi, (LPARAM)para->ptr, TRUE); 1056 if(para->flags & SET_NULL_IF_NO_MASK) 1057 ok(!*para->text, "Expect null text\n"); 1058 } 1059 1060 static void test_wm_notify_comboboxex(HWND pager) 1061 { 1062 static NMCBEDRAGBEGINW nmcbedb; 1063 static NMCBEENDEDITW nmcbeed; 1064 1065 /* CBEN_DRAGBEGIN */ 1066 memset(&nmcbedb, 0, sizeof(nmcbedb)); 1067 memcpy(nmcbedb.szText, test_w, sizeof(test_w)); 1068 send_notify(pager, CBEN_DRAGBEGINW, CBEN_DRAGBEGINA, (LPARAM)&nmcbedb, FALSE); 1069 ok(!lstrcmpW(nmcbedb.szText, test_w), "Expect %s, got %s\n", wine_dbgstr_w(test_w), wine_dbgstr_w(nmcbedb.szText)); 1070 1071 /* CBEN_ENDEDIT */ 1072 memset(&nmcbeed, 0, sizeof(nmcbeed)); 1073 memcpy(nmcbeed.szText, test_w, sizeof(test_w)); 1074 send_notify(pager, CBEN_ENDEDITW, CBEN_ENDEDITA, (LPARAM)&nmcbeed, FALSE); 1075 ok(!lstrcmpW(nmcbeed.szText, test_w), "Expect %s, got %s\n", wine_dbgstr_w(test_w), wine_dbgstr_w(nmcbeed.szText)); 1076 } 1077 1078 static void test_wm_notify_datetime(HWND pager) 1079 { 1080 const struct notify_test_datetime_format *data; 1081 NMDATETIMEFORMATW nmdtf; 1082 INT i; 1083 1084 for (i = 0; i < ARRAY_SIZE(test_datetime_format_data); i++) 1085 { 1086 data = test_datetime_format_data + i; 1087 notify_test_info.sub_test_id = i; 1088 1089 memset(&nmdtf, 0, sizeof(nmdtf)); 1090 if(data->send_pszformat) nmdtf.pszFormat = data->send_pszformat; 1091 nmdtf.pszDisplay = nmdtf.szDisplay; 1092 send_notify(pager, DTN_FORMATW, DTN_FORMATA, (LPARAM)&nmdtf, TRUE); 1093 if (data->return_szdisplay) 1094 ok(!lstrcmpW(nmdtf.szDisplay, data->return_szdisplay), "Sub test %d expect %s, got %s\n", i, 1095 wine_dbgstr_w(data->return_szdisplay), wine_dbgstr_w(nmdtf.szDisplay)); 1096 if (data->return_pszdisplay) 1097 ok(!lstrcmpW(nmdtf.pszDisplay, data->return_pszdisplay), "Sub test %d expect %s, got %s\n", i, 1098 wine_dbgstr_w(data->return_pszdisplay), wine_dbgstr_w(nmdtf.pszDisplay)); 1099 } 1100 } 1101 1102 static void test_wm_notify_header(HWND pager) 1103 { 1104 NMHEADERW nmh = {{0}}; 1105 HDITEMW hdi = {0}; 1106 HD_TEXTFILTERW hdtf = {0}; 1107 1108 hdi.mask = HDI_TEXT | HDI_FILTER; 1109 hdi.pszText = test_w; 1110 hdtf.pszText = test_w; 1111 nmh.pitem = &hdi; 1112 nmh.pitem->pvFilter = &hdtf; 1113 send_notify(pager, HDN_BEGINDRAG, HDN_BEGINDRAG, (LPARAM)&nmh, TRUE); 1114 send_notify(pager, HDN_ENDDRAG, HDN_ENDDRAG, (LPARAM)&nmh, TRUE); 1115 send_notify(pager, HDN_BEGINFILTEREDIT, HDN_BEGINFILTEREDIT, (LPARAM)&nmh, TRUE); 1116 send_notify(pager, HDN_ENDFILTEREDIT, HDN_ENDFILTEREDIT, (LPARAM)&nmh, TRUE); 1117 send_notify(pager, HDN_DROPDOWN, HDN_DROPDOWN, (LPARAM)&nmh, TRUE); 1118 send_notify(pager, HDN_FILTERCHANGE, HDN_FILTERCHANGE, (LPARAM)&nmh, TRUE); 1119 send_notify(pager, HDN_ITEMKEYDOWN, HDN_ITEMKEYDOWN, (LPARAM)&nmh, TRUE); 1120 send_notify(pager, HDN_ITEMSTATEICONCLICK, HDN_ITEMSTATEICONCLICK, (LPARAM)&nmh, TRUE); 1121 send_notify(pager, HDN_OVERFLOWCLICK, HDN_OVERFLOWCLICK, (LPARAM)&nmh, TRUE); 1122 send_notify(pager, HDN_BEGINTRACKW, HDN_BEGINTRACKA, (LPARAM)&nmh, TRUE); 1123 send_notify(pager, HDN_DIVIDERDBLCLICKW, HDN_DIVIDERDBLCLICKA, (LPARAM)&nmh, TRUE); 1124 send_notify(pager, HDN_ENDTRACKW, HDN_ENDTRACKA, (LPARAM)&nmh, TRUE); 1125 send_notify(pager, HDN_ITEMCHANGEDW, HDN_ITEMCHANGEDA, (LPARAM)&nmh, TRUE); 1126 send_notify(pager, HDN_ITEMCHANGINGW, HDN_ITEMCHANGINGA, (LPARAM)&nmh, TRUE); 1127 send_notify(pager, HDN_ITEMCLICKW, HDN_ITEMCLICKA, (LPARAM)&nmh, TRUE); 1128 send_notify(pager, HDN_ITEMDBLCLICKW, HDN_ITEMDBLCLICKA, (LPARAM)&nmh, TRUE); 1129 send_notify(pager, HDN_TRACKW, HDN_TRACKA, (LPARAM)&nmh, TRUE); 1130 } 1131 1132 static void test_wm_notify_tooltip(HWND pager) 1133 { 1134 NMTTDISPINFOW nmttdi; 1135 const struct notify_test_tooltip *data; 1136 INT i; 1137 1138 for (i = 0; i < ARRAY_SIZE(test_tooltip_data); i++) 1139 { 1140 data = test_tooltip_data + i; 1141 notify_test_info.sub_test_id = i; 1142 1143 memset(&nmttdi, 0, sizeof(nmttdi)); 1144 if (data->send_sztext) memcpy(nmttdi.szText, data->send_sztext, data->send_sztext_size); 1145 if (data->send_lpsztext) nmttdi.lpszText = data->send_lpsztext; 1146 send_notify(pager, TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE); 1147 if (data->return_sztext) 1148 { 1149 if (data->return_sztext_size == -1) 1150 ok(!lstrcmpW(nmttdi.szText, data->return_sztext), "Sub test %d expect %s, got %s\n", i, 1151 wine_dbgstr_w(data->return_sztext), wine_dbgstr_w(nmttdi.szText)); 1152 else 1153 ok(!memcmp(nmttdi.szText, data->return_sztext, data->return_sztext_size), "Wrong szText content\n"); 1154 } 1155 if (data->return_lpsztext) 1156 { 1157 if (IS_INTRESOURCE(data->return_lpsztext)) 1158 ok(nmttdi.lpszText == data->return_lpsztext, "Sub test %d expect %s, got %s\n", i, 1159 wine_dbgstr_w(data->return_lpsztext), wine_dbgstr_w(nmttdi.lpszText)); 1160 else 1161 ok(!lstrcmpW(nmttdi.lpszText, data->return_lpsztext), "Test %d expect %s, got %s\n", i, 1162 wine_dbgstr_w(data->return_lpsztext), wine_dbgstr_w(nmttdi.lpszText)); 1163 } 1164 if (data->return_hinst) 1165 ok(nmttdi.hinst == data->return_hinst, "Sub test %d expect %p, got %p\n", i, data->return_hinst, 1166 nmttdi.hinst); 1167 } 1168 } 1169 1170 static void test_wm_notify(void) 1171 { 1172 static const CHAR *class = "Pager notify class"; 1173 HWND parent, pager; 1174 /* Combo Box Ex */ 1175 static NMCOMBOBOXEXW nmcbe; 1176 /* Date and Time Picker */ 1177 static NMDATETIMEFORMATQUERYW nmdtfq; 1178 static NMDATETIMEWMKEYDOWNW nmdtkd; 1179 static NMDATETIMESTRINGW nmdts; 1180 /* Header */ 1181 static NMHDDISPINFOW nmhddi; 1182 /* List View */ 1183 static NMLVDISPINFOW nmlvdi; 1184 static NMLVGETINFOTIPW nmlvgit; 1185 static NMLVFINDITEMW nmlvfi; 1186 /* Tool Bar */ 1187 static NMTBRESTORE nmtbr; 1188 static NMTBSAVE nmtbs; 1189 static NMTOOLBARW nmtb; 1190 static NMTBDISPINFOW nmtbdi; 1191 static NMTBGETINFOTIPW nmtbgit; 1192 /* Tree View */ 1193 static NMTVDISPINFOW nmtvdi; 1194 static NMTVGETINFOTIPW nmtvgit; 1195 static NMTREEVIEWW nmtv; 1196 static const struct generic_text_helper_para paras[] = 1197 { 1198 /* Combo Box Ex */ 1199 {&nmcbe, sizeof(nmcbe), &nmcbe.ceItem.mask, CBEIF_TEXT, &nmcbe.ceItem.pszText, &nmcbe.ceItem.cchTextMax, 1200 CBEN_INSERTITEM, CBEN_INSERTITEM, DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE}, 1201 {&nmcbe, sizeof(nmcbe), &nmcbe.ceItem.mask, CBEIF_TEXT, &nmcbe.ceItem.pszText, &nmcbe.ceItem.cchTextMax, 1202 CBEN_DELETEITEM, CBEN_DELETEITEM, DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE}, 1203 {&nmcbe, sizeof(nmcbe), &nmcbe.ceItem.mask, CBEIF_TEXT, &nmcbe.ceItem.pszText, &nmcbe.ceItem.cchTextMax, 1204 CBEN_GETDISPINFOW, CBEN_GETDISPINFOA, ZERO_SEND | SET_NULL_IF_NO_MASK | DONT_CONVERT_SEND | CONVERT_RECEIVE}, 1205 /* Date and Time Picker */ 1206 {&nmdtfq, sizeof(nmdtfq), NULL, 0, (WCHAR **)&nmdtfq.pszFormat, NULL, DTN_FORMATQUERYW, DTN_FORMATQUERYA, 1207 CONVERT_SEND}, 1208 {&nmdtkd, sizeof(nmdtkd), NULL, 0, (WCHAR **)&nmdtkd.pszFormat, NULL, DTN_WMKEYDOWNW, DTN_WMKEYDOWNA, 1209 CONVERT_SEND}, 1210 {&nmdts, sizeof(nmdts), NULL, 0, (WCHAR **)&nmdts.pszUserString, NULL, DTN_USERSTRINGW, DTN_USERSTRINGA, 1211 CONVERT_SEND}, 1212 /* Header */ 1213 {&nmhddi, sizeof(nmhddi), &nmhddi.mask, HDI_TEXT, &nmhddi.pszText, &nmhddi.cchTextMax, HDN_GETDISPINFOW, 1214 HDN_GETDISPINFOA, SEND_EMPTY_IF_NULL | CONVERT_SEND | CONVERT_RECEIVE}, 1215 /* List View */ 1216 {&nmlvfi, sizeof(nmlvfi), &nmlvfi.lvfi.flags, LVFI_STRING, (WCHAR **)&nmlvfi.lvfi.psz, NULL, 1217 LVN_INCREMENTALSEARCHW, LVN_INCREMENTALSEARCHA, CONVERT_SEND}, 1218 {&nmlvfi, sizeof(nmlvfi), &nmlvfi.lvfi.flags, LVFI_SUBSTRING, (WCHAR **)&nmlvfi.lvfi.psz, NULL, LVN_ODFINDITEMW, 1219 LVN_ODFINDITEMA, CONVERT_SEND}, 1220 {&nmlvdi, sizeof(nmlvdi), &nmlvdi.item.mask, LVIF_TEXT, &nmlvdi.item.pszText, &nmlvdi.item.cchTextMax, 1221 LVN_BEGINLABELEDITW, LVN_BEGINLABELEDITA, 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_ENDLABELEDITW, LVN_ENDLABELEDITA, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE}, 1224 {&nmlvdi, sizeof(nmlvdi), &nmlvdi.item.mask, LVIF_TEXT, &nmlvdi.item.pszText, &nmlvdi.item.cchTextMax, 1225 LVN_GETDISPINFOW, LVN_GETDISPINFOA, DONT_CONVERT_SEND | CONVERT_RECEIVE}, 1226 {&nmlvdi, sizeof(nmlvdi), &nmlvdi.item.mask, LVIF_TEXT, &nmlvdi.item.pszText, &nmlvdi.item.cchTextMax, 1227 LVN_SETDISPINFOW, LVN_SETDISPINFOA, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE}, 1228 {&nmlvgit, sizeof(nmlvgit), NULL, 0, &nmlvgit.pszText, &nmlvgit.cchTextMax, LVN_GETINFOTIPW, LVN_GETINFOTIPA, 1229 CONVERT_SEND | CONVERT_RECEIVE}, 1230 /* Tool Bar */ 1231 {&nmtbs, sizeof(nmtbs), NULL, 0, (WCHAR **)&nmtbs.tbButton.iString, NULL, TBN_SAVE, TBN_SAVE, 1232 DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE}, 1233 {&nmtbr, sizeof(nmtbr), NULL, 0, (WCHAR **)&nmtbr.tbButton.iString, NULL, TBN_RESTORE, TBN_RESTORE, 1234 DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE}, 1235 {&nmtbdi, sizeof(nmtbdi), &nmtbdi.dwMask, TBNF_TEXT, &nmtbdi.pszText, &nmtbdi.cchText, TBN_GETDISPINFOW, 1236 TBN_GETDISPINFOW, DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE}, 1237 {&nmtb, sizeof(nmtb), NULL, 0, &nmtb.pszText, &nmtb.cchText, TBN_GETBUTTONINFOW, TBN_GETBUTTONINFOA, 1238 SEND_EMPTY_IF_NULL | CONVERT_SEND | CONVERT_RECEIVE}, 1239 {&nmtbgit, sizeof(nmtbgit), NULL, 0, &nmtbgit.pszText, &nmtbgit.cchTextMax, TBN_GETINFOTIPW, TBN_GETINFOTIPA, 1240 DONT_CONVERT_SEND | CONVERT_RECEIVE}, 1241 /* Tree View */ 1242 {&nmtvdi, sizeof(nmtvdi), &nmtvdi.item.mask, TVIF_TEXT, &nmtvdi.item.pszText, &nmtvdi.item.cchTextMax, 1243 TVN_BEGINLABELEDITW, TVN_BEGINLABELEDITA, 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_ENDLABELEDITW, TVN_ENDLABELEDITA, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE}, 1246 {&nmtvdi, sizeof(nmtvdi), &nmtvdi.item.mask, TVIF_TEXT, &nmtvdi.item.pszText, &nmtvdi.item.cchTextMax, 1247 TVN_GETDISPINFOW, TVN_GETDISPINFOA, ZERO_SEND | DONT_CONVERT_SEND| CONVERT_RECEIVE}, 1248 {&nmtvdi, sizeof(nmtvdi), &nmtvdi.item.mask, TVIF_TEXT, &nmtvdi.item.pszText, &nmtvdi.item.cchTextMax, 1249 TVN_SETDISPINFOW, TVN_SETDISPINFOA, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE}, 1250 {&nmtvgit, sizeof(nmtvgit), NULL, 0, &nmtvgit.pszText, &nmtvgit.cchTextMax, TVN_GETINFOTIPW, TVN_GETINFOTIPA, 1251 DONT_CONVERT_SEND | CONVERT_RECEIVE}, 1252 {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax, 1253 TVN_SINGLEEXPAND, TVN_SINGLEEXPAND, DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE, TVITEM_NEW_HANDLER}, 1254 {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax, 1255 TVN_SINGLEEXPAND, TVN_SINGLEEXPAND, DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE, TVITEM_OLD_HANDLER}, 1256 {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax, 1257 TVN_BEGINDRAGW, TVN_BEGINDRAGA, CONVERT_SEND, TVITEM_NEW_HANDLER}, 1258 {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax, 1259 TVN_BEGINDRAGW, TVN_BEGINDRAGA, DONT_CONVERT_SEND, TVITEM_OLD_HANDLER}, 1260 {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax, 1261 TVN_BEGINRDRAGW, TVN_BEGINRDRAGA, CONVERT_SEND, TVITEM_NEW_HANDLER}, 1262 {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax, 1263 TVN_BEGINRDRAGW, TVN_BEGINRDRAGA, DONT_CONVERT_SEND, TVITEM_OLD_HANDLER}, 1264 {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax, 1265 TVN_ITEMEXPANDEDW, TVN_ITEMEXPANDEDA, CONVERT_SEND, TVITEM_NEW_HANDLER}, 1266 {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax, 1267 TVN_ITEMEXPANDEDW, TVN_ITEMEXPANDEDA, DONT_CONVERT_SEND, TVITEM_OLD_HANDLER}, 1268 {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax, 1269 TVN_ITEMEXPANDINGW, TVN_ITEMEXPANDINGA, CONVERT_SEND, TVITEM_NEW_HANDLER}, 1270 {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax, 1271 TVN_ITEMEXPANDINGW, TVN_ITEMEXPANDINGA, DONT_CONVERT_SEND, TVITEM_OLD_HANDLER}, 1272 {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax, 1273 TVN_DELETEITEMW, TVN_DELETEITEMA, DONT_CONVERT_SEND, TVITEM_NEW_HANDLER}, 1274 {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax, 1275 TVN_DELETEITEMW, TVN_DELETEITEMA, CONVERT_SEND, TVITEM_OLD_HANDLER}, 1276 {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax, 1277 TVN_SELCHANGINGW, TVN_SELCHANGINGA, CONVERT_SEND, TVITEM_NEW_HANDLER}, 1278 {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax, 1279 TVN_SELCHANGINGW, TVN_SELCHANGINGA, CONVERT_SEND, TVITEM_OLD_HANDLER}, 1280 {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax, 1281 TVN_SELCHANGEDW, TVN_SELCHANGEDA, CONVERT_SEND, TVITEM_NEW_HANDLER}, 1282 {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax, 1283 TVN_SELCHANGEDW, TVN_SELCHANGEDA, CONVERT_SEND, TVITEM_OLD_HANDLER} 1284 }; 1285 BOOL bret; 1286 INT i; 1287 1288 bret = register_test_notify_class(); 1289 ok(bret, "Register test class failed, error 0x%08x\n", GetLastError()); 1290 1291 parent = CreateWindowA(class, "parent", WS_OVERLAPPED, 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), 0); 1292 ok(parent != NULL, "CreateWindow failed\n"); 1293 pager = CreateWindowA(WC_PAGESCROLLERA, "pager", WS_CHILD, 0, 0, 100, 100, parent, 0, GetModuleHandleA(0), 0); 1294 ok(pager != NULL, "CreateWindow failed\n"); 1295 child1_wnd = CreateWindowA(class, "child", WS_CHILD, 0, 0, 100, 100, pager, (HMENU)1, GetModuleHandleA(0), 0); 1296 ok(child1_wnd != NULL, "CreateWindow failed\n"); 1297 SendMessageW(pager, PGM_SETCHILD, 0, (LPARAM)child1_wnd); 1298 1299 for (i = 0; i < ARRAY_SIZE(paras); i++) 1300 test_notify_generic_text_helper(pager, paras + i); 1301 1302 /* Tests for those that can't be covered by generic text test helper */ 1303 test_wm_notify_comboboxex(pager); 1304 test_wm_notify_datetime(pager); 1305 test_wm_notify_header(pager); 1306 test_wm_notify_tooltip(pager); 1307 1308 DestroyWindow(parent); 1309 UnregisterClassA(class, GetModuleHandleA(NULL)); 1310 } 1311 1312 static void init_functions(void) 1313 { 1314 HMODULE mod = LoadLibraryA("comctl32.dll"); 1315 1316 #define X(f) p##f = (void*)GetProcAddress(mod, #f); 1317 X(InitCommonControlsEx); 1318 #undef X 1319 1320 pSetWindowSubclass = (void*)GetProcAddress(mod, (LPSTR)410); 1321 } 1322 1323 START_TEST(pager) 1324 { 1325 INITCOMMONCONTROLSEX iccex; 1326 1327 init_functions(); 1328 1329 iccex.dwSize = sizeof(iccex); 1330 iccex.dwICC = ICC_PAGESCROLLER_CLASS; 1331 pInitCommonControlsEx(&iccex); 1332 1333 init_msg_sequences(sequences, NUM_MSG_SEQUENCES); 1334 1335 parent_wnd = create_parent_window(); 1336 ok(parent_wnd != NULL, "Failed to create parent window!\n"); 1337 1338 test_pager(); 1339 test_wm_notifyformat(); 1340 test_wm_notify(); 1341 1342 DestroyWindow(parent_wnd); 1343 } 1344