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