1f4e38f0ebd2db60de4b760ed30b34d19715d78c
[reactos.git] / modules / rostests / winetests / comctl32 / updown.c
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 }