comctl32/tests: Fix some test failures on older comctl32 versions.
[wine] / dlls / comctl32 / tests / monthcal.c
1 /*
2  * comctl32 month calendar unit tests
3  *
4  * Copyright (C) 2006 Vitaliy Margolen
5  * Copyright (C) 2007 Farshad Agah
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 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27
28 #include "commctrl.h"
29
30 #include "wine/test.h"
31 #include <assert.h>
32 #include <windows.h>
33 #include "msg.h"
34
35 #define expect(expected, got) ok(expected == got, "Expected %d, got %d\n", expected, got);
36 #define expect_hex(expected, got) ok(expected == got, "Expected %x, got %x\n", expected, got);
37
38 #define NUM_MSG_SEQUENCES   2
39 #define PARENT_SEQ_INDEX    0
40 #define MONTHCAL_SEQ_INDEX  1
41
42 struct subclass_info
43 {
44     WNDPROC oldproc;
45 };
46
47 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
48
49 static HWND parent_wnd;
50
51 static const struct message create_parent_window_seq[] = {
52     { WM_GETMINMAXINFO, sent },
53     { WM_NCCREATE, sent },
54     { WM_NCCALCSIZE, sent|wparam, 0 },
55     { WM_CREATE, sent },
56     { WM_SHOWWINDOW, sent|wparam, 1 },
57     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
58     { WM_QUERYNEWPALETTE, sent|optional },
59     { WM_WINDOWPOSCHANGING, sent|wparam|optional, 0 },
60     { WM_WINDOWPOSCHANGED, sent|optional },
61     { WM_ACTIVATEAPP, sent|wparam, 1 },
62     { WM_NCACTIVATE, sent },
63     { WM_ACTIVATE, sent|wparam, 1 },
64     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
65     { WM_IME_NOTIFY, sent|defwinproc|optional },
66     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
67     /* Win9x adds SWP_NOZORDER below */
68     { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
69     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
70     { WM_SIZE, sent },
71     { WM_MOVE, sent },
72     { 0 }
73 };
74
75 static const struct message create_monthcal_control_seq[] = {
76     { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY },
77     { WM_QUERYUISTATE, sent|optional },
78     { WM_GETFONT, sent },
79     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE},
80     { 0 }
81 };
82
83 static const struct message create_monthcal_multi_sel_style_seq[] = {
84     { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY },
85     { WM_QUERYUISTATE, sent|optional },
86     { WM_GETFONT, sent },
87     { WM_PARENTNOTIFY, sent },
88     { 0 }
89 };
90
91 static const struct message monthcal_color_seq[] = {
92     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0},
93     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(0,0,0)},
94     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0},
95     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(255,255,255)},
96     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0},
97
98     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0},
99     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(0,0,0)},
100     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0},
101     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(255,255,255)},
102     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0},
103
104     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0},
105     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(0,0,0)},
106     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0},
107     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(255,255,255)},
108     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0},
109
110     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0},
111     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(0,0,0)},
112     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0},
113     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(255,255,255)},
114     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0},
115
116     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0},
117     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(0,0,0)},
118     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0},
119     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(255,255,255)},
120     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0},
121
122     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0},
123     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(0,0,0)},
124     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0},
125     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(255,255,255)},
126     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0},
127     { 0 }
128 };
129
130 static const struct message monthcal_curr_date_seq[] = {
131     { MCM_SETCURSEL, sent|wparam, 0},
132     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
133     { MCM_SETCURSEL, sent|wparam, 0},
134     { MCM_SETCURSEL, sent|wparam, 0},
135     { MCM_GETCURSEL, sent|wparam, 0},
136     { MCM_GETCURSEL, sent|wparam|lparam, 0, 0},
137     { 0 }
138 };
139
140 static const struct message monthcal_first_day_seq[] = {
141     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
142
143     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -5},
144     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
145
146     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -4},
147     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
148
149     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -3},
150     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
151
152     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -2},
153     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
154
155     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -1},
156     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
157
158     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
159     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
160
161     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 1},
162     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
163
164     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 2},
165     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
166
167     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 3},
168     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
169
170     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 4},
171     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
172
173     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 5},
174     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
175
176     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 6},
177     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
178
179     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 7},
180     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
181
182     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 8},
183     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
184
185     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 9},
186     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
187
188     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 10},
189     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
190
191     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 11},
192     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
193     { 0 }
194 };
195
196 static const struct message monthcal_unicode_seq[] = {
197     { MCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0},
198     { MCM_SETUNICODEFORMAT, sent|wparam|lparam, 1, 0},
199     { MCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0},
200     { MCM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0},
201     { MCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0},
202     { MCM_SETUNICODEFORMAT, sent|wparam|lparam, 1, 0},
203     { 0 }
204 };
205
206 static const struct message monthcal_hit_test_seq[] = {
207     { MCM_SETCURSEL, sent|wparam, 0},
208     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
209     { MCM_HITTEST, sent|wparam, 0},
210     { MCM_HITTEST, sent|wparam, 0},
211     { MCM_HITTEST, sent|wparam, 0},
212     { MCM_HITTEST, sent|wparam, 0},
213     { MCM_HITTEST, sent|wparam, 0},
214     { MCM_HITTEST, sent|wparam, 0},
215     { MCM_HITTEST, sent|wparam, 0},
216     { MCM_HITTEST, sent|wparam, 0},
217     { MCM_HITTEST, sent|wparam, 0},
218     { MCM_HITTEST, sent|wparam, 0},
219     { 0 }
220 };
221
222 static const struct message monthcal_todaylink_seq[] = {
223     { MCM_HITTEST, sent|wparam, 0},
224     { MCM_SETTODAY, sent|wparam, 0},
225     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
226     { MCM_GETTODAY, sent|wparam, 0},
227     { WM_LBUTTONDOWN, sent|wparam|lparam, MK_LBUTTON, MAKELONG(70, 370)},
228     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0},
229     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
230     { MCM_GETCURSEL, sent|wparam, 0},
231     { 0 }
232 };
233
234 static const struct message monthcal_today_seq[] = {
235     { MCM_SETTODAY, sent|wparam, 0},
236     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
237     { MCM_GETTODAY, sent|wparam, 0},
238     { MCM_SETTODAY, sent|wparam, 0},
239     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
240     { MCM_GETTODAY, sent|wparam, 0},
241     { 0 }
242 };
243
244 static const struct message monthcal_scroll_seq[] = {
245     { MCM_SETMONTHDELTA, sent|wparam|lparam, 2, 0},
246     { MCM_SETMONTHDELTA, sent|wparam|lparam, 3, 0},
247     { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
248     { MCM_SETMONTHDELTA, sent|wparam|lparam, 12, 0},
249     { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
250     { MCM_SETMONTHDELTA, sent|wparam|lparam, 15, 0},
251     { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
252     { MCM_SETMONTHDELTA, sent|wparam|lparam, -5, 0},
253     { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
254     { 0 }
255 };
256
257 static const struct message monthcal_monthrange_seq[] = {
258     { MCM_GETMONTHRANGE, sent|wparam, GMR_VISIBLE},
259     { MCM_GETMONTHRANGE, sent|wparam, GMR_DAYSTATE},
260     { 0 }
261 };
262
263 static const struct message monthcal_max_sel_day_seq[] = {
264     { MCM_SETMAXSELCOUNT, sent|wparam|lparam, 5, 0},
265     { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0},
266     { MCM_SETMAXSELCOUNT, sent|wparam|lparam, 15, 0},
267     { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0},
268     { MCM_SETMAXSELCOUNT, sent|wparam|lparam, -1, 0},
269     { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0},
270     { 0 }
271 };
272
273 /* expected message sequence for parent*/
274 static const struct message destroy_monthcal_parent_msgs_seq[] = {
275     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY},
276     { 0 }
277 };
278
279 /* expected message sequence for child*/
280 static const struct message destroy_monthcal_child_msgs_seq[] = {
281     { 0x0090, sent|optional }, /* Vista */
282     { WM_SHOWWINDOW, sent|wparam|lparam, 0, 0},
283     { WM_WINDOWPOSCHANGING, sent|wparam, 0},
284     { WM_WINDOWPOSCHANGED, sent|wparam, 0},
285     { WM_DESTROY, sent|wparam|lparam, 0, 0},
286     { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
287     { 0 }
288 };
289
290 static const struct message destroy_monthcal_multi_sel_style_seq[] = {
291     { 0x0090, sent|optional }, /* Vista */
292     { WM_SHOWWINDOW, sent|wparam|lparam, 0, 0},
293     { WM_WINDOWPOSCHANGING, sent|wparam, 0},
294     { WM_WINDOWPOSCHANGED, sent|wparam, 0},
295     { WM_DESTROY, sent|wparam|lparam, 0, 0},
296     { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
297     { 0 }
298 };
299
300 /* expected message sequence for parent window*/
301 static const struct message destroy_parent_seq[] = {
302     { 0x0090, sent|optional }, /* Vista */
303     { WM_WINDOWPOSCHANGING, sent|wparam, 0},
304     { WM_WINDOWPOSCHANGED, sent|wparam, 0},
305     { WM_IME_SETCONTEXT, sent|wparam|optional, 0},
306     { WM_IME_NOTIFY, sent|wparam|lparam|defwinproc|optional, 1, 0},
307     { WM_NCACTIVATE, sent|wparam|optional, 0},
308     { WM_ACTIVATE, sent|wparam|optional, 0},
309     { WM_NCACTIVATE, sent|wparam|lparam|optional, 0, 0},
310     { WM_ACTIVATE, sent|wparam|lparam|optional, 0, 0},
311     { WM_ACTIVATEAPP, sent|wparam|optional, 0},
312     { WM_KILLFOCUS, sent|wparam|lparam|optional, 0, 0},
313     { WM_IME_SETCONTEXT, sent|wparam|optional, 0},
314     { WM_IME_NOTIFY, sent|wparam|lparam|defwinproc|optional, 1, 0},
315     { WM_DESTROY, sent|wparam|lparam, 0, 0},
316     { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
317     { 0 }
318 };
319
320 static void test_monthcal(void)
321 {
322     HWND hwnd;
323     SYSTEMTIME st[2], st1[2], today;
324     int res, month_range;
325     DWORD limits;
326
327     hwnd = CreateWindowA(MONTHCAL_CLASSA, "MonthCal", WS_POPUP | WS_VISIBLE, CW_USEDEFAULT,
328                          0, 300, 300, 0, 0, NULL, NULL);
329     ok(hwnd != NULL, "Failed to create MonthCal\n");
330
331     /* test range just after creation */
332     memset(&st, 0xcc, sizeof(st));
333     limits = SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st);
334     ok(limits == 0 ||
335        broken(limits == GDTR_MIN), /* comctl32 <= 4.70 */
336        "No limits should be set (%d)\n", limits);
337     if (limits == GDTR_MIN)
338     {
339         win_skip("comctl32 <= 4.70 is broken\n");
340         DestroyWindow(hwnd);
341         return;
342     }
343
344     ok(0 == st[0].wYear ||
345        broken(1752 == st[0].wYear), /* comctl32 <= 4.72 */
346        "Expected 0, got %d\n", st[0].wYear);
347     ok(0 == st[0].wMonth ||
348        broken(9 == st[0].wMonth), /* comctl32 <= 4.72 */
349        "Expected 0, got %d\n", st[0].wMonth);
350     ok(0 == st[0].wDay ||
351        broken(14 == st[0].wDay), /* comctl32 <= 4.72 */
352        "Expected 0, got %d\n", st[0].wDay);
353     expect(0, st[0].wDayOfWeek);
354     expect(0, st[0].wHour);
355     expect(0, st[0].wMinute);
356     expect(0, st[0].wSecond);
357     expect(0, st[0].wMilliseconds);
358
359     expect(0, st[1].wYear);
360     expect(0, st[1].wMonth);
361     expect(0, st[1].wDay);
362     expect(0, st[1].wDayOfWeek);
363     expect(0, st[1].wHour);
364     expect(0, st[1].wMinute);
365     expect(0, st[1].wSecond);
366     expect(0, st[1].wMilliseconds);
367
368     GetSystemTime(&st[0]);
369     st[1] = st[0];
370
371     SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&today);
372
373     /* Invalid date/time */
374     st[0].wYear  = 2000;
375     /* Time should not matter */
376     st[1].wHour = st[1].wMinute = st[1].wSecond = 70;
377     st[1].wMilliseconds = 1200;
378     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set MAX limit\n");
379     /* invalid timestamp is written back with today data and msecs untouched */
380     expect(today.wHour, st[1].wHour);
381     expect(today.wMinute, st[1].wMinute);
382     expect(today.wSecond, st[1].wSecond);
383     expect(1200, st[1].wMilliseconds);
384
385     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
386     ok(st1[0].wYear != 2000, "Lower limit changed\n");
387     /* invalid timestamp should be replaced with today data, except msecs */
388     expect(today.wHour, st1[1].wHour);
389     expect(today.wMinute, st1[1].wMinute);
390     expect(today.wSecond, st1[1].wSecond);
391     expect(1200, st1[1].wMilliseconds);
392
393     /* Invalid date/time with invalid milliseconds only */
394     GetSystemTime(&st[0]);
395     st[1] = st[0];
396     /* Time should not matter */
397     st[1].wMilliseconds = 1200;
398     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set MAX limit\n");
399     /* invalid milliseconds field doesn't lead to invalid timestamp */
400     expect(st[0].wHour,   st[1].wHour);
401     expect(st[0].wMinute, st[1].wMinute);
402     expect(st[0].wSecond, st[1].wSecond);
403     expect(1200, st[1].wMilliseconds);
404
405     GetSystemTime(&st[0]);
406
407     st[1].wMonth = 0;
408     ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Should have failed to set limits\n");
409     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
410     ok(st1[0].wYear != 2000, "Lower limit changed\n");
411     ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Should have failed to set MAX limit\n");
412     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
413     ok(st1[0].wYear != 2000, "Lower limit changed\n");
414
415     GetSystemTime(&st[0]);
416     st[0].wDay = 20;
417     st[0].wMonth = 5;
418     st[1] = st[0];
419
420     month_range = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
421     st[1].wMonth--;
422     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
423     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
424     ok(res == month_range, "Invalid month range (%d)\n", res);
425     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == (GDTR_MIN|GDTR_MAX), "Limits should be set\n");
426
427     st[1].wMonth += 2;
428     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
429     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
430     ok(res == month_range, "Invalid month range (%d)\n", res);
431
432     st[1].wYear --;
433     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
434     st[1].wYear += 1;
435     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
436
437     st[1].wMonth -= 3;
438     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
439     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "Only MAX limit should be set\n");
440     st[1].wMonth += 4;
441     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
442     st[1].wYear -= 3;
443     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
444     st[1].wYear += 4;
445     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
446     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "Only MAX limit should be set\n");
447
448     /* set both limits, then set max < min */
449     GetSystemTime(&st[0]);
450     st[1] = st[0];
451     st[1].wYear++;
452     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN|GDTR_MAX, (LPARAM)st), "Failed to set limits\n");
453     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == (GDTR_MIN|GDTR_MAX), "Min limit expected\n");
454     st[1].wYear -= 2;
455     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set limits\n");
456     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "Max limit expected\n");
457
458     expect(0, st1[0].wYear);
459     expect(0, st1[0].wMonth);
460     expect(0, st1[0].wDay);
461     expect(0, st1[0].wDayOfWeek);
462     expect(0, st1[0].wHour);
463     expect(0, st1[0].wMinute);
464     expect(0, st1[0].wSecond);
465     expect(0, st1[0].wMilliseconds);
466
467     expect(st[1].wYear,      st1[1].wYear);
468     expect(st[1].wMonth,     st1[1].wMonth);
469     expect(st[1].wDay,       st1[1].wDay);
470     expect(st[1].wDayOfWeek, st1[1].wDayOfWeek);
471     expect(st[1].wHour,      st1[1].wHour);
472     expect(st[1].wMinute,    st1[1].wMinute);
473     expect(st[1].wSecond,    st1[1].wSecond);
474     expect(st[1].wMilliseconds, st1[1].wMilliseconds);
475
476     st[1] = st[0];
477     st[1].wYear++;
478     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN|GDTR_MAX, (LPARAM)st), "Failed to set limits\n");
479     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == (GDTR_MIN|GDTR_MAX), "Min limit expected\n");
480     st[0].wYear++; /* start == end now */
481     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN, (LPARAM)st), "Failed to set limits\n");
482     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MIN, "Min limit expected\n");
483
484     expect(st[0].wYear,      st1[0].wYear);
485     expect(st[0].wMonth,     st1[0].wMonth);
486     expect(st[0].wDay,       st1[0].wDay);
487     expect(st[0].wDayOfWeek, st1[0].wDayOfWeek);
488     expect(st[0].wHour,      st1[0].wHour);
489     expect(st[0].wMinute,    st1[0].wMinute);
490     expect(st[0].wSecond,    st1[0].wSecond);
491     expect(st[0].wMilliseconds, st1[0].wMilliseconds);
492
493     expect(0, st1[1].wYear);
494     expect(0, st1[1].wMonth);
495     expect(0, st1[1].wDay);
496     expect(0, st1[1].wDayOfWeek);
497     expect(0, st1[1].wHour);
498     expect(0, st1[1].wMinute);
499     expect(0, st1[1].wSecond);
500     expect(0, st1[1].wMilliseconds);
501
502     DestroyWindow(hwnd);
503 }
504
505 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
506 {
507     static LONG defwndproc_counter = 0;
508     LRESULT ret;
509     struct message msg;
510
511     /* log system messages, except for painting */
512     if (message < WM_USER &&
513         message != WM_PAINT &&
514         message != WM_ERASEBKGND &&
515         message != WM_NCPAINT &&
516         message != WM_NCHITTEST &&
517         message != WM_GETTEXT &&
518         message != WM_GETICON &&
519         message != WM_DEVICECHANGE)
520     {
521         trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
522
523         msg.message = message;
524         msg.flags = sent|wparam|lparam;
525         if (defwndproc_counter) msg.flags |= defwinproc;
526         msg.wParam = wParam;
527         msg.lParam = lParam;
528         add_message(sequences, PARENT_SEQ_INDEX, &msg);
529     }
530
531     defwndproc_counter++;
532     ret = DefWindowProcA(hwnd, message, wParam, lParam);
533     defwndproc_counter--;
534
535     return ret;
536 }
537
538 static BOOL register_parent_wnd_class(void)
539 {
540     WNDCLASSA cls;
541
542     cls.style = 0;
543     cls.lpfnWndProc = parent_wnd_proc;
544     cls.cbClsExtra = 0;
545     cls.cbWndExtra = 0;
546     cls.hInstance = GetModuleHandleA(NULL);
547     cls.hIcon = 0;
548     cls.hCursor = LoadCursorA(0, IDC_ARROW);
549     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
550     cls.lpszMenuName = NULL;
551     cls.lpszClassName = "Month-Cal test parent class";
552     return RegisterClassA(&cls);
553 }
554
555 static HWND create_parent_window(void)
556 {
557     HWND hwnd;
558
559     InitCommonControls();
560
561     /* flush message sequences, so we can check the new sequence by the end of function */
562     flush_sequences(sequences, NUM_MSG_SEQUENCES);
563
564     if (!register_parent_wnd_class())
565         return NULL;
566
567     hwnd = CreateWindowEx(0, "Month-Cal test parent class",
568                           "Month-Cal test parent window",
569                           WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
570                           WS_MAXIMIZEBOX | WS_VISIBLE,
571                           0, 0, 500, 500,
572                           GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
573
574     assert(hwnd);
575
576     /* check for message sequences */
577     ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_window_seq, "create parent window", FALSE);
578
579     return hwnd;
580 }
581
582 static LRESULT WINAPI monthcal_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
583 {
584     struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
585     static LONG defwndproc_counter = 0;
586     LRESULT ret;
587     struct message msg;
588
589     msg.message = message;
590     msg.flags = sent|wparam|lparam;
591     if (defwndproc_counter) msg.flags |= defwinproc;
592     msg.wParam = wParam;
593     msg.lParam = lParam;
594     add_message(sequences, MONTHCAL_SEQ_INDEX, &msg);
595
596     /* some debug output for style changing */
597     if ((message == WM_STYLECHANGING ||
598          message == WM_STYLECHANGED) && lParam)
599     {
600         STYLESTRUCT *style = (STYLESTRUCT*)lParam;
601         trace("\told style: 0x%08x, new style: 0x%08x\n", style->styleOld, style->styleNew);
602     }
603
604     defwndproc_counter++;
605     ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
606     defwndproc_counter--;
607
608     return ret;
609 }
610
611 static HWND create_monthcal_control(DWORD style)
612 {
613     struct subclass_info *info;
614     HWND hwnd;
615
616     info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
617     if (!info)
618         return NULL;
619
620     hwnd = CreateWindowEx(0,
621                     MONTHCAL_CLASS,
622                     "",
623                     WS_CHILD | WS_BORDER | WS_VISIBLE | style,
624                     0, 0, 300, 400,
625                     parent_wnd, NULL, GetModuleHandleA(NULL), NULL);
626
627     if (!hwnd)
628     {
629         HeapFree(GetProcessHeap(), 0, info);
630         return NULL;
631     }
632
633     info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
634                                             (LONG_PTR)monthcal_subclass_proc);
635     SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
636
637     SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0);
638
639     return hwnd;
640 }
641
642
643 /* Setter and Getters Tests */
644
645 static void test_monthcal_color(void)
646 {
647     int res, temp;
648     HWND hwnd;
649
650     hwnd = create_monthcal_control(0);
651
652     flush_sequences(sequences, NUM_MSG_SEQUENCES);
653
654     /* Setter and Getters for color*/
655     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0);
656     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_BACKGROUND, RGB(0,0,0));
657     expect(temp, res);
658     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0);
659     expect(RGB(0,0,0), temp);
660     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_BACKGROUND, RGB(255,255,255));
661     expect(temp, res);
662     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0);
663     expect(RGB(255,255,255), temp);
664
665     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0);
666     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_MONTHBK, RGB(0,0,0));
667     expect(temp, res);
668     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0);
669     expect(RGB(0,0,0), temp);
670     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_MONTHBK, RGB(255,255,255));
671     expect(temp, res);
672     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0);
673     expect(RGB(255,255,255), temp);
674
675     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0);
676     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TEXT, RGB(0,0,0));
677     expect(temp, res);
678     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0);
679     expect(RGB(0,0,0), temp);
680     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TEXT, RGB(255,255,255));
681     expect(temp, res);
682     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0);
683     expect(RGB(255,255,255), temp);
684
685     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0);
686     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLEBK, RGB(0,0,0));
687     expect(temp, res);
688     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0);
689     expect(RGB(0,0,0), temp);
690     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLEBK, RGB(255,255,255));
691     expect(temp, res);
692     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0);
693     expect(RGB(255,255,255), temp);
694
695     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0);
696     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLETEXT, RGB(0,0,0));
697     expect(temp, res);
698     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0);
699     expect(RGB(0,0,0), temp);
700     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLETEXT, RGB(255,255,255));
701     expect(temp, res);
702     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0);
703     expect(RGB(255,255,255), temp);
704
705     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0);
706     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TRAILINGTEXT, RGB(0,0,0));
707     expect(temp, res);
708     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0);
709     expect(RGB(0,0,0), temp);
710     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TRAILINGTEXT, RGB(255,255,255));
711     expect(temp, res);
712     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0);
713     expect(RGB(255,255,255), temp);
714
715     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_color_seq, "monthcal color", FALSE);
716
717     DestroyWindow(hwnd);
718 }
719
720 static void test_monthcal_currdate(void)
721 {
722     SYSTEMTIME st_original, st_new, st_test;
723     int res;
724     HWND hwnd;
725
726     hwnd = create_monthcal_control(0);
727
728     flush_sequences(sequences, NUM_MSG_SEQUENCES);
729
730     /* Setter and Getters for current date selected */
731     st_original.wYear = 2000;
732     st_original.wMonth = 11;
733     st_original.wDay = 28;
734     st_original.wHour = 11;
735     st_original.wMinute = 59;
736     st_original.wSecond = 30;
737     st_original.wMilliseconds = 0;
738     st_original.wDayOfWeek = 0;
739
740     st_new = st_test = st_original;
741
742     /* Should not validate the time */
743     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test);
744     expect(1,res);
745
746     /* Overflow matters, check for wDay */
747     st_test.wDay += 4;
748     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test);
749     expect(0,res);
750
751     /* correct wDay before checking for wMonth */
752     st_test.wDay -= 4;
753     expect(st_original.wDay, st_test.wDay);
754
755     /* Overflow matters, check for wMonth */
756     st_test.wMonth += 4;
757     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test);
758     expect(0,res);
759
760     /* checking if gets the information right, modify st_new */
761     st_new.wYear += 4;
762     st_new.wMonth += 4;
763     st_new.wDay += 4;
764     st_new.wHour += 4;
765     st_new.wMinute += 4;
766     st_new.wSecond += 4;
767
768     res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_new);
769     expect(1, res);
770
771     /* st_new change to st_origin, above settings with overflow */
772     /* should not change the current settings */
773     expect(st_original.wYear, st_new.wYear);
774     expect(st_original.wMonth, st_new.wMonth);
775     expect(st_original.wDay, st_new.wDay);
776     ok(st_original.wHour == st_new.wHour ||
777        broken(0 == st_new.wHour), /* comctl32 <= 4.70 */
778        "Expected %d, got %d\n", st_original.wHour, st_new.wHour);
779     ok(st_original.wMinute == st_new.wMinute ||
780        broken(0 == st_new.wMinute), /* comctl32 <= 4.70 */
781        "Expected %d, got %d\n", st_original.wMinute, st_new.wMinute);
782     ok(st_original.wSecond == st_new.wSecond ||
783        broken(0 == st_new.wSecond), /* comctl32 <= 4.70 */
784        "Expected %d, got %d\n", st_original.wSecond, st_new.wSecond);
785
786     /* lparam cannot be NULL */
787     res = SendMessage(hwnd, MCM_GETCURSEL, 0, 0);
788     expect(0, res);
789
790     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_curr_date_seq, "monthcal currDate", TRUE);
791
792     /* December, 31, 9999 is the maximum allowed date */
793     memset(&st_new, 0, sizeof(st_new));
794     st_new.wYear = 9999;
795     st_new.wMonth = 12;
796     st_new.wDay = 31;
797     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_new);
798     expect(1, res);
799     memset(&st_test, 0, sizeof(st_test));
800     res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_test);
801     expect(1, res);
802     expect(st_new.wYear, st_test.wYear);
803     expect(st_new.wMonth, st_test.wMonth);
804     expect(st_new.wDay, st_test.wDay);
805     expect(st_new.wHour, st_test.wHour);
806     expect(st_new.wMinute, st_test.wMinute);
807     expect(st_new.wSecond, st_test.wSecond);
808     /* try one day later */
809     st_original = st_new;
810     st_new.wYear = 10000;
811     st_new.wMonth = 1;
812     st_new.wDay = 1;
813     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_new);
814     ok(0 == res ||
815        broken(1 == res), /* comctl32 <= 4.72 */
816        "Expected 0, got %d\n", res);
817     if (0 == res)
818     {
819         memset(&st_test, 0, sizeof(st_test));
820         res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_test);
821         expect(1, res);
822         expect(st_original.wYear, st_test.wYear);
823         expect(st_original.wMonth, st_test.wMonth);
824         expect(st_original.wDay, st_test.wDay);
825         expect(st_original.wHour, st_test.wHour);
826         expect(st_original.wMinute, st_test.wMinute);
827         expect(st_original.wSecond, st_test.wSecond);
828     }
829
830     /* setting selection equal to current reports success even if out range */
831     memset(&st_new, 0, sizeof(st_new));
832     st_new.wYear = 2009;
833     st_new.wDay  = 5;
834     st_new.wMonth = 10;
835     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_new);
836     expect(1, res);
837     memset(&st_test, 0, sizeof(st_test));
838     st_test.wYear = 2009;
839     st_test.wDay  = 6;
840     st_test.wMonth = 10;
841     res = SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN, (LPARAM)&st_test);
842     expect(1, res);
843     /* set to current again */
844     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_new);
845     expect(1, res);
846
847     DestroyWindow(hwnd);
848 }
849
850 static void test_monthcal_firstDay(void)
851 {
852     int res, fday, i, prev;
853     CHAR b[128];
854     LCID lcid = LOCALE_USER_DEFAULT;
855     HWND hwnd;
856
857     hwnd = create_monthcal_control(0);
858
859     flush_sequences(sequences, NUM_MSG_SEQUENCES);
860
861     /* Setter and Getters for first day of week */
862     /* check for locale first day */
863     if(GetLocaleInfoA(lcid, LOCALE_IFIRSTDAYOFWEEK, b, 128)){
864         fday = atoi(b);
865         trace("fday: %d\n", fday);
866         res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0);
867         expect(fday, res);
868         prev = fday;
869
870         /* checking for the values that actually will be stored as */
871         /* current first day when we set a new value */
872         for (i = -5; i < 12; i++){
873             res = SendMessage(hwnd, MCM_SETFIRSTDAYOFWEEK, 0, (LPARAM) i);
874             expect(prev, res);
875             res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0);
876             prev = res;
877
878             if (i == -1){
879                 expect(MAKELONG(fday, FALSE), res);
880             }else if (i >= 7){
881                 /* out of range sets max first day of week, locale is ignored */
882                 expect(MAKELONG(6, TRUE), res);
883             }else{
884                 expect(MAKELONG(i, TRUE), res);
885             }
886         }
887
888         ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_first_day_seq, "monthcal firstDay", FALSE);
889
890     }else{
891         skip("Cannot retrieve first day of the week\n");
892     }
893
894     DestroyWindow(hwnd);
895 }
896
897 static void test_monthcal_unicode(void)
898 {
899     int res, temp;
900     HWND hwnd;
901
902     hwnd = create_monthcal_control(0);
903
904     flush_sequences(sequences, NUM_MSG_SEQUENCES);
905
906     /* Setter and Getters for Unicode format */
907
908     /* getting the current settings */
909     temp = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
910
911     /* setting to 1, should return previous settings */
912     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 1, 0);
913     expect(temp, res);
914
915     /* current setting is 1, so, should return 1 */
916     res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
917     todo_wine
918     ok(1 == res ||
919        broken(0 == res), /* comctl32 <= 4.70 */
920        "Expected 1, got %d\n", res);
921
922     /* setting to 0, should return previous settings */
923     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 0, 0);
924     todo_wine
925     ok(1 == res ||
926        broken(0 == res), /* comctl32 <= 4.70 */
927        "Expected 1, got %d\n", res);
928
929     /* current setting is 0, so, it should return 0 */
930     res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
931     expect(0, res);
932
933     /* should return previous settings */
934     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 1, 0);
935     expect(0, res);
936
937     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_unicode_seq, "monthcal unicode", FALSE);
938
939     DestroyWindow(hwnd);
940 }
941
942 static void test_monthcal_hittest(void)
943 {
944     typedef struct hittest_test
945     {
946         UINT ht;
947         int  todo;
948     } hittest_test_t;
949
950     static const hittest_test_t title_hits[] = {
951         /* Start is the same everywhere */
952         { MCHT_TITLE,        0 },
953         { MCHT_TITLEBTNPREV, 0 },
954         /* The middle piece is only tested for presence of items */
955         /* End is the same everywhere */
956         { MCHT_TITLEBTNNEXT, 0 },
957         { MCHT_TITLE,        0 },
958         { MCHT_NOWHERE,      1 }
959     };
960
961     MCHITTESTINFO mchit;
962     UINT res, old_res;
963     SYSTEMTIME st;
964     LONG x;
965     UINT title_index;
966     HWND hwnd;
967     RECT r;
968     char yearmonth[80], *locale_month, *locale_year;
969     int month_count, year_count;
970     BOOL in_the_middle;
971
972     memset(&mchit, 0, sizeof(MCHITTESTINFO));
973
974     hwnd = create_monthcal_control(0);
975
976     /* test with invalid structure size */
977     mchit.cbSize = MCHITTESTINFO_V1_SIZE - 1;
978     mchit.pt.x = 0;
979     mchit.pt.y = 0;
980     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM)&mchit);
981     expect(0, mchit.pt.x);
982     expect(0, mchit.pt.y);
983     expect(-1, res);
984     expect(0, mchit.uHit);
985     /* test with invalid pointer */
986     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM)NULL);
987     expect(-1, res);
988
989     /* resize control to display single Calendar */
990     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r);
991     if (res == 0)
992     {
993         win_skip("Message MCM_GETMINREQRECT unsupported. Skipping.\n");
994         DestroyWindow(hwnd);
995         return;
996     }
997     MoveWindow(hwnd, 0, 0, r.right, r.bottom, FALSE);
998
999     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1000
1001     st.wYear = 2007;
1002     st.wMonth = 4;
1003     st.wDay = 11;
1004     st.wHour = 1;
1005     st.wMinute = 0;
1006     st.wSecond = 0;
1007     st.wMilliseconds = 0;
1008     st.wDayOfWeek = 0;
1009
1010     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st);
1011     expect(1,res);
1012
1013     /* (0, 0) is the top left of the control - title */
1014     mchit.cbSize = MCHITTESTINFO_V1_SIZE;
1015     mchit.pt.x = 0;
1016     mchit.pt.y = 0;
1017     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM)&mchit);
1018     expect(0, mchit.pt.x);
1019     expect(0, mchit.pt.y);
1020     expect(mchit.uHit, res);
1021     expect_hex(MCHT_TITLE, res);
1022
1023     /* bottom right of the control and should not be active */
1024     mchit.pt.x = r.right;
1025     mchit.pt.y = r.bottom;
1026     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM)&mchit);
1027     expect(r.right,  mchit.pt.x);
1028     expect(r.bottom, mchit.pt.y);
1029     expect(mchit.uHit, res);
1030     todo_wine expect_hex(MCHT_NOWHERE, res);
1031
1032     /* completely out of the control, should not be active */
1033     mchit.pt.x = 2 * r.right;
1034     mchit.pt.y = 2 * r.bottom;
1035     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1036     expect(2 * r.right, mchit.pt.x);
1037     expect(2 * r.bottom, mchit.pt.y);
1038     expect(mchit.uHit, res);
1039     todo_wine expect_hex(MCHT_NOWHERE, res);
1040
1041     /* in active area - day of the week */
1042     mchit.pt.x = r.right / 2;
1043     mchit.pt.y = r.bottom / 2;
1044     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1045     expect(r.right / 2, mchit.pt.x);
1046     expect(r.bottom / 2, mchit.pt.y);
1047     expect(mchit.uHit, res);
1048     expect_hex(MCHT_CALENDARDATE, res);
1049
1050     /* in active area - day of the week #2 */
1051     mchit.pt.x = r.right / 14; /* half of first day rect */
1052     mchit.pt.y = r.bottom / 2;
1053     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1054     expect(r.right / 14, mchit.pt.x);
1055     expect(r.bottom / 2, mchit.pt.y);
1056     expect(mchit.uHit, res);
1057     expect_hex(MCHT_CALENDARDATE, res);
1058
1059     /* in active area - date from prev month */
1060     mchit.pt.x = r.right / 14; /* half of first day rect */
1061     mchit.pt.y = 6 * r.bottom / 19;
1062     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1063     expect(r.right / 14, mchit.pt.x);
1064     expect(6 * r.bottom / 19, mchit.pt.y);
1065     expect(mchit.uHit, res);
1066     expect_hex(MCHT_CALENDARDATEPREV, res);
1067
1068 #if 0
1069     /* (125, 115) is in active area - date from this month */
1070     mchit.pt.x = 125;
1071     mchit.pt.y = 115;
1072     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1073     expect(125, mchit.pt.x);
1074     expect(115, mchit.pt.y);
1075     expect(mchit.uHit, res);
1076     expect(MCHT_CALENDARDATE, res);
1077 #endif
1078
1079     /* in active area - date from next month */
1080     mchit.pt.x = 11 * r.right / 14;
1081     mchit.pt.y = 16 * r.bottom / 19;
1082     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1083     expect(11 * r.right / 14, mchit.pt.x);
1084     expect(16 * r.bottom / 19, mchit.pt.y);
1085     expect(mchit.uHit, res);
1086     expect_hex(MCHT_CALENDARDATENEXT, res);
1087
1088     /* in active area - today link */
1089     mchit.pt.x = r.right / 14;
1090     mchit.pt.y = 18 * r.bottom / 19;
1091     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1092     expect(r.right / 14, mchit.pt.x);
1093     expect(18 * r.bottom / 19, mchit.pt.y);
1094     expect(mchit.uHit, res);
1095     expect_hex(MCHT_TODAYLINK, res);
1096
1097     /* in active area - today link */
1098     mchit.pt.x = r.right / 2;
1099     mchit.pt.y = 18 * r.bottom / 19;
1100     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1101     expect(r.right / 2, mchit.pt.x);
1102     expect(18 * r.bottom / 19, mchit.pt.y);
1103     expect(mchit.uHit, res);
1104     expect_hex(MCHT_TODAYLINK, res);
1105
1106     /* in active area - today link */
1107     mchit.pt.x = r.right / 10;
1108     mchit.pt.y = 18 * r.bottom / 19;
1109     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1110     expect(r.right / 10, mchit.pt.x);
1111     expect(18 * r.bottom / 19, mchit.pt.y);
1112     expect(mchit.uHit, res);
1113     expect_hex(MCHT_TODAYLINK, res);
1114
1115     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_hit_test_seq, "monthcal hit test", TRUE);
1116
1117     /* The horizontal position of title bar elements depends on locale (y pos
1118        is constant), so we sample across a horizontal line and make sure we
1119        find all elements. */
1120
1121     /* Get the format of the title */
1122     GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SYEARMONTH, yearmonth, 80);
1123     /* Find out if we have a month and/or year */
1124     locale_year = strstr(yearmonth, "y");
1125     locale_month = strstr(yearmonth, "M");
1126
1127     mchit.pt.x = 0;
1128     mchit.pt.y = (5/2) * r.bottom / 19;
1129     title_index = 0;
1130     old_res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1131     expect_hex(title_hits[title_index].ht, old_res);
1132
1133     in_the_middle = FALSE;
1134     month_count = year_count = 0;
1135     for (x = 0; x < r.right; x++){
1136         mchit.pt.x = x;
1137         res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1138         expect(x, mchit.pt.x);
1139         expect((5/2) * r.bottom / 19, mchit.pt.y);
1140         expect(mchit.uHit, res);
1141         if (res != old_res) {
1142
1143             if (old_res == MCHT_TITLEBTNPREV)
1144                 in_the_middle = TRUE;
1145
1146             if (res == MCHT_TITLEBTNNEXT)
1147                 in_the_middle = FALSE;
1148
1149             if (in_the_middle) {
1150                 if (res == MCHT_TITLEMONTH)
1151                     month_count++;
1152                 else if (res == MCHT_TITLEYEAR)
1153                     year_count++;
1154             } else {
1155                 title_index++;
1156
1157                 if (sizeof(title_hits) / sizeof(title_hits[0]) <= title_index)
1158                     break;
1159
1160                 if (title_hits[title_index].todo) {
1161                     todo_wine
1162                     ok(title_hits[title_index].ht == res, "Expected %x, got %x, pos %d\n",
1163                                                           title_hits[title_index].ht, res, x);
1164                 } else {
1165                     ok(title_hits[title_index].ht == res, "Expected %x, got %x, pos %d\n",
1166                                                           title_hits[title_index].ht, res, x);
1167                 }
1168             }
1169             old_res = res;
1170         }
1171     }
1172
1173     /* There are some limits, even if LOCALE_SYEARMONTH contains rubbish
1174      * or no month/year indicators at all */
1175     if (locale_month)
1176         todo_wine ok(month_count == 1, "Expected 1 month item, got %d\n", month_count);
1177     else
1178         ok(month_count <= 1, "Too many month items: %d\n", month_count);
1179
1180     if (locale_year)
1181         todo_wine ok(year_count == 1, "Expected 1 year item, got %d\n", year_count);
1182     else
1183         ok(year_count <= 1, "Too many year items: %d\n", year_count);
1184
1185     todo_wine ok(month_count + year_count >= 1, "Not enough month and year items\n");
1186
1187     ok(r.right <= x && title_index + 1 == sizeof(title_hits) / sizeof(title_hits[0]),
1188        "Wrong title layout\n");
1189
1190     DestroyWindow(hwnd);
1191 }
1192
1193 static void test_monthcal_todaylink(void)
1194 {
1195     MCHITTESTINFO mchit;
1196     SYSTEMTIME st_test, st_new;
1197     BOOL error = FALSE;
1198     UINT res;
1199     HWND hwnd;
1200
1201     memset(&mchit, 0, sizeof(MCHITTESTINFO));
1202
1203     hwnd = create_monthcal_control(0);
1204
1205     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1206
1207     /* (70, 370) is in active area - today link */
1208     mchit.cbSize = MCHITTESTINFO_V1_SIZE;
1209     mchit.pt.x = 70;
1210     mchit.pt.y = 370;
1211     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1212     expect(70, mchit.pt.x);
1213     expect(370, mchit.pt.y);
1214     expect(mchit.uHit, res);
1215     todo_wine {expect(MCHT_TODAYLINK, res);}
1216     if (70 != mchit.pt.x || 370 != mchit.pt.y || mchit.uHit != res
1217         || MCHT_TODAYLINK != res)
1218         error = TRUE;
1219
1220     st_test.wDay = 1;
1221     st_test.wMonth = 1;
1222     st_test.wYear = 2005;
1223     memset(&st_new, 0, sizeof(SYSTEMTIME));
1224
1225     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
1226
1227     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
1228     expect(1, res);
1229     expect(1, st_new.wDay);
1230     expect(1, st_new.wMonth);
1231     expect(2005, st_new.wYear);
1232     if (1 != res || 1 != st_new.wDay || 1 != st_new.wMonth
1233         || 2005 != st_new.wYear)
1234         error = TRUE;
1235
1236     if (error) {
1237         skip("cannot perform today link test\n");
1238         return;
1239     }
1240
1241     res = SendMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELONG(70, 370));
1242     expect(0, res);
1243
1244     memset(&st_new, 0, sizeof(SYSTEMTIME));
1245     res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_new);
1246     expect(1, res);
1247     expect(1, st_new.wDay);
1248     expect(1, st_new.wMonth);
1249     expect(2005, st_new.wYear);
1250
1251     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_todaylink_seq, "monthcal hit test", TRUE);
1252
1253     DestroyWindow(hwnd);
1254 }
1255
1256 static void test_monthcal_today(void)
1257 {
1258     SYSTEMTIME st_test, st_new;
1259     int res;
1260     HWND hwnd;
1261
1262     hwnd = create_monthcal_control(0);
1263
1264     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1265
1266     /* Setter and Getters for "today" information */
1267
1268     /* check for overflow, should be ok */
1269     st_test.wDay = 38;
1270     st_test.wMonth = 38;
1271
1272     st_new.wDay = 27;
1273     st_new.wMonth = 27;
1274
1275     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
1276
1277     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
1278     expect(1, res);
1279
1280     /* st_test should not change */
1281     expect(38, st_test.wDay);
1282     expect(38, st_test.wMonth);
1283
1284     /* st_new should change, overflow does not matter */
1285     expect(38, st_new.wDay);
1286     expect(38, st_new.wMonth);
1287
1288     /* check for zero, should be ok*/
1289     st_test.wDay = 0;
1290     st_test.wMonth = 0;
1291
1292     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
1293
1294     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
1295     expect(1, res);
1296
1297     /* st_test should not change */
1298     expect(0, st_test.wDay);
1299     expect(0, st_test.wMonth);
1300
1301     /* st_new should change to zero*/
1302     expect(0, st_new.wDay);
1303     expect(0, st_new.wMonth);
1304
1305     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_today_seq, "monthcal today", TRUE);
1306
1307     DestroyWindow(hwnd);
1308 }
1309
1310 static void test_monthcal_scroll(void)
1311 {
1312     int res;
1313     HWND hwnd;
1314
1315     hwnd = create_monthcal_control(0);
1316
1317     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1318
1319     /* Setter and Getters for scroll rate */
1320     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 2, 0);
1321     expect(0, res);
1322
1323     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 3, 0);
1324     expect(2, res);
1325     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1326     expect(3, res);
1327
1328     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 12, 0);
1329     expect(3, res);
1330     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1331     expect(12, res);
1332
1333     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 15, 0);
1334     expect(12, res);
1335     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1336     expect(15, res);
1337
1338     res = SendMessage(hwnd, MCM_SETMONTHDELTA, -5, 0);
1339     expect(15, res);
1340     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1341     expect(-5, res);
1342
1343     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_scroll_seq, "monthcal scroll", FALSE);
1344
1345     DestroyWindow(hwnd);
1346 }
1347
1348 static void test_monthcal_monthrange(void)
1349 {
1350     int res;
1351     SYSTEMTIME st_visible[2], st_daystate[2], st;
1352     HWND hwnd;
1353
1354     hwnd = create_monthcal_control(0);
1355
1356     st_visible[0].wYear = 0;
1357     st_visible[0].wMonth = 0;
1358     st_visible[0].wDay = 0;
1359     st_daystate[1] = st_daystate[0] = st_visible[1] = st_visible[0];
1360
1361     st.wYear = 2000;
1362     st.wMonth = 11;
1363     st.wDay = 28;
1364     st.wHour = 11;
1365     st.wMinute = 59;
1366     st.wSecond = 30;
1367     st.wMilliseconds = 0;
1368     st.wDayOfWeek = 0;
1369
1370     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st);
1371     expect(1,res);
1372
1373     /* to be locale independent */
1374     SendMessage(hwnd, MCM_SETFIRSTDAYOFWEEK, 0, (LPARAM)6);
1375
1376     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1377
1378     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st_visible);
1379     todo_wine {
1380         expect(2, res);
1381     }
1382     expect(2000, st_visible[0].wYear);
1383     expect(11, st_visible[0].wMonth);
1384     expect(1, st_visible[0].wDay);
1385     expect(2000, st_visible[1].wYear);
1386
1387     todo_wine {
1388         expect(12, st_visible[1].wMonth);
1389         expect(31, st_visible[1].wDay);
1390     }
1391     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_DAYSTATE, (LPARAM)st_daystate);
1392     todo_wine {
1393         expect(4, res);
1394     }
1395     expect(2000, st_daystate[0].wYear);
1396     expect(10, st_daystate[0].wMonth);
1397     expect(29, st_daystate[0].wDay);
1398
1399     todo_wine {
1400         expect(2001, st_daystate[1].wYear);
1401         expect(1, st_daystate[1].wMonth);
1402         expect(6, st_daystate[1].wDay);
1403     }
1404
1405     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_monthrange_seq, "monthcal monthrange", FALSE);
1406
1407     DestroyWindow(hwnd);
1408 }
1409
1410 static void test_monthcal_maxselday(void)
1411 {
1412     int res;
1413     HWND hwnd;
1414     DWORD style;
1415
1416     hwnd = create_monthcal_control(0);
1417     /* if no style specified default to 1 */
1418     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1419     expect(1, res);
1420     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 5, 0);
1421     expect(0, res);
1422     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1423     expect(1, res);
1424
1425     /* try to set style */
1426     style = GetWindowLong(hwnd, GWL_STYLE);
1427     SetWindowLong(hwnd, GWL_STYLE, style | MCS_MULTISELECT);
1428     style = GetWindowLong(hwnd, GWL_STYLE);
1429     ok(!(style & MCS_MULTISELECT), "Expected MCS_MULTISELECT not to be set\n");
1430     DestroyWindow(hwnd);
1431
1432     hwnd = create_monthcal_control(MCS_MULTISELECT);
1433     /* try to remove style */
1434     style = GetWindowLong(hwnd, GWL_STYLE);
1435     SetWindowLong(hwnd, GWL_STYLE, style & ~MCS_MULTISELECT);
1436     style = GetWindowLong(hwnd, GWL_STYLE);
1437     ok(style & MCS_MULTISELECT, "Expected MCS_MULTISELECT to be set\n");
1438     DestroyWindow(hwnd);
1439
1440     hwnd = create_monthcal_control(MCS_MULTISELECT);
1441
1442     /* default width is a week */
1443     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1444     expect(7, res);
1445
1446     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1447
1448     /* Setter and Getters for max selected days */
1449     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 5, 0);
1450     expect(1, res);
1451     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1452     expect(5, res);
1453
1454     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 15, 0);
1455     expect(1, res);
1456     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1457     expect(15, res);
1458
1459     /* test invalid value */
1460     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, -1, 0);
1461     expect(0, res);
1462     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1463     expect(15, res);
1464
1465     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_max_sel_day_seq, "monthcal MaxSelDay", FALSE);
1466
1467     /* zero value is invalid too */
1468     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 0, 0);
1469     expect(0, res);
1470     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1471     expect(15, res);
1472
1473     DestroyWindow(hwnd);
1474 }
1475
1476 static void test_monthcal_size(void)
1477 {
1478     int res;
1479     RECT r1, r2;
1480     HFONT hFont1, hFont2;
1481     LOGFONTA logfont;
1482     HWND hwnd;
1483
1484     hwnd = create_monthcal_control(0);
1485
1486     lstrcpyA(logfont.lfFaceName, "Arial");
1487     memset(&logfont, 0, sizeof(logfont));
1488     logfont.lfHeight = 12;
1489     hFont1 = CreateFontIndirectA(&logfont);
1490
1491     logfont.lfHeight = 24;
1492     hFont2 = CreateFontIndirectA(&logfont);
1493
1494     /* initialize to a font we can compare against */
1495     SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont1, 0);
1496     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r1);
1497
1498     /* check that setting a larger font results in an larger rect */
1499     SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont2, 0);
1500     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r2);
1501
1502     OffsetRect(&r1, -r1.left, -r1.top);
1503     OffsetRect(&r2, -r2.left, -r2.top);
1504
1505     ok(r1.bottom < r2.bottom, "Failed to get larger rect with larger font\n");
1506
1507     DestroyWindow(hwnd);
1508 }
1509
1510 static void test_monthcal_create(void)
1511 {
1512     HWND hwnd;
1513
1514     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1515
1516     hwnd = create_monthcal_control(0);
1517     ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_control_seq, "create monthcal control", TRUE);
1518
1519     DestroyWindow(hwnd);
1520
1521     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1522     hwnd = create_monthcal_control(MCS_MULTISELECT);
1523     ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_multi_sel_style_seq, "create monthcal (multi sel style)", TRUE);
1524     DestroyWindow(hwnd);
1525 }
1526
1527 static void test_monthcal_destroy(void)
1528 {
1529     HWND hwnd;
1530
1531     hwnd = create_monthcal_control(0);
1532     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1533     DestroyWindow(hwnd);
1534     ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_monthcal_parent_msgs_seq, "Destroy monthcal (parent msg)", FALSE);
1535     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_child_msgs_seq, "Destroy monthcal (child msg)", FALSE);
1536
1537     /* MCS_MULTISELECT */
1538     hwnd = create_monthcal_control(MCS_MULTISELECT);
1539     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1540     DestroyWindow(hwnd);
1541     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_multi_sel_style_seq, "Destroy monthcal (multi sel style)", FALSE);
1542 }
1543
1544 static void test_monthcal_selrange(void)
1545 {
1546     HWND hwnd;
1547     SYSTEMTIME st, range[2], range2[2];
1548     BOOL ret, old_comctl32 = FALSE;
1549
1550     hwnd = create_monthcal_control(MCS_MULTISELECT);
1551
1552     /* just after creation selection should start and end today */
1553     ret = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st);
1554     expect(TRUE, ret);
1555
1556     memset(range, 0xcc, sizeof(range));
1557     ret = SendMessage(hwnd, MCM_GETSELRANGE, 0, (LPARAM)range);
1558     expect(TRUE, ret);
1559     expect(st.wYear,      range[0].wYear);
1560     expect(st.wMonth,     range[0].wMonth);
1561     expect(st.wDay,       range[0].wDay);
1562     if (range[0].wDayOfWeek == 0)
1563     {
1564         win_skip("comctl32 <= 4.70 doesn't set some values\n");
1565         old_comctl32 = TRUE;
1566     }
1567     else
1568     {
1569          expect(st.wDayOfWeek, range[0].wDayOfWeek);
1570          expect(st.wHour,      range[0].wHour);
1571          expect(st.wMinute,    range[0].wMinute);
1572          expect(st.wSecond,    range[0].wSecond);
1573          expect(st.wMilliseconds, range[0].wMilliseconds);
1574     }
1575
1576     expect(st.wYear,      range[1].wYear);
1577     expect(st.wMonth,     range[1].wMonth);
1578     expect(st.wDay,       range[1].wDay);
1579     if (!old_comctl32)
1580     {
1581         expect(st.wDayOfWeek, range[1].wDayOfWeek);
1582         expect(st.wHour,      range[1].wHour);
1583         expect(st.wMinute,    range[1].wMinute);
1584         expect(st.wSecond,    range[1].wSecond);
1585         expect(st.wMilliseconds, range[1].wMilliseconds);
1586     }
1587
1588     /* bounds are swapped if min > max */
1589     memset(&range[0], 0, sizeof(range[0]));
1590     range[0].wYear  = 2009;
1591     range[0].wMonth = 10;
1592     range[0].wDay   = 5;
1593     range[1] = range[0];
1594     range[1].wDay   = 3;
1595
1596     ret = SendMessage(hwnd, MCM_SETSELRANGE, 0, (LPARAM)range);
1597     expect(TRUE, ret);
1598
1599     ret = SendMessage(hwnd, MCM_GETSELRANGE, 0, (LPARAM)range2);
1600     expect(TRUE, ret);
1601
1602     expect(range[1].wYear,      range2[0].wYear);
1603     expect(range[1].wMonth,     range2[0].wMonth);
1604     expect(range[1].wDay,       range2[0].wDay);
1605     expect(6, range2[0].wDayOfWeek);
1606     expect(range[1].wHour,      range2[0].wHour);
1607     expect(range[1].wMinute,    range2[0].wMinute);
1608     expect(range[1].wSecond,    range2[0].wSecond);
1609     expect(range[1].wMilliseconds, range2[0].wMilliseconds);
1610
1611     expect(range[0].wYear,      range2[1].wYear);
1612     expect(range[0].wMonth,     range2[1].wMonth);
1613     expect(range[0].wDay,       range2[1].wDay);
1614     expect(1, range2[1].wDayOfWeek);
1615     expect(range[0].wHour,      range2[1].wHour);
1616     expect(range[0].wMinute,    range2[1].wMinute);
1617     expect(range[0].wSecond,    range2[1].wSecond);
1618     expect(range[0].wMilliseconds, range2[1].wMilliseconds);
1619
1620     /* try with range larger than maximum configured */
1621     memset(&range[0], 0, sizeof(range[0]));
1622     range[0].wYear  = 2009;
1623     range[0].wMonth = 10;
1624     range[0].wDay   = 1;
1625     range[1] = range[0];
1626
1627     ret = SendMessage(hwnd, MCM_SETSELRANGE, 0, (LPARAM)range);
1628     expect(TRUE, ret);
1629
1630     range[1] = range[0];
1631     /* default max. range is 7 days */
1632     range[1].wDay = 8;
1633
1634     ret = SendMessage(hwnd, MCM_SETSELRANGE, 0, (LPARAM)range);
1635     expect(FALSE, ret);
1636
1637     ret = SendMessage(hwnd, MCM_GETSELRANGE, 0, (LPARAM)range2);
1638     expect(TRUE, ret);
1639
1640     expect(range[0].wYear,  range2[0].wYear);
1641     expect(range[0].wMonth, range2[0].wMonth);
1642     expect(range[0].wDay,   range2[0].wDay);
1643     expect(range[0].wYear,  range2[1].wYear);
1644     expect(range[0].wMonth, range2[1].wMonth);
1645     expect(range[0].wDay,   range2[1].wDay);
1646
1647     DestroyWindow(hwnd);
1648 }
1649
1650 START_TEST(monthcal)
1651 {
1652     HMODULE hComctl32;
1653     BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
1654     INITCOMMONCONTROLSEX iccex;
1655
1656     hComctl32 = GetModuleHandleA("comctl32.dll");
1657     pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
1658     if (!pInitCommonControlsEx)
1659     {
1660         skip("InitCommonControlsEx() is missing. Skipping the tests\n");
1661         return;
1662     }
1663     iccex.dwSize = sizeof(iccex);
1664     iccex.dwICC  = ICC_DATE_CLASSES;
1665     pInitCommonControlsEx(&iccex);
1666
1667     test_monthcal();
1668
1669     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1670
1671     parent_wnd = create_parent_window();
1672
1673     test_monthcal_create();
1674     test_monthcal_destroy();
1675     test_monthcal_color();
1676     test_monthcal_currdate();
1677     test_monthcal_firstDay();
1678     test_monthcal_unicode();
1679     test_monthcal_today();
1680     test_monthcal_scroll();
1681     test_monthcal_monthrange();
1682     test_monthcal_hittest();
1683     test_monthcal_todaylink();
1684     test_monthcal_size();
1685     test_monthcal_maxselday();
1686     test_monthcal_selrange();
1687
1688     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1689     DestroyWindow(parent_wnd);
1690     ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_parent_seq, "Destroy parent window", FALSE);
1691 }