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 = CreateUpDownControl(WS_CHILD | WS_BORDER | WS_VISIBLE | style, 292 0, 0, rect.right, rect.bottom, parent_wnd, 1, GetModuleHandleA(NULL), buddy, 293 100, 0, 50); 294 if (!updown) return NULL; 295 296 oldproc = (WNDPROC)SetWindowLongPtrA(updown, GWLP_WNDPROC, 297 (LONG_PTR)updown_subclass_proc); 298 SetWindowLongPtrA(updown, GWLP_USERDATA, (LONG_PTR)oldproc); 299 300 return updown; 301 } 302 303 static void test_updown_pos(void) 304 { 305 HWND updown; 306 int r; 307 308 updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); 309 310 flush_sequences(sequences, NUM_MSG_SEQUENCES); 311 312 /* Set Range from 0 to 100 */ 313 SendMessageA(updown, UDM_SETRANGE, 0 , MAKELONG(100,0) ); 314 r = SendMessageA(updown, UDM_GETRANGE, 0,0); 315 expect(100,LOWORD(r)); 316 expect(0,HIWORD(r)); 317 318 /* Set the position to 5, return is not checked as it was set before func call */ 319 SendMessageA(updown, UDM_SETPOS, 0 , MAKELONG(5,0) ); 320 /* Since UDM_SETBUDDYINT was not set at creation HIWORD(r) will always be 1 as a return from UDM_GETPOS */ 321 /* Get the position, which should be 5 */ 322 r = SendMessageA(updown, UDM_GETPOS, 0 , 0 ); 323 expect(5,LOWORD(r)); 324 expect(1,HIWORD(r)); 325 326 /* Set the position to 0, return should be 5 */ 327 r = SendMessageA(updown, UDM_SETPOS, 0 , MAKELONG(0,0) ); 328 expect(5,r); 329 /* Get the position, which should be 0 */ 330 r = SendMessageA(updown, UDM_GETPOS, 0 , 0 ); 331 expect(0,LOWORD(r)); 332 expect(1,HIWORD(r)); 333 334 /* Set the position to -1, return should be 0 */ 335 r = SendMessageA(updown, UDM_SETPOS, 0 , MAKELONG(-1,0) ); 336 expect(0,r); 337 /* Get the position, which should be 0 */ 338 r = SendMessageA(updown, UDM_GETPOS, 0 , 0 ); 339 expect(0,LOWORD(r)); 340 expect(1,HIWORD(r)); 341 342 /* Set the position to 100, return should be 0 */ 343 r = SendMessageA(updown, UDM_SETPOS, 0 , MAKELONG(100,0) ); 344 expect(0,r); 345 /* Get the position, which should be 100 */ 346 r = SendMessageA(updown, UDM_GETPOS, 0 , 0 ); 347 expect(100,LOWORD(r)); 348 expect(1,HIWORD(r)); 349 350 /* Set the position to 101, return should be 100 */ 351 r = SendMessageA(updown, UDM_SETPOS, 0 , MAKELONG(101,0) ); 352 expect(100,r); 353 /* Get the position, which should be 100 */ 354 r = SendMessageA(updown, UDM_GETPOS, 0 , 0 ); 355 expect(100,LOWORD(r)); 356 expect(1,HIWORD(r)); 357 358 ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_pos_seq , "test updown pos", FALSE); 359 360 DestroyWindow(updown); 361 362 /* there's no attempt to update buddy Edit if text didn't change */ 363 SetWindowTextA(g_edit, "50"); 364 updown = create_updown_control(UDS_ALIGNRIGHT | UDS_SETBUDDYINT | UDS_ARROWKEYS, g_edit); 365 366 /* test sequence only on 5.8x versions */ 367 r = SendMessageA(updown, UDM_GETPOS32, 0, 0); 368 if (r) 369 { 370 UDACCEL accel; 371 372 flush_sequences(sequences, NUM_MSG_SEQUENCES); 373 374 r = SendMessageA(updown, UDM_SETPOS, 0, 50); 375 expect(50,r); 376 377 ok_sequence(sequences, EDIT_SEQ_INDEX, test_updown_pos_nochange_seq, 378 "test updown pos, no change", FALSE); 379 380 SendMessageA(updown, UDM_SETRANGE, 0, MAKELONG(1, 40)); 381 r = SendMessageA(updown, UDM_GETRANGE, 0, 0); 382 expect(1, LOWORD(r)); 383 expect(40, HIWORD(r)); 384 385 accel.nSec = 0; 386 accel.nInc = 5; 387 r = SendMessageA(updown, UDM_SETACCEL, 1, (LPARAM)&accel); 388 expect(TRUE, r); 389 390 r = SendMessageA(updown, UDM_GETPOS, 0, 0); 391 expect(40, LOWORD(r)); 392 expect(1, HIWORD(r)); 393 394 r = SendMessageA(updown, UDM_SETPOS, 0, MAKELONG(0, 0)); 395 expect(40, LOWORD(r)); 396 expect(0, HIWORD(r)); 397 398 r = SendMessageA(updown, UDM_GETPOS, 0, 0); 399 expect(1, LOWORD(r)); 400 expect(0, HIWORD(r)); 401 402 r = SendMessageA(updown, UDM_SETPOS, 0, MAKELONG(2, 0)); 403 expect(1, LOWORD(r)); 404 expect(0, HIWORD(r)); 405 406 r = SendMessageA(g_edit, WM_KEYDOWN, VK_UP, 0); 407 expect(0, r); 408 r = SendMessageA(updown, UDM_GETPOS, 0, 0); 409 expect(1, LOWORD(r)); 410 expect(0, HIWORD(r)); 411 412 r = SendMessageA(updown, UDM_SETPOS, 0, MAKELONG(50, 0)); 413 expect(1, LOWORD(r)); 414 expect(0, HIWORD(r)); 415 416 r = SendMessageA(updown, UDM_GETPOS, 0, 0); 417 expect(40, LOWORD(r)); 418 expect(0, HIWORD(r)); 419 } 420 421 DestroyWindow(updown); 422 } 423 424 static void test_updown_pos32(void) 425 { 426 HWND updown; 427 int r; 428 int low, high; 429 430 updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); 431 432 flush_sequences(sequences, NUM_MSG_SEQUENCES); 433 434 /* Set the position to 0 to 1000 */ 435 SendMessageA(updown, UDM_SETRANGE32, 0 , 1000 ); 436 437 low = high = -1; 438 r = SendMessageA(updown, UDM_GETRANGE32, (WPARAM) &low , (LPARAM) &high ); 439 expect(0,r); 440 if (low == -1) 441 { 442 win_skip("UDM_SETRANGE32/UDM_GETRANGE32 not available\n"); 443 DestroyWindow(updown); 444 return; 445 } 446 447 expect(0,low); 448 expect(1000,high); 449 450 /* Set position to 500 */ 451 r = SendMessageA(updown, UDM_SETPOS32, 0 , 500 ); 452 if (!r) 453 { 454 win_skip("UDM_SETPOS32 and UDM_GETPOS32 need 5.80\n"); 455 DestroyWindow(updown); 456 return; 457 } 458 expect(50,r); 459 460 /* Since UDM_SETBUDDYINT was not set at creation bRet will always be true as a return from UDM_GETPOS32 */ 461 462 r = SendMessageA(updown, UDM_GETPOS32, 0 , (LPARAM) &high ); 463 expect(500,r); 464 expect(1,high); 465 466 /* Set position to 0, return should be 500 */ 467 r = SendMessageA(updown, UDM_SETPOS32, 0 , 0 ); 468 expect(500,r); 469 r = SendMessageA(updown, UDM_GETPOS32, 0 , (LPARAM) &high ); 470 expect(0,r); 471 expect(1,high); 472 473 /* Set position to -1 which should become 0, return should be 0 */ 474 r = SendMessageA(updown, UDM_SETPOS32, 0 , -1 ); 475 expect(0,r); 476 r = SendMessageA(updown, UDM_GETPOS32, 0 , (LPARAM) &high ); 477 expect(0,r); 478 expect(1,high); 479 480 /* Set position to 1000, return should be 0 */ 481 r = SendMessageA(updown, UDM_SETPOS32, 0 , 1000 ); 482 expect(0,r); 483 r = SendMessageA(updown, UDM_GETPOS32, 0 , (LPARAM) &high ); 484 expect(1000,r); 485 expect(1,high); 486 487 /* Set position to 1001 which should become 1000, return should be 1000 */ 488 r = SendMessageA(updown, UDM_SETPOS32, 0 , 1001 ); 489 expect(1000,r); 490 r = SendMessageA(updown, UDM_GETPOS32, 0 , (LPARAM) &high ); 491 expect(1000,r); 492 expect(1,high); 493 494 ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_pos32_seq, "test updown pos32", FALSE); 495 496 DestroyWindow(updown); 497 498 /* there's no attempt to update buddy Edit if text didn't change */ 499 SetWindowTextA(g_edit, "50"); 500 updown = create_updown_control(UDS_ALIGNRIGHT | UDS_SETBUDDYINT, g_edit); 501 502 flush_sequences(sequences, NUM_MSG_SEQUENCES); 503 504 r = SendMessageA(updown, UDM_SETPOS32, 0, 50); 505 expect(50,r); 506 ok_sequence(sequences, EDIT_SEQ_INDEX, test_updown_pos_nochange_seq, 507 "test updown pos, no change", FALSE); 508 509 DestroyWindow(updown); 510 } 511 512 static void test_updown_buddy(void) 513 { 514 HWND updown, buddyReturn, buddy; 515 WNDPROC proc; 516 DWORD style; 517 518 updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); 519 520 flush_sequences(sequences, NUM_MSG_SEQUENCES); 521 522 buddyReturn = (HWND)SendMessageA(updown, UDM_GETBUDDY, 0 , 0 ); 523 ok(buddyReturn == g_edit, "Expected edit handle\n"); 524 525 buddyReturn = (HWND)SendMessageA(updown, UDM_SETBUDDY, (WPARAM) g_edit, 0); 526 ok(buddyReturn == g_edit, "Expected edit handle\n"); 527 528 buddyReturn = (HWND)SendMessageA(updown, UDM_GETBUDDY, 0 , 0 ); 529 ok(buddyReturn == g_edit, "Expected edit handle\n"); 530 531 ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_buddy_seq, "test updown buddy", TRUE); 532 ok_sequence(sequences, EDIT_SEQ_INDEX, add_updown_with_edit_seq, "test updown buddy_edit", FALSE); 533 534 DestroyWindow(updown); 535 536 buddy = create_edit_control(); 537 proc = (WNDPROC)GetWindowLongPtrA(buddy, GWLP_WNDPROC); 538 539 updown= create_updown_control(UDS_ALIGNRIGHT, buddy); 540 ok(proc == (WNDPROC)GetWindowLongPtrA(buddy, GWLP_WNDPROC), "No subclassing expected\n"); 541 542 style = GetWindowLongA(updown, GWL_STYLE); 543 SetWindowLongA(updown, GWL_STYLE, style | UDS_ARROWKEYS); 544 style = GetWindowLongA(updown, GWL_STYLE); 545 ok(style & UDS_ARROWKEYS, "Expected UDS_ARROWKEYS\n"); 546 /* no subclass if UDS_ARROWKEYS set after creation */ 547 ok(proc == (WNDPROC)GetWindowLongPtrA(buddy, GWLP_WNDPROC), "No subclassing expected\n"); 548 549 DestroyWindow(updown); 550 551 updown= create_updown_control(UDS_ALIGNRIGHT | UDS_ARROWKEYS, buddy); 552 ok(proc != (WNDPROC)GetWindowLongPtrA(buddy, GWLP_WNDPROC), "Subclassing expected\n"); 553 554 if (pSetWindowSubclass) 555 { 556 /* updown uses subclass helpers for buddy on >5.8x systems */ 557 ok(GetPropA(buddy, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n"); 558 } 559 560 DestroyWindow(updown); 561 562 DestroyWindow(buddy); 563 } 564 565 static void test_updown_base(void) 566 { 567 HWND updown; 568 int r; 569 CHAR text[10]; 570 571 updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); 572 573 flush_sequences(sequences, NUM_MSG_SEQUENCES); 574 575 SendMessageA(updown, UDM_SETBASE, 10 , 0); 576 r = SendMessageA(updown, UDM_GETBASE, 0 , 0); 577 expect(10,r); 578 579 /* Set base to an invalid value, should return 0 and stay at 10 */ 580 r = SendMessageA(updown, UDM_SETBASE, 80 , 0); 581 expect(0,r); 582 r = SendMessageA(updown, UDM_GETBASE, 0 , 0); 583 expect(10,r); 584 585 /* Set base to 16 now, should get 16 as the return */ 586 r = SendMessageA(updown, UDM_SETBASE, 16 , 0); 587 expect(10,r); 588 r = SendMessageA(updown, UDM_GETBASE, 0 , 0); 589 expect(16,r); 590 591 /* Set base to an invalid value, should return 0 and stay at 16 */ 592 r = SendMessageA(updown, UDM_SETBASE, 80 , 0); 593 expect(0,r); 594 r = SendMessageA(updown, UDM_GETBASE, 0 , 0); 595 expect(16,r); 596 597 /* Set base back to 10, return should be 16 */ 598 r = SendMessageA(updown, UDM_SETBASE, 10 , 0); 599 expect(16,r); 600 r = SendMessageA(updown, UDM_GETBASE, 0 , 0); 601 expect(10,r); 602 603 ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_base_seq, "test updown base", FALSE); 604 605 DestroyWindow(updown); 606 607 /* switch base with buddy attached */ 608 updown = create_updown_control(UDS_SETBUDDYINT | UDS_ALIGNRIGHT, g_edit); 609 610 r = SendMessageA(updown, UDM_SETPOS, 0, 10); 611 expect(50, r); 612 613 GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR)); 614 ok(lstrcmpA(text, "10") == 0, "Expected '10', got '%s'\n", text); 615 616 r = SendMessageA(updown, UDM_SETBASE, 16, 0); 617 expect(10, r); 618 619 GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR)); 620 /* FIXME: currently hex output isn't properly formatted, but for this 621 test only change from initial text matters */ 622 ok(lstrcmpA(text, "10") != 0, "Expected '0x000A', got '%s'\n", text); 623 624 DestroyWindow(updown); 625 } 626 627 static void test_updown_unicode(void) 628 { 629 HWND updown; 630 int r; 631 632 updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); 633 634 flush_sequences(sequences, NUM_MSG_SEQUENCES); 635 636 /* Set it to ANSI, don't check return as we don't know previous state */ 637 SendMessageA(updown, UDM_SETUNICODEFORMAT, 0 , 0); 638 r = SendMessageA(updown, UDM_GETUNICODEFORMAT, 0 , 0); 639 expect(0,r); 640 641 /* Now set it to Unicode format */ 642 r = SendMessageA(updown, UDM_SETUNICODEFORMAT, 1 , 0); 643 expect(0,r); 644 r = SendMessageA(updown, UDM_GETUNICODEFORMAT, 0 , 0); 645 if (!r) 646 { 647 win_skip("UDM_SETUNICODEFORMAT not available\n"); 648 DestroyWindow(updown); 649 return; 650 } 651 expect(1,r); 652 653 /* And now set it back to ANSI */ 654 r = SendMessageA(updown, UDM_SETUNICODEFORMAT, 0 , 0); 655 expect(1,r); 656 r = SendMessageA(updown, UDM_GETUNICODEFORMAT, 0 , 0); 657 expect(0,r); 658 659 ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_unicode_seq, "test updown unicode", FALSE); 660 661 DestroyWindow(updown); 662 } 663 664 static void test_updown_create(void) 665 { 666 CHAR text[MAX_PATH]; 667 HWND updown; 668 RECT r; 669 670 flush_sequences(sequences, NUM_MSG_SEQUENCES); 671 672 updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); 673 ok(updown != NULL, "Failed to create updown control\n"); 674 ok_sequence(sequences, PARENT_SEQ_INDEX, add_updown_to_parent_seq, "add updown control to parent", TRUE); 675 ok_sequence(sequences, EDIT_SEQ_INDEX, add_updown_with_edit_seq, "add updown control with edit", FALSE); 676 677 flush_sequences(sequences, NUM_MSG_SEQUENCES); 678 679 GetWindowTextA(g_edit, text, MAX_PATH); 680 ok(lstrlenA(text) == 0, "Expected empty string\n"); 681 ok_sequence(sequences, EDIT_SEQ_INDEX, get_edit_text_seq, "get edit text", FALSE); 682 683 DestroyWindow(updown); 684 685 /* create with zero width */ 686 updown = CreateWindowA (UPDOWN_CLASSA, 0, WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 0, 0, 687 parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); 688 ok(updown != NULL, "Failed to create updown control\n"); 689 r.right = 0; 690 GetClientRect(updown, &r); 691 ok(r.right > 0, "Expected default width, got %d\n", r.right); 692 DestroyWindow(updown); 693 /* create with really small width */ 694 updown = CreateWindowA (UPDOWN_CLASSA, 0, WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 2, 0, 695 parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); 696 ok(updown != NULL, "Failed to create updown control\n"); 697 r.right = 0; 698 GetClientRect(updown, &r); 699 ok(r.right != 2 && r.right > 0, "Expected default width, got %d\n", r.right); 700 DestroyWindow(updown); 701 /* create with width greater than default */ 702 updown = CreateWindowA (UPDOWN_CLASSA, 0, WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 100, 0, 703 parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); 704 ok(updown != NULL, "Failed to create updown control\n"); 705 r.right = 0; 706 GetClientRect(updown, &r); 707 ok(r.right < 100 && r.right > 0, "Expected default width, got %d\n", r.right); 708 DestroyWindow(updown); 709 /* create with zero height, UDS_HORZ */ 710 updown = CreateWindowA (UPDOWN_CLASSA, 0, UDS_HORZ | WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 0, 0, 711 parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); 712 ok(updown != NULL, "Failed to create updown control\n"); 713 r.bottom = 0; 714 GetClientRect(updown, &r); 715 ok(r.bottom == 0, "Expected zero height, got %d\n", r.bottom); 716 DestroyWindow(updown); 717 /* create with really small height, UDS_HORZ */ 718 updown = CreateWindowA (UPDOWN_CLASSA, 0, UDS_HORZ | WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 0, 2, 719 parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); 720 ok(updown != NULL, "Failed to create updown control\n"); 721 r.bottom = 0; 722 GetClientRect(updown, &r); 723 ok(r.bottom == 0, "Expected zero height, got %d\n", r.bottom); 724 DestroyWindow(updown); 725 /* create with height greater than default, UDS_HORZ */ 726 updown = CreateWindowA (UPDOWN_CLASSA, 0, UDS_HORZ | WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 0, 100, 727 parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); 728 ok(updown != NULL, "Failed to create updown control\n"); 729 r.bottom = 0; 730 GetClientRect(updown, &r); 731 ok(r.bottom < 100 && r.bottom > 0, "Expected default height, got %d\n", r.bottom); 732 DestroyWindow(updown); 733 } 734 735 static void test_UDS_SETBUDDYINT(void) 736 { 737 HWND updown; 738 DWORD style, ret; 739 CHAR text[10]; 740 741 /* cleanup buddy */ 742 text[0] = '\0'; 743 SetWindowTextA(g_edit, text); 744 745 /* creating without UDS_SETBUDDYINT */ 746 updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); 747 /* try to set UDS_SETBUDDYINT after creation */ 748 style = GetWindowLongA(updown, GWL_STYLE); 749 SetWindowLongA(updown, GWL_STYLE, style | UDS_SETBUDDYINT); 750 style = GetWindowLongA(updown, GWL_STYLE); 751 ok(style & UDS_SETBUDDYINT, "Expected UDS_SETBUDDY to be set\n"); 752 SendMessageA(updown, UDM_SETPOS, 0, 20); 753 GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR)); 754 ok(lstrlenA(text) == 0, "Expected empty string\n"); 755 DestroyWindow(updown); 756 757 /* creating with UDS_SETBUDDYINT */ 758 updown = create_updown_control(UDS_SETBUDDYINT | UDS_ALIGNRIGHT, g_edit); 759 GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR)); 760 /* 50 is initial value here */ 761 ok(lstrcmpA(text, "50") == 0, "Expected '50', got '%s'\n", text); 762 /* now remove style flag */ 763 style = GetWindowLongA(updown, GWL_STYLE); 764 SetWindowLongA(updown, GWL_STYLE, style & ~UDS_SETBUDDYINT); 765 SendMessageA(updown, UDM_SETPOS, 0, 20); 766 GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR)); 767 ok(lstrcmpA(text, "20") == 0, "Expected '20', got '%s'\n", text); 768 /* set edit text directly, check position */ 769 strcpy(text, "10"); 770 SetWindowTextA(g_edit, text); 771 ret = SendMessageA(updown, UDM_GETPOS, 0, 0); 772 expect(10, ret); 773 strcpy(text, "11"); 774 SetWindowTextA(g_edit, text); 775 ret = SendMessageA(updown, UDM_GETPOS, 0, 0); 776 expect(11, LOWORD(ret)); 777 expect(0, HIWORD(ret)); 778 /* set to invalid value */ 779 strcpy(text, "21st"); 780 SetWindowTextA(g_edit, text); 781 ret = SendMessageA(updown, UDM_GETPOS, 0, 0); 782 expect(11, LOWORD(ret)); 783 expect(TRUE, HIWORD(ret)); 784 /* set style back */ 785 style = GetWindowLongA(updown, GWL_STYLE); 786 SetWindowLongA(updown, GWL_STYLE, style | UDS_SETBUDDYINT); 787 SendMessageA(updown, UDM_SETPOS, 0, 30); 788 GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR)); 789 ok(lstrcmpA(text, "30") == 0, "Expected '30', got '%s'\n", text); 790 DestroyWindow(updown); 791 } 792 793 START_TEST(updown) 794 { 795 HMODULE mod = GetModuleHandleA("comctl32.dll"); 796 797 pSetWindowSubclass = (void*)GetProcAddress(mod, (LPSTR)410); 798 799 InitCommonControls(); 800 init_msg_sequences(sequences, NUM_MSG_SEQUENCES); 801 802 parent_wnd = create_parent_window(); 803 ok(parent_wnd != NULL, "Failed to create parent window!\n"); 804 g_edit = create_edit_control(); 805 ok(g_edit != NULL, "Failed to create edit control\n"); 806 807 test_updown_create(); 808 test_updown_pos(); 809 test_updown_pos32(); 810 test_updown_buddy(); 811 test_updown_base(); 812 test_updown_unicode(); 813 test_UDS_SETBUDDYINT(); 814 815 DestroyWindow(g_edit); 816 DestroyWindow(parent_wnd); 817 } 818