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