comctl32/listview: Free ID array when removing all items.
[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     st_test.wDay = 38;
1247     st_test.wMonth = 38;
1248
1249     st_new.wDay = 27;
1250     st_new.wMonth = 27;
1251
1252     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
1253
1254     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
1255     expect(1, res);
1256
1257     /* st_test should not change */
1258     expect(38, st_test.wDay);
1259     expect(38, st_test.wMonth);
1260
1261     /* st_new should change, overflow does not matter */
1262     expect(38, st_new.wDay);
1263     expect(38, st_new.wMonth);
1264
1265     /* check for zero, should be ok*/
1266     st_test.wDay = 0;
1267     st_test.wMonth = 0;
1268
1269     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
1270
1271     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
1272     expect(1, res);
1273
1274     /* st_test should not change */
1275     expect(0, st_test.wDay);
1276     expect(0, st_test.wMonth);
1277
1278     /* st_new should change to zero*/
1279     expect(0, st_new.wDay);
1280     expect(0, st_new.wMonth);
1281
1282     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_today_seq, "monthcal today", TRUE);
1283
1284     DestroyWindow(hwnd);
1285 }
1286
1287 static void test_monthcal_scroll(void)
1288 {
1289     int res;
1290     HWND hwnd;
1291
1292     hwnd = create_monthcal_control(0);
1293
1294     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1295
1296     /* Setter and Getters for scroll rate */
1297     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 2, 0);
1298     expect(0, res);
1299
1300     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 3, 0);
1301     expect(2, res);
1302     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1303     expect(3, res);
1304
1305     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 12, 0);
1306     expect(3, res);
1307     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1308     expect(12, res);
1309
1310     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 15, 0);
1311     expect(12, res);
1312     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1313     expect(15, res);
1314
1315     res = SendMessage(hwnd, MCM_SETMONTHDELTA, -5, 0);
1316     expect(15, res);
1317     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1318     expect(-5, res);
1319
1320     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_scroll_seq, "monthcal scroll", FALSE);
1321
1322     DestroyWindow(hwnd);
1323 }
1324
1325 static void test_monthcal_monthrange(void)
1326 {
1327     int res;
1328     SYSTEMTIME st_visible[2], st_daystate[2], st;
1329     HWND hwnd;
1330     RECT r;
1331
1332     hwnd = create_monthcal_control(0);
1333
1334     st_visible[0].wYear = 0;
1335     st_visible[0].wMonth = 0;
1336     st_visible[0].wDay = 0;
1337     st_daystate[1] = st_daystate[0] = st_visible[1] = st_visible[0];
1338
1339     st.wYear = 2000;
1340     st.wMonth = 11;
1341     st.wDay = 28;
1342     st.wHour = 11;
1343     st.wMinute = 59;
1344     st.wSecond = 30;
1345     st.wMilliseconds = 0;
1346     st.wDayOfWeek = 0;
1347
1348     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st);
1349     expect(1,res);
1350
1351     /* to be locale independent */
1352     SendMessage(hwnd, MCM_SETFIRSTDAYOFWEEK, 0, (LPARAM)6);
1353
1354     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r);
1355     expect(TRUE, res);
1356     /* resize control to display two Calendars */
1357     MoveWindow(hwnd, 0, 0, r.right, (5/2)*r.bottom, FALSE);
1358
1359     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1360
1361     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st_visible);
1362     todo_wine {
1363         expect(2, res);
1364     }
1365     expect(2000, st_visible[0].wYear);
1366     expect(11, st_visible[0].wMonth);
1367     expect(1, st_visible[0].wDay);
1368     expect(2000, st_visible[1].wYear);
1369
1370     todo_wine {
1371         expect(12, st_visible[1].wMonth);
1372         expect(31, st_visible[1].wDay);
1373     }
1374     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_DAYSTATE, (LPARAM)st_daystate);
1375     todo_wine {
1376         expect(4, res);
1377     }
1378     expect(2000, st_daystate[0].wYear);
1379     expect(10, st_daystate[0].wMonth);
1380     expect(29, st_daystate[0].wDay);
1381
1382     todo_wine {
1383         expect(2001, st_daystate[1].wYear);
1384         expect(1, st_daystate[1].wMonth);
1385         expect(6, st_daystate[1].wDay);
1386     }
1387
1388     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_monthrange_seq, "monthcal monthrange", FALSE);
1389
1390     /* resize control to display single Calendar */
1391     MoveWindow(hwnd, 0, 0, r.right, r.bottom, FALSE);
1392
1393     memset(&st, 0, sizeof(st));
1394     st.wMonth = 9;
1395     st.wYear  = 1752;
1396     st.wDay   = 14;
1397
1398     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st);
1399     expect(1, res);
1400
1401     /* September 1752 has 19 days */
1402     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st_visible);
1403     expect(1, res);
1404
1405     expect(1752, st_visible[0].wYear);
1406     expect(9, st_visible[0].wMonth);
1407     ok(14 == st_visible[0].wDay ||
1408        broken(1 == st_visible[0].wDay), /* comctl32 <= 4.72 */
1409        "Expected 14, got %d\n", st_visible[0].wDay);
1410
1411     expect(1752, st_visible[1].wYear);
1412     expect(9, st_visible[1].wMonth);
1413     expect(19, st_visible[1].wDay);
1414
1415     DestroyWindow(hwnd);
1416 }
1417
1418 static void test_monthcal_maxselday(void)
1419 {
1420     int res;
1421     HWND hwnd;
1422     DWORD style;
1423
1424     hwnd = create_monthcal_control(0);
1425     /* if no style specified default to 1 */
1426     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1427     expect(1, res);
1428     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 5, 0);
1429     expect(0, res);
1430     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1431     expect(1, res);
1432
1433     /* try to set 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 not to be set\n");
1438     DestroyWindow(hwnd);
1439
1440     hwnd = create_monthcal_control(MCS_MULTISELECT);
1441     /* try to remove style */
1442     style = GetWindowLong(hwnd, GWL_STYLE);
1443     SetWindowLong(hwnd, GWL_STYLE, style & ~MCS_MULTISELECT);
1444     style = GetWindowLong(hwnd, GWL_STYLE);
1445     ok(style & MCS_MULTISELECT, "Expected MCS_MULTISELECT to be set\n");
1446     DestroyWindow(hwnd);
1447
1448     hwnd = create_monthcal_control(MCS_MULTISELECT);
1449
1450     /* default width is a week */
1451     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1452     expect(7, res);
1453
1454     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1455
1456     /* Setter and Getters for max selected days */
1457     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 5, 0);
1458     expect(1, res);
1459     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1460     expect(5, res);
1461
1462     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 15, 0);
1463     expect(1, res);
1464     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1465     expect(15, res);
1466
1467     /* test invalid value */
1468     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, -1, 0);
1469     expect(0, res);
1470     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1471     expect(15, res);
1472
1473     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_max_sel_day_seq, "monthcal MaxSelDay", FALSE);
1474
1475     /* zero value is invalid too */
1476     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 0, 0);
1477     expect(0, res);
1478     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1479     expect(15, res);
1480
1481     DestroyWindow(hwnd);
1482 }
1483
1484 static void test_monthcal_size(void)
1485 {
1486     int res;
1487     RECT r1, r2;
1488     HFONT hFont1, hFont2;
1489     LOGFONTA logfont;
1490     HWND hwnd;
1491
1492     hwnd = create_monthcal_control(0);
1493
1494     lstrcpyA(logfont.lfFaceName, "Arial");
1495     memset(&logfont, 0, sizeof(logfont));
1496     logfont.lfHeight = 12;
1497     hFont1 = CreateFontIndirectA(&logfont);
1498
1499     logfont.lfHeight = 24;
1500     hFont2 = CreateFontIndirectA(&logfont);
1501
1502     /* initialize to a font we can compare against */
1503     SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont1, 0);
1504     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r1);
1505
1506     /* check that setting a larger font results in an larger rect */
1507     SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont2, 0);
1508     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r2);
1509
1510     OffsetRect(&r1, -r1.left, -r1.top);
1511     OffsetRect(&r2, -r2.left, -r2.top);
1512
1513     ok(r1.bottom < r2.bottom, "Failed to get larger rect with larger font\n");
1514
1515     DestroyWindow(hwnd);
1516 }
1517
1518 static void test_monthcal_create(void)
1519 {
1520     HWND hwnd;
1521
1522     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1523
1524     hwnd = create_monthcal_control(0);
1525     ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_control_seq, "create monthcal control", TRUE);
1526
1527     DestroyWindow(hwnd);
1528
1529     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1530     hwnd = create_monthcal_control(MCS_MULTISELECT);
1531     ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_multi_sel_style_seq, "create monthcal (multi sel style)", TRUE);
1532     DestroyWindow(hwnd);
1533 }
1534
1535 static void test_monthcal_destroy(void)
1536 {
1537     HWND hwnd;
1538
1539     hwnd = create_monthcal_control(0);
1540     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1541     DestroyWindow(hwnd);
1542     ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_monthcal_parent_msgs_seq, "Destroy monthcal (parent msg)", FALSE);
1543     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_child_msgs_seq, "Destroy monthcal (child msg)", FALSE);
1544
1545     /* MCS_MULTISELECT */
1546     hwnd = create_monthcal_control(MCS_MULTISELECT);
1547     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1548     DestroyWindow(hwnd);
1549     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_multi_sel_style_seq, "Destroy monthcal (multi sel style)", FALSE);
1550 }
1551
1552 static void test_monthcal_selrange(void)
1553 {
1554     HWND hwnd;
1555     SYSTEMTIME st, range[2], range2[2];
1556     BOOL ret, old_comctl32 = FALSE;
1557
1558     hwnd = create_monthcal_control(MCS_MULTISELECT);
1559
1560     /* just after creation selection should start and end today */
1561     ret = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st);
1562     expect(TRUE, ret);
1563
1564     memset(range, 0xcc, sizeof(range));
1565     ret = SendMessage(hwnd, MCM_GETSELRANGE, 0, (LPARAM)range);
1566     expect(TRUE, ret);
1567     expect(st.wYear,      range[0].wYear);
1568     expect(st.wMonth,     range[0].wMonth);
1569     expect(st.wDay,       range[0].wDay);
1570     if (range[0].wDayOfWeek != st.wDayOfWeek)
1571     {
1572         win_skip("comctl32 <= 4.70 doesn't set some values\n");
1573         old_comctl32 = TRUE;
1574     }
1575     else
1576     {
1577         expect(st.wDayOfWeek, range[0].wDayOfWeek);
1578         expect(st.wHour,      range[0].wHour);
1579         expect(st.wMinute,    range[0].wMinute);
1580         expect(st.wSecond,    range[0].wSecond);
1581         expect(st.wMilliseconds, range[0].wMilliseconds);
1582     }
1583
1584     expect(st.wYear,      range[1].wYear);
1585     expect(st.wMonth,     range[1].wMonth);
1586     expect(st.wDay,       range[1].wDay);
1587     if (!old_comctl32)
1588     {
1589         expect(st.wDayOfWeek, range[1].wDayOfWeek);
1590         expect(st.wHour,      range[1].wHour);
1591         expect(st.wMinute,    range[1].wMinute);
1592         expect(st.wSecond,    range[1].wSecond);
1593         expect(st.wMilliseconds, range[1].wMilliseconds);
1594     }
1595
1596     /* bounds are swapped if min > max */
1597     memset(&range[0], 0, sizeof(range[0]));
1598     range[0].wYear  = 2009;
1599     range[0].wMonth = 10;
1600     range[0].wDay   = 5;
1601     range[1] = range[0];
1602     range[1].wDay   = 3;
1603
1604     ret = SendMessage(hwnd, MCM_SETSELRANGE, 0, (LPARAM)range);
1605     expect(TRUE, ret);
1606
1607     ret = SendMessage(hwnd, MCM_GETSELRANGE, 0, (LPARAM)range2);
1608     expect(TRUE, ret);
1609
1610     expect(range[1].wYear,      range2[0].wYear);
1611     expect(range[1].wMonth,     range2[0].wMonth);
1612     expect(range[1].wDay,       range2[0].wDay);
1613     expect(6, range2[0].wDayOfWeek);
1614     expect(range[1].wHour,      range2[0].wHour);
1615     expect(range[1].wMinute,    range2[0].wMinute);
1616     expect(range[1].wSecond,    range2[0].wSecond);
1617     expect(range[1].wMilliseconds, range2[0].wMilliseconds);
1618
1619     expect(range[0].wYear,      range2[1].wYear);
1620     expect(range[0].wMonth,     range2[1].wMonth);
1621     expect(range[0].wDay,       range2[1].wDay);
1622     expect(1, range2[1].wDayOfWeek);
1623     expect(range[0].wHour,      range2[1].wHour);
1624     expect(range[0].wMinute,    range2[1].wMinute);
1625     expect(range[0].wSecond,    range2[1].wSecond);
1626     expect(range[0].wMilliseconds, range2[1].wMilliseconds);
1627
1628     /* try with range larger than maximum configured */
1629     memset(&range[0], 0, sizeof(range[0]));
1630     range[0].wYear  = 2009;
1631     range[0].wMonth = 10;
1632     range[0].wDay   = 1;
1633     range[1] = range[0];
1634
1635     ret = SendMessage(hwnd, MCM_SETSELRANGE, 0, (LPARAM)range);
1636     expect(TRUE, ret);
1637
1638     range[1] = range[0];
1639     /* default max. range is 7 days */
1640     range[1].wDay = 8;
1641
1642     ret = SendMessage(hwnd, MCM_SETSELRANGE, 0, (LPARAM)range);
1643     expect(FALSE, ret);
1644
1645     ret = SendMessage(hwnd, MCM_GETSELRANGE, 0, (LPARAM)range2);
1646     expect(TRUE, ret);
1647
1648     expect(range[0].wYear,  range2[0].wYear);
1649     expect(range[0].wMonth, range2[0].wMonth);
1650     expect(range[0].wDay,   range2[0].wDay);
1651     expect(range[0].wYear,  range2[1].wYear);
1652     expect(range[0].wMonth, range2[1].wMonth);
1653     expect(range[0].wDay,   range2[1].wDay);
1654
1655     DestroyWindow(hwnd);
1656 }
1657
1658 static void test_killfocus(void)
1659 {
1660     HWND hwnd;
1661     DWORD style;
1662
1663     hwnd = create_monthcal_control(0);
1664
1665     /* make parent invisible */
1666     style = GetWindowLong(parent_wnd, GWL_STYLE);
1667     SetWindowLong(parent_wnd, GWL_STYLE, style &~ WS_VISIBLE);
1668
1669     SendMessage(hwnd, WM_KILLFOCUS, (WPARAM)GetDesktopWindow(), 0);
1670
1671     style = GetWindowLong(hwnd, GWL_STYLE);
1672     ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
1673
1674     style = GetWindowLong(parent_wnd, GWL_STYLE);
1675     SetWindowLong(parent_wnd, GWL_STYLE, style | WS_VISIBLE);
1676
1677     DestroyWindow(hwnd);
1678 }
1679
1680 START_TEST(monthcal)
1681 {
1682     HMODULE hComctl32;
1683     BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
1684     INITCOMMONCONTROLSEX iccex;
1685
1686     hComctl32 = GetModuleHandleA("comctl32.dll");
1687     pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
1688     if (!pInitCommonControlsEx)
1689     {
1690         skip("InitCommonControlsEx() is missing. Skipping the tests\n");
1691         return;
1692     }
1693     iccex.dwSize = sizeof(iccex);
1694     iccex.dwICC  = ICC_DATE_CLASSES;
1695     pInitCommonControlsEx(&iccex);
1696
1697     test_monthcal();
1698
1699     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1700
1701     parent_wnd = create_parent_window();
1702
1703     test_monthcal_create();
1704     test_monthcal_destroy();
1705     test_monthcal_color();
1706     test_monthcal_currdate();
1707     test_monthcal_firstDay();
1708     test_monthcal_unicode();
1709     test_monthcal_today();
1710     test_monthcal_scroll();
1711     test_monthcal_monthrange();
1712     test_monthcal_hittest();
1713     test_monthcal_todaylink();
1714     test_monthcal_size();
1715     test_monthcal_maxselday();
1716     test_monthcal_selrange();
1717     test_killfocus();
1718
1719     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1720     DestroyWindow(parent_wnd);
1721     ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_parent_seq, "Destroy parent window", FALSE);
1722 }