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