2 * comctl32 month calendar unit tests
4 * Copyright (C) 2006 Vitaliy Margolen
5 * Copyright (C) 2007 Farshad Agah
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.
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.
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
22 #include <wine/test.h>
27 //#include "winbase.h"
35 //#include <windows.h>
38 #define expect(expected, got) ok(expected == got, "Expected %d, got %d\n", expected, got);
39 #define expect_hex(expected, got) ok(expected == got, "Expected %x, got %x\n", expected, got);
40 #define expect_d(expected, got) ok(abs((expected) - (got)) <= 2, "Expected %d, got %d\n", expected, got);
42 #define NUM_MSG_SEQUENCES 2
43 #define PARENT_SEQ_INDEX 0
44 #define MONTHCAL_SEQ_INDEX 1
46 #define SEL_NOTIFY_TEST_ID 100
48 static struct msg_sequence
*sequences
[NUM_MSG_SEQUENCES
];
50 static HWND parent_wnd
;
52 static const struct message create_parent_window_seq
[] = {
53 { WM_GETMINMAXINFO
, sent
},
54 { WM_NCCREATE
, sent
},
55 { WM_NCCALCSIZE
, sent
|wparam
, 0 },
57 { WM_SHOWWINDOW
, sent
|wparam
, 1 },
58 { WM_WINDOWPOSCHANGING
, sent
|wparam
, 0 },
59 { WM_QUERYNEWPALETTE
, sent
|optional
},
60 { WM_WINDOWPOSCHANGING
, sent
|wparam
|optional
, 0 },
61 { WM_WINDOWPOSCHANGED
, sent
|optional
},
62 { WM_ACTIVATEAPP
, sent
|wparam
, 1 },
63 { WM_NCACTIVATE
, sent
},
64 { WM_ACTIVATE
, sent
|wparam
, 1 },
65 { WM_IME_SETCONTEXT
, sent
|wparam
|defwinproc
|optional
, 1 },
66 { WM_IME_NOTIFY
, sent
|defwinproc
|optional
},
67 { WM_SETFOCUS
, sent
|wparam
|defwinproc
, 0 },
68 /* Win9x adds SWP_NOZORDER below */
69 { WM_WINDOWPOSCHANGED
, sent
, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
70 { WM_NCCALCSIZE
, sent
|wparam
|optional
, 1 },
76 static const struct message create_monthcal_control_seq
[] = {
77 { WM_NOTIFYFORMAT
, sent
|lparam
, 0, NF_QUERY
},
78 { WM_QUERYUISTATE
, sent
|optional
},
80 { WM_PARENTNOTIFY
, sent
|wparam
, WM_CREATE
},
84 static const struct message create_monthcal_multi_sel_style_seq
[] = {
85 { WM_NOTIFYFORMAT
, sent
|lparam
, 0, NF_QUERY
},
86 { WM_QUERYUISTATE
, sent
|optional
},
88 { WM_PARENTNOTIFY
, sent
},
92 static const struct message monthcal_curr_date_seq
[] = {
93 { MCM_SETCURSEL
, sent
|wparam
, 0},
94 { WM_PAINT
, sent
|wparam
|lparam
|defwinproc
, 0, 0},
95 { MCM_SETCURSEL
, sent
|wparam
, 0},
96 { MCM_SETCURSEL
, sent
|wparam
, 0},
97 { MCM_GETCURSEL
, sent
|wparam
, 0},
98 { MCM_GETCURSEL
, sent
|wparam
|lparam
, 0, 0},
102 static const struct message monthcal_first_day_seq
[] = {
103 { MCM_GETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 0},
105 { MCM_SETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, -5},
106 { MCM_GETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 0},
108 { MCM_SETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, -4},
109 { MCM_GETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 0},
111 { MCM_SETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, -3},
112 { MCM_GETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 0},
114 { MCM_SETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, -2},
115 { MCM_GETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 0},
117 { MCM_SETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, -1},
118 { MCM_GETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 0},
120 { MCM_SETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 0},
121 { MCM_GETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 0},
123 { MCM_SETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 1},
124 { MCM_GETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 0},
126 { MCM_SETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 2},
127 { MCM_GETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 0},
129 { MCM_SETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 3},
130 { MCM_GETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 0},
132 { MCM_SETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 4},
133 { MCM_GETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 0},
135 { MCM_SETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 5},
136 { MCM_GETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 0},
138 { MCM_SETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 6},
139 { MCM_GETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 0},
141 { MCM_SETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 7},
142 { MCM_GETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 0},
144 { MCM_SETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 8},
145 { MCM_GETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 0},
147 { MCM_SETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 9},
148 { MCM_GETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 0},
150 { MCM_SETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 10},
151 { MCM_GETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 0},
153 { MCM_SETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 11},
154 { MCM_GETFIRSTDAYOFWEEK
, sent
|wparam
|lparam
, 0, 0},
158 static const struct message monthcal_unicode_seq
[] = {
159 { MCM_GETUNICODEFORMAT
, sent
|wparam
|lparam
, 0, 0},
160 { MCM_SETUNICODEFORMAT
, sent
|wparam
|lparam
, 1, 0},
161 { MCM_GETUNICODEFORMAT
, sent
|wparam
|lparam
, 0, 0},
162 { MCM_SETUNICODEFORMAT
, sent
|wparam
|lparam
, 0, 0},
163 { MCM_GETUNICODEFORMAT
, sent
|wparam
|lparam
, 0, 0},
164 { MCM_SETUNICODEFORMAT
, sent
|wparam
|lparam
, 1, 0},
168 static const struct message monthcal_hit_test_seq
[] = {
169 { MCM_SETCURSEL
, sent
|wparam
, 0},
170 { WM_PAINT
, sent
|wparam
|lparam
|defwinproc
, 0, 0},
171 { MCM_HITTEST
, sent
|wparam
, 0},
172 { MCM_HITTEST
, sent
|wparam
, 0},
173 { MCM_HITTEST
, sent
|wparam
, 0},
174 { MCM_HITTEST
, sent
|wparam
, 0},
175 { MCM_HITTEST
, sent
|wparam
, 0},
176 { MCM_HITTEST
, sent
|wparam
, 0},
177 { MCM_HITTEST
, sent
|wparam
, 0},
178 { MCM_HITTEST
, sent
|wparam
, 0},
179 { MCM_HITTEST
, sent
|wparam
, 0},
180 { MCM_HITTEST
, sent
|wparam
, 0},
184 static const struct message monthcal_todaylink_seq
[] = {
185 { MCM_HITTEST
, sent
|wparam
, 0},
186 { MCM_SETTODAY
, sent
|wparam
, 0},
187 { WM_PAINT
, sent
|wparam
|lparam
|defwinproc
, 0, 0},
188 { MCM_GETTODAY
, sent
|wparam
, 0},
189 { WM_LBUTTONDOWN
, sent
|wparam
, MK_LBUTTON
},
190 { WM_CAPTURECHANGED
, sent
|wparam
|lparam
|defwinproc
, 0, 0},
191 { WM_PAINT
, sent
|wparam
|lparam
|defwinproc
, 0, 0},
192 { MCM_GETCURSEL
, sent
|wparam
, 0},
196 static const struct message monthcal_today_seq
[] = {
197 { MCM_SETTODAY
, sent
|wparam
, 0},
198 { WM_PAINT
, sent
|wparam
|lparam
|defwinproc
, 0, 0},
199 { MCM_GETTODAY
, sent
|wparam
, 0},
200 { MCM_SETTODAY
, sent
|wparam
, 0},
201 { WM_PAINT
, sent
|wparam
|lparam
|defwinproc
, 0, 0},
202 { MCM_GETTODAY
, sent
|wparam
, 0},
206 static const struct message monthcal_scroll_seq
[] = {
207 { MCM_SETMONTHDELTA
, sent
|wparam
|lparam
, 2, 0},
208 { MCM_SETMONTHDELTA
, sent
|wparam
|lparam
, 3, 0},
209 { MCM_GETMONTHDELTA
, sent
|wparam
|lparam
, 0, 0},
210 { MCM_SETMONTHDELTA
, sent
|wparam
|lparam
, 12, 0},
211 { MCM_GETMONTHDELTA
, sent
|wparam
|lparam
, 0, 0},
212 { MCM_SETMONTHDELTA
, sent
|wparam
|lparam
, 15, 0},
213 { MCM_GETMONTHDELTA
, sent
|wparam
|lparam
, 0, 0},
214 { MCM_SETMONTHDELTA
, sent
|wparam
|lparam
, -5, 0},
215 { MCM_GETMONTHDELTA
, sent
|wparam
|lparam
, 0, 0},
219 static const struct message monthcal_monthrange_seq
[] = {
220 { MCM_GETMONTHRANGE
, sent
|wparam
, GMR_VISIBLE
},
221 { MCM_GETMONTHRANGE
, sent
|wparam
, GMR_DAYSTATE
},
225 static const struct message monthcal_max_sel_day_seq
[] = {
226 { MCM_SETMAXSELCOUNT
, sent
|wparam
|lparam
, 5, 0},
227 { MCM_GETMAXSELCOUNT
, sent
|wparam
|lparam
, 0, 0},
228 { MCM_SETMAXSELCOUNT
, sent
|wparam
|lparam
, 15, 0},
229 { MCM_GETMAXSELCOUNT
, sent
|wparam
|lparam
, 0, 0},
230 { MCM_SETMAXSELCOUNT
, sent
|wparam
|lparam
, -1, 0},
231 { MCM_GETMAXSELCOUNT
, sent
|wparam
|lparam
, 0, 0},
235 /* expected message sequence for parent*/
236 static const struct message destroy_monthcal_parent_msgs_seq
[] = {
237 { WM_PARENTNOTIFY
, sent
|wparam
, WM_DESTROY
},
241 /* expected message sequence for child*/
242 static const struct message destroy_monthcal_child_msgs_seq
[] = {
243 { 0x0090, sent
|optional
}, /* Vista */
244 { WM_SHOWWINDOW
, sent
|wparam
|lparam
, 0, 0},
245 { WM_WINDOWPOSCHANGING
, sent
|wparam
, 0},
246 { WM_WINDOWPOSCHANGED
, sent
|wparam
, 0},
247 { WM_DESTROY
, sent
|wparam
|lparam
, 0, 0},
248 { WM_NCDESTROY
, sent
|wparam
|lparam
, 0, 0},
252 static const struct message destroy_monthcal_multi_sel_style_seq
[] = {
253 { 0x0090, sent
|optional
}, /* Vista */
254 { WM_SHOWWINDOW
, sent
|wparam
|lparam
, 0, 0},
255 { WM_WINDOWPOSCHANGING
, sent
|wparam
, 0},
256 { WM_WINDOWPOSCHANGED
, sent
|wparam
, 0},
257 { WM_DESTROY
, sent
|wparam
|lparam
, 0, 0},
258 { WM_NCDESTROY
, sent
|wparam
|lparam
, 0, 0},
262 static void test_monthcal(void)
265 SYSTEMTIME st
[2], st1
[2], today
;
266 int res
, month_range
;
270 hwnd
= CreateWindowA(MONTHCAL_CLASSA
, "MonthCal", WS_POPUP
| WS_VISIBLE
, CW_USEDEFAULT
,
271 0, 300, 300, 0, 0, NULL
, NULL
);
272 ok(hwnd
!= NULL
, "Failed to create MonthCal\n");
274 /* test range just after creation */
275 memset(&st
, 0xcc, sizeof(st
));
276 limits
= SendMessageA(hwnd
, MCM_GETRANGE
, 0, (LPARAM
)st
);
278 broken(limits
== GDTR_MIN
), /* comctl32 <= 4.70 */
279 "No limits should be set (%d)\n", limits
);
280 if (limits
== GDTR_MIN
)
282 win_skip("comctl32 <= 4.70 is broken\n");
287 ok(0 == st
[0].wYear
||
288 broken(1752 == st
[0].wYear
), /* comctl32 <= 4.72 */
289 "Expected 0, got %d\n", st
[0].wYear
);
290 ok(0 == st
[0].wMonth
||
291 broken(9 == st
[0].wMonth
), /* comctl32 <= 4.72 */
292 "Expected 0, got %d\n", st
[0].wMonth
);
293 ok(0 == st
[0].wDay
||
294 broken(14 == st
[0].wDay
), /* comctl32 <= 4.72 */
295 "Expected 0, got %d\n", st
[0].wDay
);
296 expect(0, st
[0].wDayOfWeek
);
297 expect(0, st
[0].wHour
);
298 expect(0, st
[0].wMinute
);
299 expect(0, st
[0].wSecond
);
300 expect(0, st
[0].wMilliseconds
);
302 expect(0, st
[1].wYear
);
303 expect(0, st
[1].wMonth
);
304 expect(0, st
[1].wDay
);
305 expect(0, st
[1].wDayOfWeek
);
306 expect(0, st
[1].wHour
);
307 expect(0, st
[1].wMinute
);
308 expect(0, st
[1].wSecond
);
309 expect(0, st
[1].wMilliseconds
);
311 limits
= SendMessageA(hwnd
, MCM_GETRANGE
, 0, 0);
312 ok(limits
== 0, "got %u\n", limits
);
314 GetSystemTime(&st
[0]);
317 SendMessageA(hwnd
, MCM_GETTODAY
, 0, (LPARAM
)&today
);
319 /* Invalid date/time */
321 /* Time should not matter */
322 st
[1].wHour
= st
[1].wMinute
= st
[1].wSecond
= 70;
323 st
[1].wMilliseconds
= 1200;
324 ok(SendMessageA(hwnd
, MCM_SETRANGE
, GDTR_MAX
, (LPARAM
)st
), "Failed to set MAX limit\n");
325 /* invalid timestamp is written back with today data and msecs untouched */
326 expect(today
.wHour
, st
[1].wHour
);
327 expect(today
.wMinute
, st
[1].wMinute
);
328 expect(today
.wSecond
, st
[1].wSecond
);
329 expect(1200, st
[1].wMilliseconds
);
331 ok(SendMessageA(hwnd
, MCM_GETRANGE
, 0, (LPARAM
)st1
) == GDTR_MAX
, "No limits should be set\n");
332 ok(st1
[0].wYear
!= 2000, "Lower limit changed\n");
333 /* invalid timestamp should be replaced with today data, except msecs */
334 expect(today
.wHour
, st1
[1].wHour
);
335 expect(today
.wMinute
, st1
[1].wMinute
);
336 expect(today
.wSecond
, st1
[1].wSecond
);
337 expect(1200, st1
[1].wMilliseconds
);
339 /* Invalid date/time with invalid milliseconds only */
340 GetSystemTime(&st
[0]);
342 /* Time should not matter */
343 st
[1].wMilliseconds
= 1200;
344 ok(SendMessageA(hwnd
, MCM_SETRANGE
, GDTR_MAX
, (LPARAM
)st
), "Failed to set MAX limit\n");
345 /* invalid milliseconds field doesn't lead to invalid timestamp */
346 expect(st
[0].wHour
, st
[1].wHour
);
347 expect(st
[0].wMinute
, st
[1].wMinute
);
348 expect(st
[0].wSecond
, st
[1].wSecond
);
349 expect(1200, st
[1].wMilliseconds
);
351 GetSystemTime(&st
[0]);
354 ok(!SendMessageA(hwnd
, MCM_SETRANGE
, GDTR_MIN
| GDTR_MAX
, (LPARAM
)st
),
355 "Should have failed to set limits\n");
356 ok(SendMessageA(hwnd
, MCM_GETRANGE
, 0, (LPARAM
)st1
) == GDTR_MAX
, "No limits should be set\n");
357 ok(st1
[0].wYear
!= 2000, "Lower limit changed\n");
358 ok(!SendMessageA(hwnd
, MCM_SETRANGE
, GDTR_MAX
, (LPARAM
)st
),
359 "Should have failed to set MAX limit\n");
360 ok(SendMessageA(hwnd
, MCM_GETRANGE
, 0, (LPARAM
)st1
) == GDTR_MAX
, "No limits should be set\n");
361 ok(st1
[0].wYear
!= 2000, "Lower limit changed\n");
363 GetSystemTime(&st
[0]);
368 month_range
= SendMessageA(hwnd
, MCM_GETMONTHRANGE
, GMR_VISIBLE
, (LPARAM
)st1
);
370 ok(SendMessageA(hwnd
, MCM_SETRANGE
, GDTR_MIN
| GDTR_MAX
, (LPARAM
)st
),
371 "Failed to set both min and max limits\n");
372 res
= SendMessageA(hwnd
, MCM_GETMONTHRANGE
, GMR_VISIBLE
, (LPARAM
)st1
);
373 ok(res
== month_range
, "Invalid month range (%d)\n", res
);
374 ok(SendMessageA(hwnd
, MCM_GETRANGE
, 0, (LPARAM
)st1
) == (GDTR_MIN
|GDTR_MAX
),
375 "Limits should be set\n");
378 ok(SendMessageA(hwnd
, MCM_SETRANGE
, GDTR_MIN
| GDTR_MAX
, (LPARAM
)st
),
379 "Failed to set both min and max limits\n");
380 res
= SendMessageA(hwnd
, MCM_GETMONTHRANGE
, GMR_VISIBLE
, (LPARAM
)st1
);
381 ok(res
== month_range
, "Invalid month range (%d)\n", res
);
384 ok(SendMessageA(hwnd
, MCM_SETRANGE
, GDTR_MIN
| GDTR_MAX
, (LPARAM
)st
),
385 "Failed to set both min and max limits\n");
387 ok(SendMessageA(hwnd
, MCM_SETRANGE
, GDTR_MIN
| GDTR_MAX
, (LPARAM
)st
),
388 "Failed to set both min and max limits\n");
391 ok(SendMessageA(hwnd
, MCM_SETRANGE
, GDTR_MAX
, (LPARAM
)st
), "Failed to set max limit\n");
392 ok(SendMessageA(hwnd
, MCM_GETRANGE
, 0, (LPARAM
)st1
) == GDTR_MAX
,
393 "Only MAX limit should be set\n");
395 ok(SendMessageA(hwnd
, MCM_SETRANGE
, GDTR_MAX
, (LPARAM
)st
), "Failed to set max limit\n");
397 ok(SendMessageA(hwnd
, MCM_SETRANGE
, GDTR_MAX
, (LPARAM
)st
), "Failed to set max limit\n");
399 ok(SendMessageA(hwnd
, MCM_SETRANGE
, GDTR_MAX
, (LPARAM
)st
), "Failed to set max limit\n");
400 ok(SendMessageA(hwnd
, MCM_GETRANGE
, 0, (LPARAM
)st1
) == GDTR_MAX
,
401 "Only MAX limit should be set\n");
403 /* set both limits, then set max < min */
404 GetSystemTime(&st
[0]);
408 ok(SendMessageA(hwnd
, MCM_SETRANGE
, GDTR_MIN
|GDTR_MAX
, (LPARAM
)st
), "Failed to set limits\n");
409 ok(SendMessageA(hwnd
, MCM_GETRANGE
, 0, (LPARAM
)st1
) == (GDTR_MIN
|GDTR_MAX
),
410 "Min limit expected\n");
412 ok(SendMessageA(hwnd
, MCM_SETRANGE
, GDTR_MAX
, (LPARAM
)st
), "Failed to set limits\n");
413 ok(SendMessageA(hwnd
, MCM_GETRANGE
, 0, (LPARAM
)st1
) == GDTR_MAX
, "Max limit expected\n");
415 expect(0, st1
[0].wYear
);
416 expect(0, st1
[0].wMonth
);
417 expect(0, st1
[0].wDay
);
418 expect(0, st1
[0].wDayOfWeek
);
419 expect(0, st1
[0].wHour
);
420 expect(0, st1
[0].wMinute
);
421 expect(0, st1
[0].wSecond
);
422 expect(0, st1
[0].wMilliseconds
);
424 expect(st
[1].wYear
, st1
[1].wYear
);
425 expect(st
[1].wMonth
, st1
[1].wMonth
);
426 expect(st
[1].wDay
, st1
[1].wDay
);
427 expect(st
[1].wDayOfWeek
, st1
[1].wDayOfWeek
);
428 expect(st
[1].wHour
, st1
[1].wHour
);
429 expect(st
[1].wMinute
, st1
[1].wMinute
);
430 expect(st
[1].wSecond
, st1
[1].wSecond
);
431 expect(st
[1].wMilliseconds
, st1
[1].wMilliseconds
);
435 ok(SendMessageA(hwnd
, MCM_SETRANGE
, GDTR_MIN
|GDTR_MAX
, (LPARAM
)st
), "Failed to set limits\n");
436 ok(SendMessageA(hwnd
, MCM_GETRANGE
, 0, (LPARAM
)st1
) == (GDTR_MIN
|GDTR_MAX
),
437 "Min limit expected\n");
438 st
[0].wYear
++; /* start == end now */
439 ok(SendMessageA(hwnd
, MCM_SETRANGE
, GDTR_MIN
, (LPARAM
)st
), "Failed to set limits\n");
440 ok(SendMessageA(hwnd
, MCM_GETRANGE
, 0, (LPARAM
)st1
) == GDTR_MIN
, "Min limit expected\n");
442 expect(st
[0].wYear
, st1
[0].wYear
);
443 expect(st
[0].wMonth
, st1
[0].wMonth
);
444 expect(st
[0].wDay
, st1
[0].wDay
);
445 expect(st
[0].wDayOfWeek
, st1
[0].wDayOfWeek
);
446 expect(st
[0].wHour
, st1
[0].wHour
);
447 expect(st
[0].wMinute
, st1
[0].wMinute
);
448 expect(st
[0].wSecond
, st1
[0].wSecond
);
449 expect(st
[0].wMilliseconds
, st1
[0].wMilliseconds
);
451 expect(0, st1
[1].wYear
);
452 expect(0, st1
[1].wMonth
);
453 expect(0, st1
[1].wDay
);
454 expect(0, st1
[1].wDayOfWeek
);
455 expect(0, st1
[1].wHour
);
456 expect(0, st1
[1].wMinute
);
457 expect(0, st1
[1].wSecond
);
458 expect(0, st1
[1].wMilliseconds
);
461 limits
= SendMessageA(hwnd
, MCM_GETRANGE
, 0, (LPARAM
)st1
);
462 ok(limits
== GDTR_MIN
, "got 0x%08x\n", limits
);
467 r
= SendMessageA(hwnd
, MCM_SETRANGE
, 0, (LPARAM
)st
);
468 ok(r
, "got %d\n", r
);
470 limits
= SendMessageA(hwnd
, MCM_GETRANGE
, 0, (LPARAM
)st
);
471 ok(limits
== 0, "got 0x%08x\n", limits
);
472 ok(st
[0].wYear
== 0 && st
[1].wYear
== 0, "got %u, %u\n", st
[0].wYear
, st
[1].wYear
);
474 /* flags are 0, set min limit */
479 r
= SendMessageA(hwnd
, MCM_SETRANGE
, GDTR_MIN
, (LPARAM
)st
);
480 ok(r
, "got %d\n", r
);
482 limits
= SendMessageA(hwnd
, MCM_GETRANGE
, 0, (LPARAM
)st1
);
483 ok(limits
== GDTR_MIN
, "got 0x%08x\n", limits
);
484 ok(st1
[1].wYear
== 0, "got %u\n", st1
[1].wYear
);
486 /* now set max limit, check flags */
487 r
= SendMessageA(hwnd
, MCM_SETRANGE
, GDTR_MAX
, (LPARAM
)st
);
488 ok(r
, "got %d\n", r
);
490 limits
= SendMessageA(hwnd
, MCM_GETRANGE
, 0, (LPARAM
)st1
);
491 ok(limits
== GDTR_MAX
, "got 0x%08x\n", limits
);
492 ok(st1
[0].wYear
== 0, "got %u\n", st1
[0].wYear
);
497 static LRESULT WINAPI
parent_wnd_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
499 static LONG defwndproc_counter
= 0;
503 /* log system messages, except for painting */
504 if (message
< WM_USER
&&
505 message
!= WM_PAINT
&&
506 message
!= WM_ERASEBKGND
&&
507 message
!= WM_NCPAINT
&&
508 message
!= WM_NCHITTEST
&&
509 message
!= WM_GETTEXT
&&
510 message
!= WM_GETICON
&&
511 message
!= WM_DEVICECHANGE
)
513 msg
.message
= message
;
514 msg
.flags
= sent
|wparam
|lparam
;
515 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
518 add_message(sequences
, PARENT_SEQ_INDEX
, &msg
);
521 if (message
== WM_NOTIFY
)
523 NMHDR
*hdr
= (NMHDR
*)lParam
;
526 case MCN_GETDAYSTATE
:
528 NMDAYSTATE
*nmstate
= (NMDAYSTATE
*)lParam
;
529 static MONTHDAYSTATE months
[14] = { 0 };
531 ok(nmstate
->cDayState
> 0, "got %d\n", nmstate
->cDayState
);
532 ok(nmstate
->cDayState
<= 14, "got %d\n", nmstate
->cDayState
);
533 ok(nmstate
->prgDayState
!= NULL
, "got %p\n", nmstate
->prgDayState
);
535 nmstate
->prgDayState
= months
;
542 NMSELCHANGE
*nmchg
= (NMSELCHANGE
*)lParam
;
544 BOOL is_multisel
= GetWindowLongPtrA(nmchg
->nmhdr
.hwndFrom
, GWL_STYLE
) & MCS_MULTISELECT
;
546 if(GetWindowLongPtrA(nmchg
->nmhdr
.hwndFrom
, GWLP_ID
) != SEL_NOTIFY_TEST_ID
)
548 SendMessageA(nmchg
->nmhdr
.hwndFrom
, is_multisel
? MCM_GETSELRANGE
: MCM_GETCURSEL
,
551 expect(st
[0].wYear
, nmchg
->stSelStart
.wYear
);
552 expect(st
[0].wMonth
, nmchg
->stSelStart
.wMonth
);
553 expect(0, nmchg
->stSelStart
.wDayOfWeek
);
554 expect(st
[0].wDay
, nmchg
->stSelStart
.wDay
);
558 expect(st
[1].wYear
, nmchg
->stSelEnd
.wYear
);
559 expect(st
[1].wMonth
, nmchg
->stSelEnd
.wMonth
);
560 expect(0, nmchg
->stSelEnd
.wDayOfWeek
);
561 expect(st
[1].wDay
, nmchg
->stSelEnd
.wDay
);
564 ok(!(nmchg
->stSelEnd
.wYear
| nmchg
->stSelEnd
.wMonth
|
565 nmchg
->stSelEnd
.wDayOfWeek
| nmchg
->stSelEnd
.wDay
|
566 nmchg
->stSelEnd
.wHour
| nmchg
->stSelEnd
.wMinute
|
567 nmchg
->stSelEnd
.wSecond
| nmchg
->stSelEnd
.wMilliseconds
),
568 "Non-zero member in stSelEnd\n");
576 defwndproc_counter
++;
577 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
578 defwndproc_counter
--;
583 static BOOL
register_parent_wnd_class(void)
588 cls
.lpfnWndProc
= parent_wnd_proc
;
591 cls
.hInstance
= GetModuleHandleA(NULL
);
593 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
594 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
595 cls
.lpszMenuName
= NULL
;
596 cls
.lpszClassName
= "Month-Cal test parent class";
597 return RegisterClassA(&cls
);
600 static HWND
create_parent_window(void)
604 InitCommonControls();
606 /* flush message sequences, so we can check the new sequence by the end of function */
607 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
609 if (!register_parent_wnd_class())
612 hwnd
= CreateWindowExA(0, "Month-Cal test parent class", "Month-Cal test parent window",
613 WS_CAPTION
| WS_SYSMENU
| WS_MINIMIZEBOX
| WS_MAXIMIZEBOX
| WS_VISIBLE
,
614 0, 0, 500, 500, GetDesktopWindow(), NULL
, GetModuleHandleA(NULL
), NULL
);
615 ok(hwnd
!= NULL
, "failed to create parent wnd\n");
617 /* check for message sequences */
618 ok_sequence(sequences
, PARENT_SEQ_INDEX
, create_parent_window_seq
, "create parent window", FALSE
);
623 static LRESULT WINAPI
monthcal_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
625 WNDPROC oldproc
= (WNDPROC
)GetWindowLongPtrA(hwnd
, GWLP_USERDATA
);
626 static LONG defwndproc_counter
= 0;
630 msg
.message
= message
;
631 msg
.flags
= sent
|wparam
|lparam
;
632 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
636 add_message(sequences
, MONTHCAL_SEQ_INDEX
, &msg
);
638 /* some debug output for style changing */
639 if ((message
== WM_STYLECHANGING
||
640 message
== WM_STYLECHANGED
) && lParam
)
642 STYLESTRUCT
*style
= (STYLESTRUCT
*)lParam
;
643 trace("\told style: 0x%08x, new style: 0x%08x\n", style
->styleOld
, style
->styleNew
);
646 defwndproc_counter
++;
647 ret
= CallWindowProcA(oldproc
, hwnd
, message
, wParam
, lParam
);
648 defwndproc_counter
--;
653 static HWND
create_monthcal_control(DWORD style
)
660 hwnd
= CreateWindowExA(0, MONTHCAL_CLASSA
, "", WS_CHILD
| WS_BORDER
| WS_VISIBLE
| style
,
661 0, 0, 300, 400, parent_wnd
, NULL
, GetModuleHandleA(NULL
), NULL
);
662 ok(hwnd
!= NULL
, "failed to create monthcal wnd\n");
663 if (!hwnd
) return NULL
;
665 oldproc
= (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
666 (LONG_PTR
)monthcal_subclass_proc
);
667 SetWindowLongPtrA(hwnd
, GWLP_USERDATA
, (LONG_PTR
)oldproc
);
669 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)GetStockObject(SYSTEM_FONT
), 0);
671 /* make sure calendar grid is 2x1 */
672 ret
= SendMessageA(hwnd
, MCM_GETMINREQRECT
, 0, (LPARAM
)&rect
);
673 ok(ret
, "got %d\n", ret
);
675 ret
= SetWindowPos(hwnd
, NULL
, 0, 0, rect
.right
* 5 / 2, rect
.bottom
* 3 / 2, SWP_NOMOVE
);
676 ok(ret
, "got %d\n", ret
);
682 /* Setter and Getters Tests */
684 static void test_color(void)
686 COLORREF color
, prev
;
689 hwnd
= create_monthcal_control(0);
691 /* invalid color index */
692 color
= SendMessageA(hwnd
, MCM_GETCOLOR
, MCSC_TRAILINGTEXT
+ 1, 0);
694 prev
= SendMessageA(hwnd
, MCM_SETCOLOR
, MCSC_TRAILINGTEXT
+ 1, RGB(255,255,255));
697 color
= SendMessageA(hwnd
, MCM_GETCOLOR
, MCSC_BACKGROUND
, 0);
698 prev
= SendMessageA(hwnd
, MCM_SETCOLOR
, MCSC_BACKGROUND
, RGB(0,0,0));
700 color
= SendMessageA(hwnd
, MCM_GETCOLOR
, MCSC_BACKGROUND
, 0);
701 expect(RGB(0,0,0), color
);
702 prev
= SendMessageA(hwnd
, MCM_SETCOLOR
, MCSC_BACKGROUND
, RGB(255,255,255));
704 color
= SendMessageA(hwnd
, MCM_GETCOLOR
, MCSC_BACKGROUND
, 0);
705 expect(RGB(255,255,255), color
);
707 color
= SendMessageA(hwnd
, MCM_GETCOLOR
, MCSC_MONTHBK
, 0);
708 prev
= SendMessageA(hwnd
, MCM_SETCOLOR
, MCSC_MONTHBK
, RGB(0,0,0));
710 color
= SendMessageA(hwnd
, MCM_GETCOLOR
, MCSC_MONTHBK
, 0);
711 expect(RGB(0,0,0), color
);
712 prev
= SendMessageA(hwnd
, MCM_SETCOLOR
, MCSC_MONTHBK
, RGB(255,255,255));
714 color
= SendMessageA(hwnd
, MCM_GETCOLOR
, MCSC_MONTHBK
, 0);
715 expect(RGB(255,255,255), color
);
717 color
= SendMessageA(hwnd
, MCM_GETCOLOR
, MCSC_TEXT
, 0);
718 prev
= SendMessageA(hwnd
, MCM_SETCOLOR
, MCSC_TEXT
, RGB(0,0,0));
720 color
= SendMessageA(hwnd
, MCM_GETCOLOR
, MCSC_TEXT
, 0);
721 expect(RGB(0,0,0), color
);
722 prev
= SendMessageA(hwnd
, MCM_SETCOLOR
, MCSC_TEXT
, RGB(255,255,255));
724 color
= SendMessageA(hwnd
, MCM_GETCOLOR
, MCSC_TEXT
, 0);
725 expect(RGB(255,255,255), color
);
727 color
= SendMessageA(hwnd
, MCM_GETCOLOR
, MCSC_TITLEBK
, 0);
728 prev
= SendMessageA(hwnd
, MCM_SETCOLOR
, MCSC_TITLEBK
, RGB(0,0,0));
730 color
= SendMessageA(hwnd
, MCM_GETCOLOR
, MCSC_TITLEBK
, 0);
731 expect(RGB(0,0,0), color
);
732 prev
= SendMessageA(hwnd
, MCM_SETCOLOR
, MCSC_TITLEBK
, RGB(255,255,255));
734 color
= SendMessageA(hwnd
, MCM_GETCOLOR
, MCSC_TITLEBK
, 0);
735 expect(RGB(255,255,255), color
);
737 color
= SendMessageA(hwnd
, MCM_GETCOLOR
, MCSC_TITLETEXT
, 0);
738 prev
= SendMessageA(hwnd
, MCM_SETCOLOR
, MCSC_TITLETEXT
, RGB(0,0,0));
740 color
= SendMessageA(hwnd
, MCM_GETCOLOR
, MCSC_TITLETEXT
, 0);
741 expect(RGB(0,0,0), color
);
742 prev
= SendMessageA(hwnd
, MCM_SETCOLOR
, MCSC_TITLETEXT
, RGB(255,255,255));
744 color
= SendMessageA(hwnd
, MCM_GETCOLOR
, MCSC_TITLETEXT
, 0);
745 expect(RGB(255,255,255), color
);
747 color
= SendMessageA(hwnd
, MCM_GETCOLOR
, MCSC_TRAILINGTEXT
, 0);
748 prev
= SendMessageA(hwnd
, MCM_SETCOLOR
, MCSC_TRAILINGTEXT
, RGB(0,0,0));
750 color
= SendMessageA(hwnd
, MCM_GETCOLOR
, MCSC_TRAILINGTEXT
, 0);
751 expect(RGB(0,0,0), color
);
752 prev
= SendMessageA(hwnd
, MCM_SETCOLOR
, MCSC_TRAILINGTEXT
, RGB(255,255,255));
754 color
= SendMessageA(hwnd
, MCM_GETCOLOR
, MCSC_TRAILINGTEXT
, 0);
755 expect(RGB(255,255,255), color
);
760 static void test_currdate(void)
762 SYSTEMTIME st_original
, st_new
, st_test
;
766 hwnd
= create_monthcal_control(0);
768 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
770 /* Setter and Getters for current date selected */
771 st_original
.wYear
= 2000;
772 st_original
.wMonth
= 11;
773 st_original
.wDay
= 28;
774 st_original
.wHour
= 11;
775 st_original
.wMinute
= 59;
776 st_original
.wSecond
= 30;
777 st_original
.wMilliseconds
= 0;
778 st_original
.wDayOfWeek
= 0;
780 st_new
= st_test
= st_original
;
782 /* Should not validate the time */
783 res
= SendMessageA(hwnd
, MCM_SETCURSEL
, 0, (LPARAM
)&st_test
);
786 /* Overflow matters, check for wDay */
788 res
= SendMessageA(hwnd
, MCM_SETCURSEL
, 0, (LPARAM
)&st_test
);
791 /* correct wDay before checking for wMonth */
793 expect(st_original
.wDay
, st_test
.wDay
);
795 /* Overflow matters, check for wMonth */
797 res
= SendMessageA(hwnd
, MCM_SETCURSEL
, 0, (LPARAM
)&st_test
);
800 /* checking if gets the information right, modify st_new */
808 res
= SendMessageA(hwnd
, MCM_GETCURSEL
, 0, (LPARAM
)&st_new
);
811 /* st_new change to st_origin, above settings with overflow */
812 /* should not change the current settings */
813 expect(st_original
.wYear
, st_new
.wYear
);
814 expect(st_original
.wMonth
, st_new
.wMonth
);
815 expect(st_original
.wDay
, st_new
.wDay
);
816 ok(st_original
.wHour
== st_new
.wHour
||
817 broken(0 == st_new
.wHour
), /* comctl32 <= 4.70 */
818 "Expected %d, got %d\n", st_original
.wHour
, st_new
.wHour
);
819 ok(st_original
.wMinute
== st_new
.wMinute
||
820 broken(0 == st_new
.wMinute
), /* comctl32 <= 4.70 */
821 "Expected %d, got %d\n", st_original
.wMinute
, st_new
.wMinute
);
822 ok(st_original
.wSecond
== st_new
.wSecond
||
823 broken(0 == st_new
.wSecond
), /* comctl32 <= 4.70 */
824 "Expected %d, got %d\n", st_original
.wSecond
, st_new
.wSecond
);
826 /* lparam cannot be NULL */
827 res
= SendMessageA(hwnd
, MCM_GETCURSEL
, 0, 0);
830 ok_sequence(sequences
, MONTHCAL_SEQ_INDEX
, monthcal_curr_date_seq
, "monthcal currDate", TRUE
);
832 /* December, 31, 9999 is the maximum allowed date */
833 memset(&st_new
, 0, sizeof(st_new
));
837 res
= SendMessageA(hwnd
, MCM_SETCURSEL
, 0, (LPARAM
)&st_new
);
839 memset(&st_test
, 0, sizeof(st_test
));
840 res
= SendMessageA(hwnd
, MCM_GETCURSEL
, 0, (LPARAM
)&st_test
);
842 expect(st_new
.wYear
, st_test
.wYear
);
843 expect(st_new
.wMonth
, st_test
.wMonth
);
844 expect(st_new
.wDay
, st_test
.wDay
);
845 expect(st_new
.wHour
, st_test
.wHour
);
846 expect(st_new
.wMinute
, st_test
.wMinute
);
847 expect(st_new
.wSecond
, st_test
.wSecond
);
848 /* try one day later */
849 st_original
= st_new
;
850 st_new
.wYear
= 10000;
853 res
= SendMessageA(hwnd
, MCM_SETCURSEL
, 0, (LPARAM
)&st_new
);
855 broken(1 == res
), /* comctl32 <= 4.72 */
856 "Expected 0, got %d\n", res
);
859 memset(&st_test
, 0, sizeof(st_test
));
860 res
= SendMessageA(hwnd
, MCM_GETCURSEL
, 0, (LPARAM
)&st_test
);
862 expect(st_original
.wYear
, st_test
.wYear
);
863 expect(st_original
.wMonth
, st_test
.wMonth
);
864 expect(st_original
.wDay
, st_test
.wDay
);
865 expect(st_original
.wHour
, st_test
.wHour
);
866 expect(st_original
.wMinute
, st_test
.wMinute
);
867 expect(st_original
.wSecond
, st_test
.wSecond
);
870 /* setting selection equal to current reports success even if out range */
871 memset(&st_new
, 0, sizeof(st_new
));
875 res
= SendMessageA(hwnd
, MCM_SETCURSEL
, 0, (LPARAM
)&st_new
);
877 memset(&st_test
, 0, sizeof(st_test
));
878 st_test
.wYear
= 2009;
881 res
= SendMessageA(hwnd
, MCM_SETRANGE
, GDTR_MIN
, (LPARAM
)&st_test
);
883 /* set to current again */
884 res
= SendMessageA(hwnd
, MCM_SETCURSEL
, 0, (LPARAM
)&st_new
);
887 /* set with invalid day of week */
888 memset(&st_test
, 0, sizeof(st_test
));
889 st_test
.wYear
= 2009;
892 st_test
.wDayOfWeek
= 100;
893 res
= SendMessageA(hwnd
, MCM_SETCURSEL
, 0, (LPARAM
)&st_test
);
896 memset(&st_test
, 0, sizeof(st_test
));
897 res
= SendMessageA(hwnd
, MCM_GETCURSEL
, 0, (LPARAM
)&st_test
);
899 expect(2009, st_test
.wYear
);
900 expect(7, st_test
.wDay
);
901 expect(10, st_test
.wMonth
);
902 expect(3, st_test
.wDayOfWeek
);
907 static void test_firstDay(void)
909 int res
, fday
, i
, prev
;
910 CHAR b
[128], caltype
[3];
911 LCID lcid
= LOCALE_USER_DEFAULT
;
915 SetLastError(0xdeadbeef);
916 ret
= GetLocaleInfoA(lcid
, LOCALE_ICALENDARTYPE
, caltype
, 3);
918 skip("Must know local calendar type (%x)\n", GetLastError());
920 } else if (atoi(caltype
) != CAL_GREGORIAN
) {
921 skip("MonthCalendar Control only supports Gregorian calendar (type: %s)\n", caltype
);
925 hwnd
= create_monthcal_control(0);
927 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
929 /* Setter and Getters for first day of week */
930 /* check for locale first day */
931 if(GetLocaleInfoA(lcid
, LOCALE_IFIRSTDAYOFWEEK
, b
, 128)){
933 res
= SendMessageA(hwnd
, MCM_GETFIRSTDAYOFWEEK
, 0, 0);
937 /* checking for the values that actually will be stored as */
938 /* current first day when we set a new value */
939 for (i
= -5; i
< 12; i
++){
940 res
= SendMessageA(hwnd
, MCM_SETFIRSTDAYOFWEEK
, 0, i
);
942 res
= SendMessageA(hwnd
, MCM_GETFIRSTDAYOFWEEK
, 0, 0);
946 expect(MAKELONG(fday
, FALSE
), res
);
948 /* out of range sets max first day of week, locale is ignored */
949 expect(MAKELONG(6, TRUE
), res
);
951 expect(MAKELONG(i
, TRUE
), res
);
955 ok_sequence(sequences
, MONTHCAL_SEQ_INDEX
, monthcal_first_day_seq
, "monthcal firstDay", FALSE
);
958 skip("Cannot retrieve first day of the week\n");
964 static void test_unicode(void)
969 hwnd
= create_monthcal_control(0);
971 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
973 /* Setter and Getters for Unicode format */
975 /* getting the current settings */
976 temp
= SendMessageA(hwnd
, MCM_GETUNICODEFORMAT
, 0, 0);
978 /* setting to 1, should return previous settings */
979 res
= SendMessageA(hwnd
, MCM_SETUNICODEFORMAT
, 1, 0);
982 /* current setting is 1, so, should return 1 */
983 res
= SendMessageA(hwnd
, MCM_GETUNICODEFORMAT
, 0, 0);
985 broken(0 == res
), /* comctl32 <= 4.70 */
986 "Expected 1, got %d\n", res
);
988 /* setting to 0, should return previous settings */
989 res
= SendMessageA(hwnd
, MCM_SETUNICODEFORMAT
, 0, 0);
991 broken(0 == res
), /* comctl32 <= 4.70 */
992 "Expected 1, got %d\n", res
);
994 /* current setting is 0, so, it should return 0 */
995 res
= SendMessageA(hwnd
, MCM_GETUNICODEFORMAT
, 0, 0);
998 /* should return previous settings */
999 res
= SendMessageA(hwnd
, MCM_SETUNICODEFORMAT
, 1, 0);
1002 ok_sequence(sequences
, MONTHCAL_SEQ_INDEX
, monthcal_unicode_seq
, "monthcal unicode", FALSE
);
1004 DestroyWindow(hwnd
);
1007 static void test_hittest(void)
1009 typedef struct hittest_test
1015 static const hittest_test_t title_hits
[] = {
1016 /* Start is the same everywhere */
1017 { MCHT_TITLE
, FALSE
},
1018 { MCHT_TITLEBTNPREV
, FALSE
},
1019 /* The middle piece is only tested for presence of items */
1020 /* End is the same everywhere */
1021 { MCHT_TITLEBTNNEXT
, FALSE
},
1022 { MCHT_TITLE
, FALSE
},
1023 { MCHT_NOWHERE
, TRUE
}
1026 MCHITTESTINFO mchit
;
1033 char yearmonth
[80], *locale_month
, *locale_year
;
1034 int month_count
, year_count
;
1037 memset(&mchit
, 0, sizeof(MCHITTESTINFO
));
1039 hwnd
= create_monthcal_control(0);
1041 /* test with invalid structure size */
1042 mchit
.cbSize
= MCHITTESTINFO_V1_SIZE
- 1;
1045 res
= SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
1046 expect(0, mchit
.pt
.x
);
1047 expect(0, mchit
.pt
.y
);
1049 expect(0, mchit
.uHit
);
1050 /* test with invalid pointer */
1051 res
= SendMessageA(hwnd
, MCM_HITTEST
, 0, 0);
1054 /* resize control to display single Calendar */
1055 res
= SendMessageA(hwnd
, MCM_GETMINREQRECT
, 0, (LPARAM
)&r
);
1058 win_skip("Message MCM_GETMINREQRECT unsupported. Skipping.\n");
1059 DestroyWindow(hwnd
);
1062 MoveWindow(hwnd
, 0, 0, r
.right
, r
.bottom
, FALSE
);
1064 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1072 st
.wMilliseconds
= 0;
1075 res
= SendMessageA(hwnd
, MCM_SETCURSEL
, 0, (LPARAM
)&st
);
1078 /* (0, 0) is the top left of the control - title */
1079 mchit
.cbSize
= MCHITTESTINFO_V1_SIZE
;
1082 res
= SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
1083 expect(0, mchit
.pt
.x
);
1084 expect(0, mchit
.pt
.y
);
1085 expect(mchit
.uHit
, res
);
1086 expect_hex(MCHT_TITLE
, res
);
1088 /* bottom right of the control and should not be active */
1089 mchit
.pt
.x
= r
.right
;
1090 mchit
.pt
.y
= r
.bottom
;
1091 res
= SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
1092 expect(r
.right
, mchit
.pt
.x
);
1093 expect(r
.bottom
, mchit
.pt
.y
);
1094 expect(mchit
.uHit
, res
);
1095 todo_wine
expect_hex(MCHT_NOWHERE
, res
);
1097 /* completely out of the control, should not be active */
1098 mchit
.pt
.x
= 2 * r
.right
;
1099 mchit
.pt
.y
= 2 * r
.bottom
;
1100 res
= SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
1101 expect(2 * r
.right
, mchit
.pt
.x
);
1102 expect(2 * r
.bottom
, mchit
.pt
.y
);
1103 expect(mchit
.uHit
, res
);
1104 todo_wine
expect_hex(MCHT_NOWHERE
, res
);
1106 /* in active area - day of the week */
1107 mchit
.pt
.x
= r
.right
/ 2;
1108 mchit
.pt
.y
= r
.bottom
/ 2;
1109 res
= SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
1110 expect(r
.right
/ 2, mchit
.pt
.x
);
1111 expect(r
.bottom
/ 2, mchit
.pt
.y
);
1112 expect(mchit
.uHit
, res
);
1113 expect_hex(MCHT_CALENDARDATE
, res
);
1115 /* in active area - day of the week #2 */
1116 mchit
.pt
.x
= r
.right
/ 14; /* half of first day rect */
1117 mchit
.pt
.y
= r
.bottom
/ 2;
1118 res
= SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
1119 expect(r
.right
/ 14, mchit
.pt
.x
);
1120 expect(r
.bottom
/ 2, mchit
.pt
.y
);
1121 expect(mchit
.uHit
, res
);
1122 expect_hex(MCHT_CALENDARDATE
, res
);
1124 /* in active area - date from prev month */
1125 mchit
.pt
.x
= r
.right
/ 14; /* half of first day rect */
1126 mchit
.pt
.y
= 6 * r
.bottom
/ 19;
1127 res
= SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
1128 expect(r
.right
/ 14, mchit
.pt
.x
);
1129 expect(6 * r
.bottom
/ 19, mchit
.pt
.y
);
1130 expect(mchit
.uHit
, res
);
1131 expect_hex(MCHT_CALENDARDATEPREV
, res
);
1135 /* (125, 115) is in active area - date from this month */
1138 res
= SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
1139 expect(125, mchit
.pt
.x
);
1140 expect(115, mchit
.pt
.y
);
1141 expect(mchit
.uHit
, res
);
1142 expect(MCHT_CALENDARDATE
, res
);
1145 /* in active area - date from next month */
1146 mchit
.pt
.x
= 11 * r
.right
/ 14;
1147 mchit
.pt
.y
= 16 * r
.bottom
/ 19;
1148 res
= SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
1149 expect(11 * r
.right
/ 14, mchit
.pt
.x
);
1150 expect(16 * r
.bottom
/ 19, mchit
.pt
.y
);
1151 expect(mchit
.uHit
, res
);
1152 expect_hex(MCHT_CALENDARDATENEXT
, res
);
1154 /* in active area - today link */
1155 mchit
.pt
.x
= r
.right
/ 14;
1156 mchit
.pt
.y
= 18 * r
.bottom
/ 19;
1157 res
= SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
1158 expect(r
.right
/ 14, mchit
.pt
.x
);
1159 expect(18 * r
.bottom
/ 19, mchit
.pt
.y
);
1160 expect(mchit
.uHit
, res
);
1161 expect_hex(MCHT_TODAYLINK
, res
);
1163 /* in active area - today link */
1164 mchit
.pt
.x
= r
.right
/ 2;
1165 mchit
.pt
.y
= 18 * r
.bottom
/ 19;
1166 res
= SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
1167 expect(r
.right
/ 2, mchit
.pt
.x
);
1168 expect(18 * r
.bottom
/ 19, mchit
.pt
.y
);
1169 expect(mchit
.uHit
, res
);
1170 expect_hex(MCHT_TODAYLINK
, res
);
1172 /* in active area - today link */
1173 mchit
.pt
.x
= r
.right
/ 10;
1174 mchit
.pt
.y
= 18 * r
.bottom
/ 19;
1175 res
= SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
1176 expect(r
.right
/ 10, mchit
.pt
.x
);
1177 expect(18 * r
.bottom
/ 19, mchit
.pt
.y
);
1178 expect(mchit
.uHit
, res
);
1179 expect_hex(MCHT_TODAYLINK
, res
);
1181 ok_sequence(sequences
, MONTHCAL_SEQ_INDEX
, monthcal_hit_test_seq
, "monthcal hit test", TRUE
);
1183 /* The horizontal position of title bar elements depends on locale (y pos
1184 is constant), so we sample across a horizontal line and make sure we
1185 find all elements. */
1187 /* Get the format of the title */
1188 GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_SYEARMONTH
, yearmonth
, 80);
1189 /* Find out if we have a month and/or year */
1190 locale_year
= strstr(yearmonth
, "y");
1191 locale_month
= strstr(yearmonth
, "M");
1194 mchit
.pt
.y
= (5/2) * r
.bottom
/ 19;
1196 old_res
= SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
1197 expect_hex(title_hits
[title_index
].ht
, old_res
);
1199 in_the_middle
= FALSE
;
1200 month_count
= year_count
= 0;
1201 for (x
= 0; x
< r
.right
; x
++){
1203 res
= SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
1204 expect(x
, mchit
.pt
.x
);
1205 expect((5/2) * r
.bottom
/ 19, mchit
.pt
.y
);
1206 expect(mchit
.uHit
, res
);
1207 if (res
!= old_res
) {
1209 if (old_res
== MCHT_TITLEBTNPREV
)
1210 in_the_middle
= TRUE
;
1212 if (res
== MCHT_TITLEBTNNEXT
)
1213 in_the_middle
= FALSE
;
1215 if (in_the_middle
) {
1216 if (res
== MCHT_TITLEMONTH
)
1218 else if (res
== MCHT_TITLEYEAR
)
1223 if (sizeof(title_hits
) / sizeof(title_hits
[0]) <= title_index
)
1226 todo_wine_if(title_hits
[title_index
].todo
)
1227 ok(title_hits
[title_index
].ht
== res
, "Expected %x, got %x, pos %d\n",
1228 title_hits
[title_index
].ht
, res
, x
);
1234 /* There are some limits, even if LOCALE_SYEARMONTH contains rubbish
1235 * or no month/year indicators at all */
1237 todo_wine
ok(month_count
== 1, "Expected 1 month item, got %d\n", month_count
);
1239 ok(month_count
<= 1, "Too many month items: %d\n", month_count
);
1242 todo_wine
ok(year_count
== 1, "Expected 1 year item, got %d\n", year_count
);
1244 ok(year_count
<= 1, "Too many year items: %d\n", year_count
);
1246 todo_wine
ok(month_count
+ year_count
>= 1, "Not enough month and year items\n");
1248 ok(r
.right
<= x
&& title_index
+ 1 == sizeof(title_hits
) / sizeof(title_hits
[0]),
1249 "Wrong title layout\n");
1251 DestroyWindow(hwnd
);
1254 static void test_todaylink(void)
1256 MCHITTESTINFO mchit
;
1257 SYSTEMTIME st_test
, st_new
;
1262 memset(&mchit
, 0, sizeof(MCHITTESTINFO
));
1264 hwnd
= create_monthcal_control(0);
1266 res
= SendMessageA(hwnd
, MCM_GETMINREQRECT
, 0, (LPARAM
)&r
);
1268 MoveWindow(hwnd
, 0, 0, r
.right
, r
.bottom
, FALSE
);
1270 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1272 /* hit active area - today link */
1273 mchit
.cbSize
= MCHITTESTINFO_V1_SIZE
;
1274 mchit
.pt
.x
= r
.right
/ 14;
1275 mchit
.pt
.y
= 18 * r
.bottom
/ 19;
1276 res
= SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
1277 expect(r
.right
/ 14, mchit
.pt
.x
);
1278 expect(18 * r
.bottom
/ 19, mchit
.pt
.y
);
1279 expect(mchit
.uHit
, res
);
1280 expect(MCHT_TODAYLINK
, res
);
1284 st_test
.wYear
= 2005;
1286 res
= SendMessageA(hwnd
, MCM_SETTODAY
, 0, (LPARAM
)&st_test
);
1289 memset(&st_new
, 0, sizeof(st_new
));
1290 res
= SendMessageA(hwnd
, MCM_GETTODAY
, 0, (LPARAM
)&st_new
);
1292 expect(1, st_new
.wDay
);
1293 expect(1, st_new
.wMonth
);
1294 expect(2005, st_new
.wYear
);
1296 res
= SendMessageA(hwnd
, WM_LBUTTONDOWN
, MK_LBUTTON
, MAKELONG(mchit
.pt
.x
, mchit
.pt
.y
));
1299 memset(&st_new
, 0, sizeof(st_new
));
1300 res
= SendMessageA(hwnd
, MCM_GETCURSEL
, 0, (LPARAM
)&st_new
);
1302 expect(1, st_new
.wDay
);
1303 expect(1, st_new
.wMonth
);
1304 expect(2005, st_new
.wYear
);
1306 ok_sequence(sequences
, MONTHCAL_SEQ_INDEX
, monthcal_todaylink_seq
, "monthcal hit test", TRUE
);
1308 DestroyWindow(hwnd
);
1311 static void test_today(void)
1313 SYSTEMTIME st_test
, st_new
;
1317 hwnd
= create_monthcal_control(0);
1319 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1321 /* Setter and Getters for "today" information */
1323 /* check for overflow, should be ok */
1324 memset(&st_test
, 0, sizeof(st_test
));
1326 st_test
.wMonth
= 38;
1331 res
= SendMessageA(hwnd
, MCM_SETTODAY
, 0, (LPARAM
)&st_test
);
1334 res
= SendMessageA(hwnd
, MCM_GETTODAY
, 0, (LPARAM
)&st_new
);
1337 /* st_test should not change */
1338 expect(38, st_test
.wDay
);
1339 expect(38, st_test
.wMonth
);
1341 /* st_new should change, overflow does not matter */
1342 expect(38, st_new
.wDay
);
1343 expect(38, st_new
.wMonth
);
1345 /* check for zero, should be ok*/
1349 res
= SendMessageA(hwnd
, MCM_SETTODAY
, 0, (LPARAM
)&st_test
);
1352 res
= SendMessageA(hwnd
, MCM_GETTODAY
, 0, (LPARAM
)&st_new
);
1355 /* st_test should not change */
1356 expect(0, st_test
.wDay
);
1357 expect(0, st_test
.wMonth
);
1359 /* st_new should change to zero*/
1360 expect(0, st_new
.wDay
);
1361 expect(0, st_new
.wMonth
);
1363 ok_sequence(sequences
, MONTHCAL_SEQ_INDEX
, monthcal_today_seq
, "monthcal today", TRUE
);
1365 DestroyWindow(hwnd
);
1368 static void test_scroll(void)
1373 hwnd
= create_monthcal_control(0);
1375 res
= SendMessageA(hwnd
, MCM_GETMONTHDELTA
, 0, 0);
1378 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1380 /* Setter and Getters for scroll rate */
1381 res
= SendMessageA(hwnd
, MCM_SETMONTHDELTA
, 2, 0);
1384 res
= SendMessageA(hwnd
, MCM_SETMONTHDELTA
, 3, 0);
1386 res
= SendMessageA(hwnd
, MCM_GETMONTHDELTA
, 0, 0);
1389 res
= SendMessageA(hwnd
, MCM_SETMONTHDELTA
, 12, 0);
1391 res
= SendMessageA(hwnd
, MCM_GETMONTHDELTA
, 0, 0);
1394 res
= SendMessageA(hwnd
, MCM_SETMONTHDELTA
, 15, 0);
1396 res
= SendMessageA(hwnd
, MCM_GETMONTHDELTA
, 0, 0);
1399 res
= SendMessageA(hwnd
, MCM_SETMONTHDELTA
, -5, 0);
1401 res
= SendMessageA(hwnd
, MCM_GETMONTHDELTA
, 0, 0);
1404 ok_sequence(sequences
, MONTHCAL_SEQ_INDEX
, monthcal_scroll_seq
, "monthcal scroll", FALSE
);
1406 DestroyWindow(hwnd
);
1409 static void test_monthrange(void)
1412 SYSTEMTIME st_visible
[2], st_daystate
[2], st
;
1416 hwnd
= create_monthcal_control(0);
1418 memset(&st_visible
, 0, sizeof(st_visible
));
1419 memset(&st_daystate
, 0, sizeof(st_daystate
));
1427 st
.wMilliseconds
= 0;
1430 res
= SendMessageA(hwnd
, MCM_SETCURSEL
, 0, (LPARAM
)&st
);
1433 /* to be locale independent */
1434 SendMessageA(hwnd
, MCM_SETFIRSTDAYOFWEEK
, 0, (LPARAM
)6);
1436 res
= SendMessageA(hwnd
, MCM_GETMINREQRECT
, 0, (LPARAM
)&r
);
1438 /* resize control to display two Calendars */
1439 MoveWindow(hwnd
, 0, 0, r
.right
, (5/2)*r
.bottom
, FALSE
);
1441 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1443 res
= SendMessageA(hwnd
, MCM_GETMONTHRANGE
, GMR_VISIBLE
, (LPARAM
)st_visible
);
1445 expect(2000, st_visible
[0].wYear
);
1446 expect(11, st_visible
[0].wMonth
);
1447 expect(1, st_visible
[0].wDay
);
1448 expect(2000, st_visible
[1].wYear
);
1449 expect(12, st_visible
[1].wMonth
);
1450 expect(31, st_visible
[1].wDay
);
1452 res
= SendMessageA(hwnd
, MCM_GETMONTHRANGE
, GMR_DAYSTATE
, (LPARAM
)st_daystate
);
1454 expect(2000, st_daystate
[0].wYear
);
1455 expect(10, st_daystate
[0].wMonth
);
1456 expect(29, st_daystate
[0].wDay
);
1457 expect(2001, st_daystate
[1].wYear
);
1458 expect(1, st_daystate
[1].wMonth
);
1459 expect(6, st_daystate
[1].wDay
);
1461 ok_sequence(sequences
, MONTHCAL_SEQ_INDEX
, monthcal_monthrange_seq
, "monthcal monthrange", FALSE
);
1463 /* with null date array parameter */
1464 res
= SendMessageA(hwnd
, MCM_GETMONTHRANGE
, GMR_VISIBLE
, 0);
1467 res
= SendMessageA(hwnd
, MCM_GETMONTHRANGE
, GMR_DAYSTATE
, 0);
1470 /* resize control to display single Calendar */
1471 MoveWindow(hwnd
, 0, 0, r
.right
, r
.bottom
, FALSE
);
1473 memset(&st
, 0, sizeof(st
));
1478 res
= SendMessageA(hwnd
, MCM_SETCURSEL
, 0, (LPARAM
)&st
);
1481 /* September 1752 has 19 days */
1482 res
= SendMessageA(hwnd
, MCM_GETMONTHRANGE
, GMR_VISIBLE
, (LPARAM
)st_visible
);
1485 expect(1752, st_visible
[0].wYear
);
1486 expect(9, st_visible
[0].wMonth
);
1487 ok(14 == st_visible
[0].wDay
||
1488 broken(1 == st_visible
[0].wDay
), /* comctl32 <= 4.72 */
1489 "Expected 14, got %d\n", st_visible
[0].wDay
);
1491 expect(1752, st_visible
[1].wYear
);
1492 expect(9, st_visible
[1].wMonth
);
1493 expect(19, st_visible
[1].wDay
);
1495 DestroyWindow(hwnd
);
1498 static void test_maxselday(void)
1504 hwnd
= create_monthcal_control(0);
1505 /* if no style specified default to 1 */
1506 res
= SendMessageA(hwnd
, MCM_GETMAXSELCOUNT
, 0, 0);
1508 res
= SendMessageA(hwnd
, MCM_SETMAXSELCOUNT
, 5, 0);
1510 res
= SendMessageA(hwnd
, MCM_GETMAXSELCOUNT
, 0, 0);
1513 /* try to set style */
1514 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
1515 SetWindowLongA(hwnd
, GWL_STYLE
, style
| MCS_MULTISELECT
);
1516 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
1517 ok(!(style
& MCS_MULTISELECT
), "Expected MCS_MULTISELECT not to be set\n");
1518 DestroyWindow(hwnd
);
1520 hwnd
= create_monthcal_control(MCS_MULTISELECT
);
1521 /* try to remove style */
1522 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
1523 SetWindowLongA(hwnd
, GWL_STYLE
, style
& ~MCS_MULTISELECT
);
1524 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
1525 ok(style
& MCS_MULTISELECT
, "Expected MCS_MULTISELECT to be set\n");
1526 DestroyWindow(hwnd
);
1528 hwnd
= create_monthcal_control(MCS_MULTISELECT
);
1530 /* default width is a week */
1531 res
= SendMessageA(hwnd
, MCM_GETMAXSELCOUNT
, 0, 0);
1534 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1536 /* Setter and Getters for max selected days */
1537 res
= SendMessageA(hwnd
, MCM_SETMAXSELCOUNT
, 5, 0);
1539 res
= SendMessageA(hwnd
, MCM_GETMAXSELCOUNT
, 0, 0);
1542 res
= SendMessageA(hwnd
, MCM_SETMAXSELCOUNT
, 15, 0);
1544 res
= SendMessageA(hwnd
, MCM_GETMAXSELCOUNT
, 0, 0);
1547 /* test invalid value */
1548 res
= SendMessageA(hwnd
, MCM_SETMAXSELCOUNT
, -1, 0);
1550 res
= SendMessageA(hwnd
, MCM_GETMAXSELCOUNT
, 0, 0);
1553 ok_sequence(sequences
, MONTHCAL_SEQ_INDEX
, monthcal_max_sel_day_seq
, "monthcal MaxSelDay", FALSE
);
1555 /* zero value is invalid too */
1556 res
= SendMessageA(hwnd
, MCM_SETMAXSELCOUNT
, 0, 0);
1558 res
= SendMessageA(hwnd
, MCM_GETMAXSELCOUNT
, 0, 0);
1561 DestroyWindow(hwnd
);
1564 static void test_size(void)
1568 HFONT hFont1
, hFont2
;
1572 hwnd
= create_monthcal_control(0);
1574 lstrcpyA(logfont
.lfFaceName
, "Arial");
1575 memset(&logfont
, 0, sizeof(logfont
));
1576 logfont
.lfHeight
= 12;
1577 hFont1
= CreateFontIndirectA(&logfont
);
1579 logfont
.lfHeight
= 24;
1580 hFont2
= CreateFontIndirectA(&logfont
);
1582 /* initialize to a font we can compare against */
1583 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hFont1
, 0);
1584 res
= SendMessageA(hwnd
, MCM_GETMINREQRECT
, 0, (LPARAM
)&r1
);
1585 ok(res
, "SendMessageA(MCM_GETMINREQRECT) failed\n");
1587 /* check that setting a larger font results in an larger rect */
1588 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hFont2
, 0);
1589 res
= SendMessageA(hwnd
, MCM_GETMINREQRECT
, 0, (LPARAM
)&r2
);
1590 ok(res
, "SendMessageA(MCM_GETMINREQRECT) failed\n");
1592 OffsetRect(&r1
, -r1
.left
, -r1
.top
);
1593 OffsetRect(&r2
, -r2
.left
, -r2
.top
);
1595 ok(r1
.bottom
< r2
.bottom
, "Failed to get larger rect with larger font\n");
1597 DestroyWindow(hwnd
);
1600 static void test_create(void)
1604 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1606 hwnd
= create_monthcal_control(0);
1607 ok_sequence(sequences
, PARENT_SEQ_INDEX
, create_monthcal_control_seq
, "create monthcal control", TRUE
);
1609 DestroyWindow(hwnd
);
1611 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1612 hwnd
= create_monthcal_control(MCS_MULTISELECT
);
1613 ok_sequence(sequences
, PARENT_SEQ_INDEX
, create_monthcal_multi_sel_style_seq
, "create monthcal (multi sel style)", TRUE
);
1614 DestroyWindow(hwnd
);
1617 static void test_destroy(void)
1621 hwnd
= create_monthcal_control(0);
1622 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1623 DestroyWindow(hwnd
);
1624 ok_sequence(sequences
, PARENT_SEQ_INDEX
, destroy_monthcal_parent_msgs_seq
, "Destroy monthcal (parent msg)", FALSE
);
1625 ok_sequence(sequences
, MONTHCAL_SEQ_INDEX
, destroy_monthcal_child_msgs_seq
, "Destroy monthcal (child msg)", FALSE
);
1627 /* MCS_MULTISELECT */
1628 hwnd
= create_monthcal_control(MCS_MULTISELECT
);
1629 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1630 DestroyWindow(hwnd
);
1631 ok_sequence(sequences
, MONTHCAL_SEQ_INDEX
, destroy_monthcal_multi_sel_style_seq
, "Destroy monthcal (multi sel style)", FALSE
);
1634 static void test_selrange(void)
1637 SYSTEMTIME st
, range
[2], range2
[2];
1638 BOOL ret
, old_comctl32
= FALSE
;
1640 hwnd
= create_monthcal_control(MCS_MULTISELECT
);
1642 /* just after creation selection should start and end today */
1643 ret
= SendMessageA(hwnd
, MCM_GETTODAY
, 0, (LPARAM
)&st
);
1646 memset(range
, 0xcc, sizeof(range
));
1647 ret
= SendMessageA(hwnd
, MCM_GETSELRANGE
, 0, (LPARAM
)range
);
1649 expect(st
.wYear
, range
[0].wYear
);
1650 expect(st
.wMonth
, range
[0].wMonth
);
1651 expect(st
.wDay
, range
[0].wDay
);
1652 if (range
[0].wDayOfWeek
!= st
.wDayOfWeek
)
1654 win_skip("comctl32 <= 4.70 doesn't set some values\n");
1655 old_comctl32
= TRUE
;
1659 expect(st
.wDayOfWeek
, range
[0].wDayOfWeek
);
1660 expect(st
.wHour
, range
[0].wHour
);
1661 expect(st
.wMinute
, range
[0].wMinute
);
1662 expect(st
.wSecond
, range
[0].wSecond
);
1663 expect(st
.wMilliseconds
, range
[0].wMilliseconds
);
1666 expect(st
.wYear
, range
[1].wYear
);
1667 expect(st
.wMonth
, range
[1].wMonth
);
1668 expect(st
.wDay
, range
[1].wDay
);
1671 expect(st
.wDayOfWeek
, range
[1].wDayOfWeek
);
1672 expect(st
.wHour
, range
[1].wHour
);
1673 expect(st
.wMinute
, range
[1].wMinute
);
1674 expect(st
.wSecond
, range
[1].wSecond
);
1675 expect(st
.wMilliseconds
, range
[1].wMilliseconds
);
1678 /* bounds are swapped if min > max */
1679 memset(&range
[0], 0, sizeof(range
[0]));
1680 range
[0].wYear
= 2009;
1681 range
[0].wMonth
= 10;
1683 range
[1] = range
[0];
1686 ret
= SendMessageA(hwnd
, MCM_SETSELRANGE
, 0, (LPARAM
)range
);
1689 ret
= SendMessageA(hwnd
, MCM_GETSELRANGE
, 0, (LPARAM
)range2
);
1692 expect(range
[1].wYear
, range2
[0].wYear
);
1693 expect(range
[1].wMonth
, range2
[0].wMonth
);
1694 expect(range
[1].wDay
, range2
[0].wDay
);
1695 expect(6, range2
[0].wDayOfWeek
);
1696 expect(range
[1].wHour
, range2
[0].wHour
);
1697 expect(range
[1].wMinute
, range2
[0].wMinute
);
1698 expect(range
[1].wSecond
, range2
[0].wSecond
);
1699 expect(range
[1].wMilliseconds
, range2
[0].wMilliseconds
);
1701 expect(range
[0].wYear
, range2
[1].wYear
);
1702 expect(range
[0].wMonth
, range2
[1].wMonth
);
1703 expect(range
[0].wDay
, range2
[1].wDay
);
1704 expect(1, range2
[1].wDayOfWeek
);
1705 expect(range
[0].wHour
, range2
[1].wHour
);
1706 expect(range
[0].wMinute
, range2
[1].wMinute
);
1707 expect(range
[0].wSecond
, range2
[1].wSecond
);
1708 expect(range
[0].wMilliseconds
, range2
[1].wMilliseconds
);
1710 /* try with range larger than maximum configured */
1711 memset(&range
[0], 0, sizeof(range
[0]));
1712 range
[0].wYear
= 2009;
1713 range
[0].wMonth
= 10;
1715 range
[1] = range
[0];
1717 ret
= SendMessageA(hwnd
, MCM_SETSELRANGE
, 0, (LPARAM
)range
);
1720 range
[1] = range
[0];
1721 /* default max. range is 7 days */
1724 ret
= SendMessageA(hwnd
, MCM_SETSELRANGE
, 0, (LPARAM
)range
);
1727 ret
= SendMessageA(hwnd
, MCM_GETSELRANGE
, 0, (LPARAM
)range2
);
1730 expect(range
[0].wYear
, range2
[0].wYear
);
1731 expect(range
[0].wMonth
, range2
[0].wMonth
);
1732 expect(range
[0].wDay
, range2
[0].wDay
);
1733 expect(range
[0].wYear
, range2
[1].wYear
);
1734 expect(range
[0].wMonth
, range2
[1].wMonth
);
1735 expect(range
[0].wDay
, range2
[1].wDay
);
1737 DestroyWindow(hwnd
);
1740 static void test_killfocus(void)
1745 hwnd
= create_monthcal_control(0);
1747 /* make parent invisible */
1748 style
= GetWindowLongA(parent_wnd
, GWL_STYLE
);
1749 SetWindowLongA(parent_wnd
, GWL_STYLE
, style
& ~WS_VISIBLE
);
1751 SendMessageA(hwnd
, WM_KILLFOCUS
, (WPARAM
)GetDesktopWindow(), 0);
1753 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
1754 ok(style
& WS_VISIBLE
, "Expected WS_VISIBLE to be set\n");
1756 style
= GetWindowLongA(parent_wnd
, GWL_STYLE
);
1757 SetWindowLongA(parent_wnd
, GWL_STYLE
, style
| WS_VISIBLE
);
1759 DestroyWindow(hwnd
);
1762 static void test_hittest_v6(void)
1764 MCHITTESTINFO mchit
;
1769 hwnd
= create_monthcal_control(0);
1770 SendMessageA(hwnd
, MCM_SETCALENDARBORDER
, TRUE
, 0);
1772 SendMessageA(hwnd
, MCM_GETMINREQRECT
, 0, (LPARAM
)&r
);
1773 /* reserving some area around calendar */
1774 MoveWindow(hwnd
, 0, 0, r
.right
* 3 / 2, r
.bottom
* 3 / 2, FALSE
);
1775 mchit
.cbSize
= sizeof(MCHITTESTINFO
);
1776 mchit
.pt
.x
= mchit
.pt
.y
= 0;
1780 ret
= SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
1783 win_skip("Only MCHITTESTINFO_V1 supported\n");
1784 DestroyWindow(hwnd
);
1787 todo_wine
expect_hex(MCHT_NOWHERE
, ret
);
1788 expect(-1, mchit
.iOffset
);
1789 expect(-1, mchit
.iRow
);
1790 expect(-1, mchit
.iCol
);
1792 MoveWindow(hwnd
, 0, 0, r
.right
, r
.bottom
, FALSE
);
1793 mchit
.pt
.x
= r
.right
/ 2;
1794 mchit
.pt
.y
= r
.bottom
/ 2;
1796 ret
= SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
1797 expect_hex(MCHT_CALENDARDATE
, ret
);
1798 expect(0, mchit
.iOffset
);
1801 mchit
.pt
.x
= r
.right
/ (7*2);
1802 mchit
.pt
.y
= r
.bottom
/ 2;
1804 mchit
.iCol
= mchit
.iRow
= -1;
1806 mchit
.rc
.left
= mchit
.rc
.right
= mchit
.rc
.top
= mchit
.rc
.bottom
= -1;
1807 ret
= SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
1808 expect_hex(MCHT_CALENDARDATE
, ret
);
1809 expect_hex(MCHT_CALENDARDATE
, mchit
.uHit
);
1810 expect(0, mchit
.iOffset
);
1811 expect(2, mchit
.iRow
);
1812 expect(0, mchit
.iCol
);
1813 /* returned a one day rectangle */
1814 expect_d(r
.right
/ 7, mchit
.rc
.right
- mchit
.rc
.left
);
1815 expect_d(r
.bottom
/ 10, mchit
.rc
.bottom
- mchit
.rc
.top
);
1821 mchit
.iCol
= mchit
.iRow
= -1;
1823 mchit
.rc
.left
= mchit
.rc
.right
= mchit
.rc
.top
= mchit
.rc
.bottom
= -1;
1824 ret
= SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
1825 expect_hex(MCHT_TITLE
, ret
);
1826 expect_hex(MCHT_TITLE
, mchit
.uHit
);
1827 expect(0, mchit
.iOffset
);
1828 expect(-1, mchit
.iRow
);
1829 expect(-1, mchit
.iCol
);
1830 expect(0, mchit
.rc
.left
);
1831 expect(0, mchit
.rc
.top
);
1832 expect_d(r
.right
, mchit
.rc
.right
);
1833 ok(mchit
.rc
.bottom
> 0, "got %d\n", mchit
.rc
.bottom
);
1835 /* between two calendars */
1836 MoveWindow(hwnd
, 0, 0, r
.right
* 5/2, r
.bottom
, FALSE
);
1837 mchit
.pt
.x
= r
.right
/ (5*4);
1838 mchit
.pt
.y
= r
.bottom
/ 2;
1840 mchit
.iCol
= mchit
.iRow
= -2;
1842 mchit
.rc
.left
= mchit
.rc
.right
= mchit
.rc
.top
= mchit
.rc
.bottom
= -1;
1843 ret
= SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
1844 todo_wine
expect_hex(MCHT_NOWHERE
, ret
);
1845 todo_wine
expect_hex(MCHT_NOWHERE
, mchit
.uHit
);
1846 expect(-2, mchit
.iOffset
);
1847 expect(-2, mchit
.iRow
);
1848 expect(-2, mchit
.iCol
);
1849 todo_wine
expect(0, mchit
.rc
.left
);
1850 todo_wine
expect(0, mchit
.rc
.top
);
1851 todo_wine
expect_d(r
.right
* 5/2, mchit
.rc
.right
);
1852 todo_wine
expect_d(r
.bottom
, mchit
.rc
.bottom
);
1854 DestroyWindow(hwnd
);
1857 static void test_get_set_border(void)
1862 hwnd
= create_monthcal_control(0);
1864 /* a non-default value */
1865 ret
= SendMessageA(hwnd
, MCM_SETCALENDARBORDER
, TRUE
, 10);
1868 ret
= SendMessageA(hwnd
, MCM_GETCALENDARBORDER
, 0, 0);
1872 skip("MCM_GET/SETCALENDARBORDER not supported\n");
1873 DestroyWindow(hwnd
);
1879 DestroyWindow(hwnd
);
1882 static void test_MCM_SIZERECTTOMIN(void)
1888 hwnd
= create_monthcal_control(0);
1890 ret
= SendMessageA(hwnd
, MCM_GETMINREQRECT
, 0, (LPARAM
)&r2
);
1893 win_skip("Message MCM_GETMINREQRECT unsupported. Skipping.\n");
1894 DestroyWindow(hwnd
);
1898 ret
= SendMessageA(hwnd
, MCM_SIZERECTTOMIN
, 0, 0);
1899 ok(ret
== 0, "got %d\n", ret
);
1902 ret
= SendMessageA(hwnd
, MCM_SIZERECTTOMIN
, 0, (LPARAM
)&r
);
1905 skip("Message MCM_SIZERECTTOMIN unsupported. Skipping.\n");
1906 DestroyWindow(hwnd
);
1909 ok(ret
== 1, "got %d\n", ret
);
1910 ok(r
.left
== 0 && r
.right
> 0, "got %d, %d\n", r
.left
, r
.right
);
1913 ret
= SendMessageA(hwnd
, MCM_SIZERECTTOMIN
, 0, (LPARAM
)&r
);
1914 ok(ret
== 1, "got %d\n", ret
);
1916 r2
.right
= (r2
.right
- r2
.left
) * 3;
1917 r2
.bottom
= (r2
.bottom
- r2
.top
) * 3;
1918 r2
.left
= r2
.top
= 0;
1919 ret
= SendMessageA(hwnd
, MCM_SIZERECTTOMIN
, 0, (LPARAM
)&r2
);
1920 ok(ret
== 1, "got %d\n", ret
);
1922 DestroyWindow(hwnd
);
1925 static void test_MCM_GETCALENDARCOUNT(void)
1930 hwnd
= create_monthcal_control(0);
1932 ret
= SendMessageA(hwnd
, MCM_GETCALENDARCOUNT
, 0, 0);
1935 win_skip("Message MCM_GETCALENDARCOUNT unsupported. Skipping.\n");
1936 DestroyWindow(hwnd
);
1942 DestroyWindow(hwnd
);
1945 static void test_daystate(void)
1947 MONTHDAYSTATE state
[4];
1952 /* without MCS_DAYSTATE */
1953 hwnd
= create_monthcal_control(0);
1955 ret
= SendMessageA(hwnd
, MCM_GETMINREQRECT
, 0, (LPARAM
)&r
);
1958 /* resize control to display two Calendars */
1959 MoveWindow(hwnd
, 0, 0, r
.right
, (5/2)*r
.bottom
, FALSE
);
1961 ret
= SendMessageA(hwnd
, MCM_GETMONTHRANGE
, GMR_DAYSTATE
, 0);
1964 ret
= SendMessageA(hwnd
, MCM_SETDAYSTATE
, 4, (LPARAM
)&state
);
1967 ret
= SendMessageA(hwnd
, MCM_SETDAYSTATE
, 2, (LPARAM
)&state
);
1970 ret
= SendMessageA(hwnd
, MCM_SETDAYSTATE
, 0, 0);
1973 /* try to switch on */
1974 SetWindowLongA(hwnd
, GWL_STYLE
, GetWindowLongA(hwnd
, GWL_STYLE
) | MCS_DAYSTATE
);
1975 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
1976 ok((style
& MCS_DAYSTATE
) == 0, "got 0x%08x\n", style
);
1978 DestroyWindow(hwnd
);
1980 /* with MCS_DAYSTATE */
1981 hwnd
= create_monthcal_control(MCS_DAYSTATE
);
1983 ret
= SendMessageA(hwnd
, MCM_GETMONTHRANGE
, GMR_DAYSTATE
, 0);
1986 ret
= SendMessageA(hwnd
, MCM_SETDAYSTATE
, 4, (LPARAM
)&state
);
1989 ret
= SendMessageA(hwnd
, MCM_SETDAYSTATE
, 2, (LPARAM
)&state
);
1992 ret
= SendMessageA(hwnd
, MCM_SETDAYSTATE
, 0, 0);
1995 /* try to switch off */
1996 SetWindowLongA(hwnd
, GWL_STYLE
, GetWindowLongA(hwnd
, GWL_STYLE
) & ~MCS_DAYSTATE
);
1997 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
1998 ok((style
& MCS_DAYSTATE
) == MCS_DAYSTATE
, "got 0x%08x\n", style
);
2000 DestroyWindow(hwnd
);
2003 static void test_sel_notify(void)
2013 MCHITTESTINFO mchit
= {sizeof(MCHITTESTINFO
)};
2015 Monthcal_style styles
[] = {
2016 {MCS_NOTODAY
, "MCS_NOTODAY"},
2017 {MCS_NOTODAY
| MCS_MULTISELECT
, "MCS_NOTODAY | MCS_MULTISELECT"},
2018 {MCS_DAYSTATE
, "MCS_DAYSTATE"},
2019 {MCS_DAYSTATE
| MCS_MULTISELECT
, "MCS_DAYSTATE | MCS_MULTISELECT"}
2023 for(i
= 0; i
< sizeof styles
/ sizeof styles
[0]; i
++)
2025 hwnd
= create_monthcal_control(styles
[i
].val
);
2026 SetWindowLongPtrA(hwnd
, GWLP_ID
, SEL_NOTIFY_TEST_ID
);
2027 SendMessageA(hwnd
, MCM_GETMINREQRECT
, 0, (LPARAM
)&rc
);
2028 MoveWindow(hwnd
, 0, 0, rc
.right
, rc
.bottom
, FALSE
);
2029 /* Simulate mouse click on some unselected day to generate
2030 MCN_SELECT and MCN_SELCHANGE notifications */
2031 mchit
.pt
.x
= rc
.right
/ 2;
2032 mchit
.pt
.y
= rc
.bottom
/ 2;
2033 SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
2034 SendMessageA(hwnd
, MCM_GETCURSEL
, 0, (LPARAM
)&st
);
2035 while(st
.wDay
== mchit
.st
.wDay
) /* Ensure that mchit.pt points to unselected day */
2038 SendMessageA(hwnd
, MCM_HITTEST
, 0, (LPARAM
)&mchit
);
2040 SendMessageA(hwnd
, WM_LBUTTONDOWN
, 0, MAKELPARAM(mchit
.pt
.x
, mchit
.pt
.y
));
2041 SendMessageA(hwnd
, WM_LBUTTONUP
, 0, MAKELPARAM(mchit
.pt
.x
, mchit
.pt
.y
));
2042 DestroyWindow(hwnd
);
2046 START_TEST(monthcal
)
2048 BOOL (WINAPI
*pInitCommonControlsEx
)(const INITCOMMONCONTROLSEX
*);
2049 INITCOMMONCONTROLSEX iccex
;
2052 ULONG_PTR ctx_cookie
;
2055 hComctl32
= GetModuleHandleA("comctl32.dll");
2056 pInitCommonControlsEx
= (void*)GetProcAddress(hComctl32
, "InitCommonControlsEx");
2057 if (!pInitCommonControlsEx
)
2059 skip("InitCommonControlsEx() is missing. Skipping the tests\n");
2062 iccex
.dwSize
= sizeof(iccex
);
2063 iccex
.dwICC
= ICC_DATE_CLASSES
;
2064 pInitCommonControlsEx(&iccex
);
2068 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
2070 parent_wnd
= create_parent_window();
2090 if (!load_v6_module(&ctx_cookie
, &hCtx
))
2092 DestroyWindow(parent_wnd
);
2097 test_get_set_border();
2098 test_MCM_SIZERECTTOMIN();
2099 test_MCM_GETCALENDARCOUNT();
2101 unload_v6_module(ctx_cookie
, hCtx
);
2103 DestroyWindow(parent_wnd
);