1 /* Unit tests for the up-down control 2 * 3 * Copyright 2005 C. Scott Ananian 4 * Copyright (C) 2007 James Hawkins 5 * Copyright (C) 2007 Leslie Choong 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 /* TO TEST: 23 * - send click messages to the up-down control, check the current position 24 * - up-down control automatically positions itself next to its buddy window 25 * - up-down control sets the caption of the buddy window 26 * - test CreateUpDownControl API 27 * - check UDS_AUTOBUDDY style, up-down control selects previous window in z-order 28 * - check UDM_SETBUDDY message 29 * - check UDM_GETBUDDY message 30 * - up-down control and buddy control must have the same parent 31 * - up-down control notifies its parent window when its position changes with UDN_DELTAPOS + WM_VSCROLL or WM_HSCROLL 32 * - check UDS_ALIGN[LEFT,RIGHT]...check that width of buddy window is decreased 33 * - check that UDS_SETBUDDYINT sets the caption of the buddy window when it is changed 34 * - check that the thousands operator is set for large numbers 35 * - check that the thousands operator is not set with UDS_NOTHOUSANDS 36 * - check UDS_ARROWKEYS, control subclasses the buddy window so that it processes the keys when it has focus 37 * - check UDS_HORZ 38 * - check changing past min/max values 39 * - check UDS_WRAP wraps values past min/max, incrementing past upper value wraps position to lower value 40 * - can change control's position, min/max pos, radix 41 * - check UDM_GETPOS, for up-down control with a buddy window, position is the caption of the buddy window, so change the 42 * caption of the buddy window then call UDM_GETPOS 43 * - check UDM_SETRANGE, max can be less than min, so clicking the up arrow decreases the current position 44 * - more stuff to test 45 */ 46 47 #include "precomp.h" 48 49 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT)) 50 51 #define NUM_MSG_SEQUENCES 3 52 #define PARENT_SEQ_INDEX 0 53 #define EDIT_SEQ_INDEX 1 54 #define UPDOWN_SEQ_INDEX 2 55 56 #define UPDOWN_ID 0 57 #define BUDDY_ID 1 58 59 static HWND parent_wnd, g_edit; 60 61 static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR); 62 63 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES]; 64 65 static const struct message add_updown_with_edit_seq[] = { 66 { WM_WINDOWPOSCHANGING, sent }, 67 { WM_NCCALCSIZE, sent|wparam, TRUE }, 68 { WM_WINDOWPOSCHANGED, sent }, 69 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED /*, MAKELONG(91, 75) exact size depends on font */ }, 70 { 0 } 71 }; 72 73 static const struct message add_updown_to_parent_seq[] = { 74 { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY }, 75 { WM_QUERYUISTATE, sent|optional }, 76 { WM_PARENTNOTIFY, sent|wparam, MAKELONG(WM_CREATE, WM_CREATE) }, 77 { 0 } 78 }; 79 80 static const struct message get_edit_text_seq[] = { 81 { WM_GETTEXT, sent }, 82 { 0 } 83 }; 84 85 static const struct message test_updown_pos_seq[] = { 86 { UDM_SETRANGE, sent|lparam, 0, MAKELONG(100,0) }, 87 { UDM_GETRANGE, sent}, 88 { UDM_SETPOS, sent|lparam, 0, 5}, 89 { UDM_GETPOS, sent}, 90 { UDM_SETPOS, sent|lparam, 0, 0}, 91 { UDM_GETPOS, sent}, 92 { UDM_SETPOS, sent|lparam, 0, MAKELONG(-1,0)}, 93 { UDM_GETPOS, sent}, 94 { UDM_SETPOS, sent|lparam, 0, 100}, 95 { UDM_GETPOS, sent}, 96 { UDM_SETPOS, sent|lparam, 0, 101}, 97 { UDM_GETPOS, sent}, 98 { 0 } 99 }; 100 101 static const struct message test_updown_pos32_seq[] = { 102 { UDM_SETRANGE32, sent|lparam, 0, 1000 }, 103 { UDM_GETRANGE32, sent}, /* Cannot check wparam and lparam as they are ptrs */ 104 { UDM_SETPOS32, sent|lparam, 0, 500 }, 105 { UDM_GETPOS32, sent}, 106 { UDM_SETPOS32, sent|lparam, 0, 0 }, 107 { UDM_GETPOS32, sent}, 108 { UDM_SETPOS32, sent|lparam, 0, -1 }, 109 { UDM_GETPOS32, sent}, 110 { UDM_SETPOS32, sent|lparam, 0, 1000 }, 111 { UDM_GETPOS32, sent}, 112 { UDM_SETPOS32, sent|lparam, 0, 1001 }, 113 { UDM_GETPOS32, sent}, 114 { 0 } 115 }; 116 117 static const struct message test_updown_buddy_seq[] = { 118 { UDM_GETBUDDY, sent }, 119 { UDM_SETBUDDY, sent }, 120 { WM_STYLECHANGING, sent|defwinproc }, 121 { WM_STYLECHANGED, sent|defwinproc }, 122 { WM_STYLECHANGING, sent|defwinproc }, 123 { WM_STYLECHANGED, sent|defwinproc }, 124 { WM_WINDOWPOSCHANGING, sent|defwinproc }, 125 { WM_NCCALCSIZE, sent|wparam|optional|defwinproc, 1 }, 126 { WM_WINDOWPOSCHANGED, sent|defwinproc }, 127 { WM_MOVE, sent|defwinproc }, 128 { UDM_GETBUDDY, sent }, 129 { 0 } 130 }; 131 132 static const struct message test_updown_base_seq[] = { 133 { UDM_SETBASE, sent|wparam, 10 }, 134 { UDM_GETBASE, sent }, 135 { UDM_SETBASE, sent|wparam, 80 }, 136 { UDM_GETBASE, sent }, 137 { UDM_SETBASE, sent|wparam, 16 }, 138 { UDM_GETBASE, sent }, 139 { UDM_SETBASE, sent|wparam, 80 }, 140 { UDM_GETBASE, sent }, 141 { UDM_SETBASE, sent|wparam, 10 }, 142 { UDM_GETBASE, sent }, 143 { 0 } 144 }; 145 146 static const struct message test_updown_unicode_seq[] = { 147 { UDM_SETUNICODEFORMAT, sent|wparam, 0 }, 148 { UDM_GETUNICODEFORMAT, sent }, 149 { UDM_SETUNICODEFORMAT, sent|wparam, 1 }, 150 { UDM_GETUNICODEFORMAT, sent }, 151 { UDM_SETUNICODEFORMAT, sent|wparam, 0 }, 152 { UDM_GETUNICODEFORMAT, sent }, 153 { 0 } 154 }; 155 156 static const struct message test_updown_pos_nochange_seq[] = { 157 { WM_GETTEXT, sent|id, 0, 0, BUDDY_ID }, 158 { 0 } 159 }; 160 161 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 162 { 163 static LONG defwndproc_counter = 0; 164 struct message msg = { 0 }; 165 LRESULT ret; 166 167 /* log system messages, except for painting */ 168 if (message < WM_USER && 169 message != WM_PAINT && 170 message != WM_ERASEBKGND && 171 message != WM_NCPAINT && 172 message != WM_NCHITTEST && 173 message != WM_GETTEXT && 174 message != WM_GETICON && 175 message != WM_DEVICECHANGE) 176 { 177 msg.message = message; 178 msg.flags = sent|wparam|lparam; 179 if (defwndproc_counter) msg.flags |= defwinproc; 180 msg.wParam = wParam; 181 msg.lParam = lParam; 182 add_message(sequences, PARENT_SEQ_INDEX, &msg); 183 } 184 185 defwndproc_counter++; 186 ret = DefWindowProcA(hwnd, message, wParam, lParam); 187 defwndproc_counter--; 188 189 return ret; 190 } 191 192 static BOOL register_parent_wnd_class(void) 193 { 194 WNDCLASSA cls; 195 196 cls.style = 0; 197 cls.lpfnWndProc = parent_wnd_proc; 198 cls.cbClsExtra = 0; 199 cls.cbWndExtra = 0; 200 cls.hInstance = GetModuleHandleA(NULL); 201 cls.hIcon = 0; 202 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); 203 cls.hbrBackground = GetStockObject(WHITE_BRUSH); 204 cls.lpszMenuName = NULL; 205 cls.lpszClassName = "Up-Down test parent class"; 206 return RegisterClassA(&cls); 207 } 208 209 static HWND create_parent_window(void) 210 { 211 if (!register_parent_wnd_class()) 212 return NULL; 213 214 return CreateWindowExA(0, "Up-Down test parent class", 215 "Up-Down test parent window", 216 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | 217 WS_MAXIMIZEBOX | WS_VISIBLE, 218 0, 0, 100, 100, 219 GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL); 220 } 221 222 static LRESULT WINAPI edit_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 223 { 224 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); 225 static LONG defwndproc_counter = 0; 226 struct message msg = { 0 }; 227 LRESULT ret; 228 229 msg.message = message; 230 msg.flags = sent|wparam|lparam; 231 if (defwndproc_counter) msg.flags |= defwinproc; 232 msg.wParam = wParam; 233 msg.lParam = lParam; 234 msg.id = BUDDY_ID; 235 add_message(sequences, EDIT_SEQ_INDEX, &msg); 236 237 defwndproc_counter++; 238 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); 239 defwndproc_counter--; 240 return ret; 241 } 242 243 static HWND create_edit_control(void) 244 { 245 WNDPROC oldproc; 246 HWND hwnd; 247 RECT rect; 248 249 GetClientRect(parent_wnd, &rect); 250 hwnd = CreateWindowExA(0, WC_EDITA, NULL, WS_CHILD | WS_BORDER | WS_VISIBLE, 251 0, 0, rect.right, rect.bottom, 252 parent_wnd, NULL, GetModuleHandleA(NULL), NULL); 253 if (!hwnd) return NULL; 254 255 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, 256 (LONG_PTR)edit_subclass_proc); 257 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc); 258 259 return hwnd; 260 } 261 262 static LRESULT WINAPI updown_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 263 { 264 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); 265 static LONG defwndproc_counter = 0; 266 struct message msg = { 0 }; 267 LRESULT ret; 268 269 msg.message = message; 270 msg.flags = sent|wparam|lparam; 271 if (defwndproc_counter) msg.flags |= defwinproc; 272 msg.wParam = wParam; 273 msg.lParam = lParam; 274 msg.id = UPDOWN_ID; 275 add_message(sequences, UPDOWN_SEQ_INDEX, &msg); 276 277 defwndproc_counter++; 278 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); 279 defwndproc_counter--; 280 281 return ret; 282 } 283 284 static HWND create_updown_control(DWORD style, HWND buddy) 285 { 286 WNDPROC oldproc; 287 HWND updown; 288 RECT rect; 289 290 GetClientRect(parent_wnd, &rect); 291 updown = CreateWindowExA(0, UPDOWN_CLASSA, NULL, WS_CHILD | WS_BORDER | WS_VISIBLE | style, 292 0, 0, rect.right, rect.bottom, 293 parent_wnd, (HMENU)1, GetModuleHandleA(NULL), NULL); 294 ok(updown != NULL, "Failed to create UpDown control.\n"); 295 if (!updown) return NULL; 296 297 SendMessageA(updown, UDM_SETBUDDY, (WPARAM)buddy, 0); 298 SendMessageA(updown, UDM_SETRANGE, 0, MAKELONG(100, 0)); 299 SendMessageA(updown, UDM_SETPOS, 0, MAKELONG(50, 0)); 300 301 oldproc = (WNDPROC)SetWindowLongPtrA(updown, GWLP_WNDPROC, 302 (LONG_PTR)updown_subclass_proc); 303 SetWindowLongPtrA(updown, GWLP_USERDATA, (LONG_PTR)oldproc); 304 305 return updown; 306 } 307 308 static void test_updown_pos(void) 309 { 310 HWND updown; 311 int r; 312 313 updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); 314 315 flush_sequences(sequences, NUM_MSG_SEQUENCES); 316 317 /* Set Range from 0 to 100 */ 318 SendMessageA(updown, UDM_SETRANGE, 0 , MAKELONG(100,0) ); 319 r = SendMessageA(updown, UDM_GETRANGE, 0,0); 320 expect(100,LOWORD(r)); 321 expect(0,HIWORD(r)); 322 323 /* Set the position to 5, return is not checked as it was set before func call */ 324 SendMessageA(updown, UDM_SETPOS, 0 , MAKELONG(5,0) ); 325 /* Since UDM_SETBUDDYINT was not set at creation HIWORD(r) will always be 1 as a return from UDM_GETPOS */ 326 /* Get the position, which should be 5 */ 327 r = SendMessageA(updown, UDM_GETPOS, 0 , 0 ); 328 expect(5,LOWORD(r)); 329 expect(1,HIWORD(r)); 330 331 /* Set the position to 0, return should be 5 */ 332 r = SendMessageA(updown, UDM_SETPOS, 0 , MAKELONG(0,0) ); 333 expect(5,r); 334 /* Get the position, which should be 0 */ 335 r = SendMessageA(updown, UDM_GETPOS, 0 , 0 ); 336 expect(0,LOWORD(r)); 337 expect(1,HIWORD(r)); 338 339 /* Set the position to -1, return should be 0 */ 340 r = SendMessageA(updown, UDM_SETPOS, 0 , MAKELONG(-1,0) ); 341 expect(0,r); 342 /* Get the position, which should be 0 */ 343 r = SendMessageA(updown, UDM_GETPOS, 0 , 0 ); 344 expect(0,LOWORD(r)); 345 expect(1,HIWORD(r)); 346 347 /* Set the position to 100, return should be 0 */ 348 r = SendMessageA(updown, UDM_SETPOS, 0 , MAKELONG(100,0) ); 349 expect(0,r); 350 /* Get the position, which should be 100 */ 351 r = SendMessageA(updown, UDM_GETPOS, 0 , 0 ); 352 expect(100,LOWORD(r)); 353 expect(1,HIWORD(r)); 354 355 /* Set the position to 101, return should be 100 */ 356 r = SendMessageA(updown, UDM_SETPOS, 0 , MAKELONG(101,0) ); 357 expect(100,r); 358 /* Get the position, which should be 100 */ 359 r = SendMessageA(updown, UDM_GETPOS, 0 , 0 ); 360 expect(100,LOWORD(r)); 361 expect(1,HIWORD(r)); 362 363 ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_pos_seq , "test updown pos", FALSE); 364 365 DestroyWindow(updown); 366 367 /* there's no attempt to update buddy Edit if text didn't change */ 368 SetWindowTextA(g_edit, "50"); 369 updown = create_updown_control(UDS_ALIGNRIGHT | UDS_SETBUDDYINT | UDS_ARROWKEYS, g_edit); 370 371 /* test sequence only on 5.8x versions */ 372 r = SendMessageA(updown, UDM_GETPOS32, 0, 0); 373 if (r) 374 { 375 UDACCEL accel; 376 377 flush_sequences(sequences, NUM_MSG_SEQUENCES); 378 379 r = SendMessageA(updown, UDM_SETPOS, 0, 50); 380 expect(50,r); 381 382 ok_sequence(sequences, EDIT_SEQ_INDEX, test_updown_pos_nochange_seq, 383 "test updown pos, no change", FALSE); 384 385 SendMessageA(updown, UDM_SETRANGE, 0, MAKELONG(1, 40)); 386 r = SendMessageA(updown, UDM_GETRANGE, 0, 0); 387 expect(1, LOWORD(r)); 388 expect(40, HIWORD(r)); 389 390 accel.nSec = 0; 391 accel.nInc = 5; 392 r = SendMessageA(updown, UDM_SETACCEL, 1, (LPARAM)&accel); 393 expect(TRUE, r); 394 395 r = SendMessageA(updown, UDM_GETPOS, 0, 0); 396 expect(40, LOWORD(r)); 397 expect(1, HIWORD(r)); 398 399 r = SendMessageA(updown, UDM_SETPOS, 0, MAKELONG(0, 0)); 400 expect(40, LOWORD(r)); 401 expect(0, HIWORD(r)); 402 403 r = SendMessageA(updown, UDM_GETPOS, 0, 0); 404 expect(1, LOWORD(r)); 405 expect(0, HIWORD(r)); 406 407 r = SendMessageA(updown, UDM_SETPOS, 0, MAKELONG(2, 0)); 408 expect(1, LOWORD(r)); 409 expect(0, HIWORD(r)); 410 411 r = SendMessageA(g_edit, WM_KEYDOWN, VK_UP, 0); 412 expect(0, r); 413 r = SendMessageA(updown, UDM_GETPOS, 0, 0); 414 expect(1, LOWORD(r)); 415 expect(0, HIWORD(r)); 416 417 r = SendMessageA(updown, UDM_SETPOS, 0, MAKELONG(50, 0)); 418 expect(1, LOWORD(r)); 419 expect(0, HIWORD(r)); 420 421 r = SendMessageA(updown, UDM_GETPOS, 0, 0); 422 expect(40, LOWORD(r)); 423 expect(0, HIWORD(r)); 424 } 425 426 DestroyWindow(updown); 427 } 428 429 static void test_updown_pos32(void) 430 { 431 HWND updown; 432 int r; 433 int low, high; 434 435 updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); 436 437 flush_sequences(sequences, NUM_MSG_SEQUENCES); 438 439 /* Set the position to 0 to 1000 */ 440 SendMessageA(updown, UDM_SETRANGE32, 0 , 1000 ); 441 442 low = high = -1; 443 r = SendMessageA(updown, UDM_GETRANGE32, (WPARAM) &low , (LPARAM) &high ); 444 expect(0,r); 445 if (low == -1) 446 { 447 win_skip("UDM_SETRANGE32/UDM_GETRANGE32 not available\n"); 448 DestroyWindow(updown); 449 return; 450 } 451 452 expect(0,low); 453 expect(1000,high); 454 455 /* Set position to 500 */ 456 r = SendMessageA(updown, UDM_SETPOS32, 0 , 500 ); 457 if (!r) 458 { 459 win_skip("UDM_SETPOS32 and UDM_GETPOS32 need 5.80\n"); 460 DestroyWindow(updown); 461 return; 462 } 463 expect(50,r); 464 465 /* Since UDM_SETBUDDYINT was not set at creation bRet will always be true as a return from UDM_GETPOS32 */ 466 467 r = SendMessageA(updown, UDM_GETPOS32, 0 , (LPARAM) &high ); 468 expect(500,r); 469 expect(1,high); 470 471 /* Set position to 0, return should be 500 */ 472 r = SendMessageA(updown, UDM_SETPOS32, 0 , 0 ); 473 expect(500,r); 474 r = SendMessageA(updown, UDM_GETPOS32, 0 , (LPARAM) &high ); 475 expect(0,r); 476 expect(1,high); 477 478 /* Set position to -1 which should become 0, return should be 0 */ 479 r = SendMessageA(updown, UDM_SETPOS32, 0 , -1 ); 480 expect(0,r); 481 r = SendMessageA(updown, UDM_GETPOS32, 0 , (LPARAM) &high ); 482 expect(0,r); 483 expect(1,high); 484 485 /* Set position to 1000, return should be 0 */ 486 r = SendMessageA(updown, UDM_SETPOS32, 0 , 1000 ); 487 expect(0,r); 488 r = SendMessageA(updown, UDM_GETPOS32, 0 , (LPARAM) &high ); 489 expect(1000,r); 490 expect(1,high); 491 492 /* Set position to 1001 which should become 1000, return should be 1000 */ 493 r = SendMessageA(updown, UDM_SETPOS32, 0 , 1001 ); 494 expect(1000,r); 495 r = SendMessageA(updown, UDM_GETPOS32, 0 , (LPARAM) &high ); 496 expect(1000,r); 497 expect(1,high); 498 499 ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_pos32_seq, "test updown pos32", FALSE); 500 501 DestroyWindow(updown); 502 503 /* there's no attempt to update buddy Edit if text didn't change */ 504 SetWindowTextA(g_edit, "50"); 505 updown = create_updown_control(UDS_ALIGNRIGHT | UDS_SETBUDDYINT, g_edit); 506 507 flush_sequences(sequences, NUM_MSG_SEQUENCES); 508 509 r = SendMessageA(updown, UDM_SETPOS32, 0, 50); 510 expect(50,r); 511 ok_sequence(sequences, EDIT_SEQ_INDEX, test_updown_pos_nochange_seq, 512 "test updown pos, no change", FALSE); 513 514 DestroyWindow(updown); 515 } 516 517 static void test_updown_buddy(void) 518 { 519 HWND updown, buddyReturn, buddy; 520 RECT rect, rect2; 521 WNDPROC proc; 522 DWORD style; 523 524 updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); 525 526 flush_sequences(sequences, NUM_MSG_SEQUENCES); 527 528 buddyReturn = (HWND)SendMessageA(updown, UDM_GETBUDDY, 0 , 0 ); 529 ok(buddyReturn == g_edit, "Expected edit handle\n"); 530 531 buddyReturn = (HWND)SendMessageA(updown, UDM_SETBUDDY, (WPARAM) g_edit, 0); 532 ok(buddyReturn == g_edit, "Expected edit handle\n"); 533 534 buddyReturn = (HWND)SendMessageA(updown, UDM_GETBUDDY, 0 , 0 ); 535 ok(buddyReturn == g_edit, "Expected edit handle\n"); 536 537 ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_buddy_seq, "test updown buddy", TRUE); 538 ok_sequence(sequences, EDIT_SEQ_INDEX, add_updown_with_edit_seq, "test updown buddy_edit", FALSE); 539 540 DestroyWindow(updown); 541 542 buddy = create_edit_control(); 543 proc = (WNDPROC)GetWindowLongPtrA(buddy, GWLP_WNDPROC); 544 545 updown= create_updown_control(UDS_ALIGNRIGHT, buddy); 546 ok(proc == (WNDPROC)GetWindowLongPtrA(buddy, GWLP_WNDPROC), "No subclassing expected\n"); 547 548 style = GetWindowLongA(updown, GWL_STYLE); 549 SetWindowLongA(updown, GWL_STYLE, style | UDS_ARROWKEYS); 550 style = GetWindowLongA(updown, GWL_STYLE); 551 ok(style & UDS_ARROWKEYS, "Expected UDS_ARROWKEYS\n"); 552 /* no subclass if UDS_ARROWKEYS set after creation */ 553 ok(proc == (WNDPROC)GetWindowLongPtrA(buddy, GWLP_WNDPROC), "No subclassing expected\n"); 554 555 DestroyWindow(updown); 556 557 updown= create_updown_control(UDS_ALIGNRIGHT | UDS_ARROWKEYS, buddy); 558 ok(proc != (WNDPROC)GetWindowLongPtrA(buddy, GWLP_WNDPROC), "Subclassing expected\n"); 559 560 if (pSetWindowSubclass) 561 { 562 /* updown uses subclass helpers for buddy on >5.8x systems */ 563 ok(GetPropA(buddy, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n"); 564 } 565 566 DestroyWindow(updown); 567 DestroyWindow(buddy); 568 569 /* Create with buddy and UDS_HORZ, reset buddy. */ 570 updown = create_updown_control(UDS_HORZ, g_edit); 571 572 buddyReturn = (HWND)SendMessageA(updown, UDM_GETBUDDY, 0, 0); 573 ok(buddyReturn == g_edit, "Unexpected buddy window.\n"); 574 575 GetClientRect(updown, &rect); 576 577 buddyReturn = (HWND)SendMessageA(updown, UDM_SETBUDDY, 0, 0); 578 ok(buddyReturn == g_edit, "Unexpected buddy window.\n"); 579 580 GetClientRect(updown, &rect2); 581 ok(EqualRect(&rect, &rect2), "Unexpected window rect.\n"); 582 583 /* Remove UDS_HORZ, reset buddy again. */ 584 style = GetWindowLongA(updown, GWL_STYLE); 585 SetWindowLongA(updown, GWL_STYLE, style & ~UDS_HORZ); 586 style = GetWindowLongA(updown, GWL_STYLE); 587 ok(!(style & UDS_HORZ), "Unexpected style.\n"); 588 589 buddyReturn = (HWND)SendMessageA(updown, UDM_SETBUDDY, 0, 0); 590 ok(buddyReturn == NULL, "Unexpected buddy window.\n"); 591 592 GetClientRect(updown, &rect2); 593 ok(EqualRect(&rect, &rect2), "Unexpected window rect.\n"); 594 595 DestroyWindow(updown); 596 597 /* Without UDS_HORZ. */ 598 updown = create_updown_control(0, g_edit); 599 600 buddyReturn = (HWND)SendMessageA(updown, UDM_GETBUDDY, 0, 0); 601 ok(buddyReturn == g_edit, "Unexpected buddy window.\n"); 602 603 GetClientRect(updown, &rect); 604 605 buddyReturn = (HWND)SendMessageA(updown, UDM_SETBUDDY, 0, 0); 606 ok(buddyReturn == g_edit, "Unexpected buddy window.\n"); 607 608 GetClientRect(updown, &rect2); 609 ok(EqualRect(&rect, &rect2), "Unexpected window rect.\n"); 610 611 DestroyWindow(updown); 612 613 /* Create without buddy. */ 614 GetClientRect(parent_wnd, &rect); 615 updown = CreateWindowExA(0, UPDOWN_CLASSA, NULL, WS_CHILD | WS_BORDER | WS_VISIBLE | UDS_HORZ, 616 0, 0, rect.right, rect.bottom, parent_wnd, (HMENU)1, GetModuleHandleA(NULL), NULL); 617 ok(updown != NULL, "Failed to create UpDown control.\n"); 618 619 GetClientRect(updown, &rect); 620 buddyReturn = (HWND)SendMessageA(updown, UDM_SETBUDDY, 0, 0); 621 ok(buddyReturn == NULL, "Unexpected buddy window.\n"); 622 GetClientRect(updown, &rect2); 623 624 ok(EqualRect(&rect, &rect2), "Unexpected window rect.\n"); 625 626 style = GetWindowLongA(updown, GWL_STYLE); 627 SetWindowLongA(updown, GWL_STYLE, style & ~UDS_HORZ); 628 629 GetClientRect(updown, &rect2); 630 ok(EqualRect(&rect, &rect2), "Unexpected window rect.\n"); 631 632 buddyReturn = (HWND)SendMessageA(updown, UDM_SETBUDDY, (WPARAM)g_edit, 0); 633 ok(buddyReturn == NULL, "Unexpected buddy window.\n"); 634 GetClientRect(updown, &rect); 635 636 buddyReturn = (HWND)SendMessageA(updown, UDM_SETBUDDY, 0, 0); 637 ok(buddyReturn == g_edit, "Unexpected buddy window.\n"); 638 GetClientRect(updown, &rect2); 639 todo_wine 640 ok(EqualRect(&rect, &rect2), "Unexpected window rect.\n"); 641 642 DestroyWindow(updown); 643 } 644 645 static void test_updown_base(void) 646 { 647 HWND updown; 648 int r; 649 CHAR text[10]; 650 651 updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); 652 653 flush_sequences(sequences, NUM_MSG_SEQUENCES); 654 655 SendMessageA(updown, UDM_SETBASE, 10 , 0); 656 r = SendMessageA(updown, UDM_GETBASE, 0 , 0); 657 expect(10,r); 658 659 /* Set base to an invalid value, should return 0 and stay at 10 */ 660 r = SendMessageA(updown, UDM_SETBASE, 80 , 0); 661 expect(0,r); 662 r = SendMessageA(updown, UDM_GETBASE, 0 , 0); 663 expect(10,r); 664 665 /* Set base to 16 now, should get 16 as the return */ 666 r = SendMessageA(updown, UDM_SETBASE, 16 , 0); 667 expect(10,r); 668 r = SendMessageA(updown, UDM_GETBASE, 0 , 0); 669 expect(16,r); 670 671 /* Set base to an invalid value, should return 0 and stay at 16 */ 672 r = SendMessageA(updown, UDM_SETBASE, 80 , 0); 673 expect(0,r); 674 r = SendMessageA(updown, UDM_GETBASE, 0 , 0); 675 expect(16,r); 676 677 /* Set base back to 10, return should be 16 */ 678 r = SendMessageA(updown, UDM_SETBASE, 10 , 0); 679 expect(16,r); 680 r = SendMessageA(updown, UDM_GETBASE, 0 , 0); 681 expect(10,r); 682 683 ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_base_seq, "test updown base", FALSE); 684 685 DestroyWindow(updown); 686 687 /* switch base with buddy attached */ 688 updown = create_updown_control(UDS_SETBUDDYINT | UDS_ALIGNRIGHT, g_edit); 689 690 r = SendMessageA(updown, UDM_SETPOS, 0, 10); 691 expect(50, r); 692 693 GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR)); 694 ok(lstrcmpA(text, "10") == 0, "Expected '10', got '%s'\n", text); 695 696 r = SendMessageA(updown, UDM_SETBASE, 16, 0); 697 expect(10, r); 698 699 GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR)); 700 /* FIXME: currently hex output isn't properly formatted, but for this 701 test only change from initial text matters */ 702 ok(lstrcmpA(text, "10") != 0, "Expected '0x000A', got '%s'\n", text); 703 704 DestroyWindow(updown); 705 } 706 707 static void test_updown_unicode(void) 708 { 709 HWND updown; 710 int r; 711 712 updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); 713 714 flush_sequences(sequences, NUM_MSG_SEQUENCES); 715 716 /* Set it to ANSI, don't check return as we don't know previous state */ 717 SendMessageA(updown, UDM_SETUNICODEFORMAT, 0 , 0); 718 r = SendMessageA(updown, UDM_GETUNICODEFORMAT, 0 , 0); 719 expect(0,r); 720 721 /* Now set it to Unicode format */ 722 r = SendMessageA(updown, UDM_SETUNICODEFORMAT, 1 , 0); 723 expect(0,r); 724 r = SendMessageA(updown, UDM_GETUNICODEFORMAT, 0 , 0); 725 if (!r) 726 { 727 win_skip("UDM_SETUNICODEFORMAT not available\n"); 728 DestroyWindow(updown); 729 return; 730 } 731 expect(1,r); 732 733 /* And now set it back to ANSI */ 734 r = SendMessageA(updown, UDM_SETUNICODEFORMAT, 0 , 0); 735 expect(1,r); 736 r = SendMessageA(updown, UDM_GETUNICODEFORMAT, 0 , 0); 737 expect(0,r); 738 739 ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_unicode_seq, "test updown unicode", FALSE); 740 741 DestroyWindow(updown); 742 } 743 744 static void test_updown_create(void) 745 { 746 CHAR text[MAX_PATH]; 747 HWND updown; 748 RECT r; 749 750 flush_sequences(sequences, NUM_MSG_SEQUENCES); 751 752 updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); 753 ok(updown != NULL, "Failed to create updown control\n"); 754 ok_sequence(sequences, PARENT_SEQ_INDEX, add_updown_to_parent_seq, "add updown control to parent", TRUE); 755 ok_sequence(sequences, EDIT_SEQ_INDEX, add_updown_with_edit_seq, "add updown control with edit", FALSE); 756 757 flush_sequences(sequences, NUM_MSG_SEQUENCES); 758 759 GetWindowTextA(g_edit, text, MAX_PATH); 760 ok(lstrlenA(text) == 0, "Expected empty string\n"); 761 ok_sequence(sequences, EDIT_SEQ_INDEX, get_edit_text_seq, "get edit text", FALSE); 762 763 DestroyWindow(updown); 764 765 /* create with zero width */ 766 updown = CreateWindowA (UPDOWN_CLASSA, 0, WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 0, 0, 767 parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); 768 ok(updown != NULL, "Failed to create updown control\n"); 769 r.right = 0; 770 GetClientRect(updown, &r); 771 ok(r.right > 0, "Expected default width, got %d\n", r.right); 772 DestroyWindow(updown); 773 /* create with really small width */ 774 updown = CreateWindowA (UPDOWN_CLASSA, 0, WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 2, 0, 775 parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); 776 ok(updown != NULL, "Failed to create updown control\n"); 777 r.right = 0; 778 GetClientRect(updown, &r); 779 ok(r.right != 2 && r.right > 0, "Expected default width, got %d\n", r.right); 780 DestroyWindow(updown); 781 /* create with width greater than default */ 782 updown = CreateWindowA (UPDOWN_CLASSA, 0, WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 100, 0, 783 parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); 784 ok(updown != NULL, "Failed to create updown control\n"); 785 r.right = 0; 786 GetClientRect(updown, &r); 787 ok(r.right < 100 && r.right > 0, "Expected default width, got %d\n", r.right); 788 DestroyWindow(updown); 789 /* create with zero height, UDS_HORZ */ 790 updown = CreateWindowA (UPDOWN_CLASSA, 0, UDS_HORZ | WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 0, 0, 791 parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); 792 ok(updown != NULL, "Failed to create updown control\n"); 793 r.bottom = 0; 794 GetClientRect(updown, &r); 795 ok(r.bottom == 0, "Expected zero height, got %d\n", r.bottom); 796 DestroyWindow(updown); 797 /* create with really small height, UDS_HORZ */ 798 updown = CreateWindowA (UPDOWN_CLASSA, 0, UDS_HORZ | WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 0, 2, 799 parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); 800 ok(updown != NULL, "Failed to create updown control\n"); 801 r.bottom = 0; 802 GetClientRect(updown, &r); 803 ok(r.bottom == 0, "Expected zero height, got %d\n", r.bottom); 804 DestroyWindow(updown); 805 /* create with height greater than default, UDS_HORZ */ 806 updown = CreateWindowA (UPDOWN_CLASSA, 0, UDS_HORZ | WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 0, 100, 807 parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); 808 ok(updown != NULL, "Failed to create updown control\n"); 809 r.bottom = 0; 810 GetClientRect(updown, &r); 811 ok(r.bottom < 100 && r.bottom > 0, "Expected default height, got %d\n", r.bottom); 812 DestroyWindow(updown); 813 } 814 815 static void test_UDS_SETBUDDYINT(void) 816 { 817 HWND updown; 818 DWORD style, ret; 819 CHAR text[10]; 820 821 /* cleanup buddy */ 822 text[0] = '\0'; 823 SetWindowTextA(g_edit, text); 824 825 /* creating without UDS_SETBUDDYINT */ 826 updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); 827 /* try to set UDS_SETBUDDYINT after creation */ 828 style = GetWindowLongA(updown, GWL_STYLE); 829 SetWindowLongA(updown, GWL_STYLE, style | UDS_SETBUDDYINT); 830 style = GetWindowLongA(updown, GWL_STYLE); 831 ok(style & UDS_SETBUDDYINT, "Expected UDS_SETBUDDY to be set\n"); 832 SendMessageA(updown, UDM_SETPOS, 0, 20); 833 GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR)); 834 ok(lstrlenA(text) == 0, "Expected empty string\n"); 835 DestroyWindow(updown); 836 837 /* creating with UDS_SETBUDDYINT */ 838 updown = create_updown_control(UDS_SETBUDDYINT | UDS_ALIGNRIGHT, g_edit); 839 GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR)); 840 /* 50 is initial value here */ 841 ok(lstrcmpA(text, "50") == 0, "Expected '50', got '%s'\n", text); 842 /* now remove style flag */ 843 style = GetWindowLongA(updown, GWL_STYLE); 844 SetWindowLongA(updown, GWL_STYLE, style & ~UDS_SETBUDDYINT); 845 SendMessageA(updown, UDM_SETPOS, 0, 20); 846 GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR)); 847 ok(lstrcmpA(text, "20") == 0, "Expected '20', got '%s'\n", text); 848 /* set edit text directly, check position */ 849 strcpy(text, "10"); 850 SetWindowTextA(g_edit, text); 851 ret = SendMessageA(updown, UDM_GETPOS, 0, 0); 852 expect(10, ret); 853 strcpy(text, "11"); 854 SetWindowTextA(g_edit, text); 855 ret = SendMessageA(updown, UDM_GETPOS, 0, 0); 856 expect(11, LOWORD(ret)); 857 expect(0, HIWORD(ret)); 858 /* set to invalid value */ 859 strcpy(text, "21st"); 860 SetWindowTextA(g_edit, text); 861 ret = SendMessageA(updown, UDM_GETPOS, 0, 0); 862 expect(11, LOWORD(ret)); 863 expect(TRUE, HIWORD(ret)); 864 /* set style back */ 865 style = GetWindowLongA(updown, GWL_STYLE); 866 SetWindowLongA(updown, GWL_STYLE, style | UDS_SETBUDDYINT); 867 SendMessageA(updown, UDM_SETPOS, 0, 30); 868 GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR)); 869 ok(lstrcmpA(text, "30") == 0, "Expected '30', got '%s'\n", text); 870 DestroyWindow(updown); 871 } 872 873 static void test_CreateUpDownControl(void) 874 { 875 HWND updown, buddy; 876 DWORD range, pos; 877 RECT rect; 878 879 GetClientRect(parent_wnd, &rect); 880 updown = CreateUpDownControl(WS_CHILD | WS_BORDER | WS_VISIBLE, 881 0, 0, rect.right, rect.bottom, parent_wnd, 1, GetModuleHandleA(NULL), g_edit, 100, 10, 50); 882 ok(updown != NULL, "Failed to create control.\n"); 883 884 buddy = (HWND)SendMessageA(updown, UDM_GETBUDDY, 0, 0); 885 ok(buddy == g_edit, "Unexpected buddy window.\n"); 886 887 range = SendMessageA(updown, UDM_GETRANGE, 0, 0); 888 ok(range == MAKELONG(100, 10), "Unexpected range.\n"); 889 890 pos = SendMessageA(updown, UDM_GETPOS, 0, 0); 891 ok(pos == MAKELONG(50, 1), "Unexpected position.\n"); 892 893 DestroyWindow(updown); 894 } 895 896 START_TEST(updown) 897 { 898 HMODULE mod = GetModuleHandleA("comctl32.dll"); 899 900 pSetWindowSubclass = (void*)GetProcAddress(mod, (LPSTR)410); 901 902 InitCommonControls(); 903 init_msg_sequences(sequences, NUM_MSG_SEQUENCES); 904 905 parent_wnd = create_parent_window(); 906 ok(parent_wnd != NULL, "Failed to create parent window!\n"); 907 g_edit = create_edit_control(); 908 ok(g_edit != NULL, "Failed to create edit control\n"); 909 910 test_updown_create(); 911 test_updown_pos(); 912 test_updown_pos32(); 913 test_updown_buddy(); 914 test_updown_base(); 915 test_updown_unicode(); 916 test_UDS_SETBUDDYINT(); 917 test_CreateUpDownControl(); 918 919 DestroyWindow(g_edit); 920 DestroyWindow(parent_wnd); 921 } 922