comctl32/tooltips: Remove redundant code, let handlers deal with A<->W conversions.
[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     todo_wine
905     ok(1 == res ||
906        broken(0 == res), /* comctl32 <= 4.70 */
907        "Expected 1, got %d\n", res);
908
909     /* setting to 0, should return previous settings */
910     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 0, 0);
911     todo_wine
912     ok(1 == res ||
913        broken(0 == res), /* comctl32 <= 4.70 */
914        "Expected 1, got %d\n", res);
915
916     /* current setting is 0, so, it should return 0 */
917     res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
918     expect(0, res);
919
920     /* should return previous settings */
921     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 1, 0);
922     expect(0, res);
923
924     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_unicode_seq, "monthcal unicode", FALSE);
925
926     DestroyWindow(hwnd);
927 }
928
929 static void test_monthcal_hittest(void)
930 {
931     typedef struct hittest_test
932     {
933         UINT ht;
934         int  todo;
935     } hittest_test_t;
936
937     static const hittest_test_t title_hits[] = {
938         /* Start is the same everywhere */
939         { MCHT_TITLE,        0 },
940         { MCHT_TITLEBTNPREV, 0 },
941         /* The middle piece is only tested for presence of items */
942         /* End is the same everywhere */
943         { MCHT_TITLEBTNNEXT, 0 },
944         { MCHT_TITLE,        0 },
945         { MCHT_NOWHERE,      1 }
946     };
947
948     MCHITTESTINFO mchit;
949     UINT res, old_res;
950     SYSTEMTIME st;
951     LONG x;
952     UINT title_index;
953     HWND hwnd;
954     RECT r;
955     char yearmonth[80], *locale_month, *locale_year;
956     int month_count, year_count;
957     BOOL in_the_middle;
958
959     memset(&mchit, 0, sizeof(MCHITTESTINFO));
960
961     hwnd = create_monthcal_control(0);
962
963     /* test with invalid structure size */
964     mchit.cbSize = MCHITTESTINFO_V1_SIZE - 1;
965     mchit.pt.x = 0;
966     mchit.pt.y = 0;
967     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM)&mchit);
968     expect(0, mchit.pt.x);
969     expect(0, mchit.pt.y);
970     expect(-1, res);
971     expect(0, mchit.uHit);
972     /* test with invalid pointer */
973     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM)NULL);
974     expect(-1, res);
975
976     /* resize control to display single Calendar */
977     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r);
978     if (res == 0)
979     {
980         win_skip("Message MCM_GETMINREQRECT unsupported. Skipping.\n");
981         DestroyWindow(hwnd);
982         return;
983     }
984     MoveWindow(hwnd, 0, 0, r.right, r.bottom, FALSE);
985
986     flush_sequences(sequences, NUM_MSG_SEQUENCES);
987
988     st.wYear = 2007;
989     st.wMonth = 4;
990     st.wDay = 11;
991     st.wHour = 1;
992     st.wMinute = 0;
993     st.wSecond = 0;
994     st.wMilliseconds = 0;
995     st.wDayOfWeek = 0;
996
997     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st);
998     expect(1,res);
999
1000     /* (0, 0) is the top left of the control - title */
1001     mchit.cbSize = MCHITTESTINFO_V1_SIZE;
1002     mchit.pt.x = 0;
1003     mchit.pt.y = 0;
1004     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM)&mchit);
1005     expect(0, mchit.pt.x);
1006     expect(0, mchit.pt.y);
1007     expect(mchit.uHit, res);
1008     expect_hex(MCHT_TITLE, res);
1009
1010     /* bottom right of the control and should not be active */
1011     mchit.pt.x = r.right;
1012     mchit.pt.y = r.bottom;
1013     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM)&mchit);
1014     expect(r.right,  mchit.pt.x);
1015     expect(r.bottom, mchit.pt.y);
1016     expect(mchit.uHit, res);
1017     todo_wine expect_hex(MCHT_NOWHERE, res);
1018
1019     /* completely out of the control, should not be active */
1020     mchit.pt.x = 2 * r.right;
1021     mchit.pt.y = 2 * r.bottom;
1022     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1023     expect(2 * r.right, mchit.pt.x);
1024     expect(2 * r.bottom, mchit.pt.y);
1025     expect(mchit.uHit, res);
1026     todo_wine expect_hex(MCHT_NOWHERE, res);
1027
1028     /* in active area - day of the week */
1029     mchit.pt.x = r.right / 2;
1030     mchit.pt.y = r.bottom / 2;
1031     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1032     expect(r.right / 2, mchit.pt.x);
1033     expect(r.bottom / 2, mchit.pt.y);
1034     expect(mchit.uHit, res);
1035     expect_hex(MCHT_CALENDARDATE, res);
1036
1037     /* in active area - day of the week #2 */
1038     mchit.pt.x = r.right / 14; /* half of first day rect */
1039     mchit.pt.y = r.bottom / 2;
1040     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1041     expect(r.right / 14, mchit.pt.x);
1042     expect(r.bottom / 2, mchit.pt.y);
1043     expect(mchit.uHit, res);
1044     expect_hex(MCHT_CALENDARDATE, res);
1045
1046     /* in active area - date from prev month */
1047     mchit.pt.x = r.right / 14; /* half of first day rect */
1048     mchit.pt.y = 6 * r.bottom / 19;
1049     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1050     expect(r.right / 14, mchit.pt.x);
1051     expect(6 * r.bottom / 19, mchit.pt.y);
1052     expect(mchit.uHit, res);
1053     expect_hex(MCHT_CALENDARDATEPREV, res);
1054
1055 #if 0
1056     /* (125, 115) is in active area - date from this month */
1057     mchit.pt.x = 125;
1058     mchit.pt.y = 115;
1059     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1060     expect(125, mchit.pt.x);
1061     expect(115, mchit.pt.y);
1062     expect(mchit.uHit, res);
1063     expect(MCHT_CALENDARDATE, res);
1064 #endif
1065
1066     /* in active area - date from next month */
1067     mchit.pt.x = 11 * r.right / 14;
1068     mchit.pt.y = 16 * r.bottom / 19;
1069     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1070     expect(11 * r.right / 14, mchit.pt.x);
1071     expect(16 * r.bottom / 19, mchit.pt.y);
1072     expect(mchit.uHit, res);
1073     expect_hex(MCHT_CALENDARDATENEXT, res);
1074
1075     /* in active area - today link */
1076     mchit.pt.x = r.right / 14;
1077     mchit.pt.y = 18 * r.bottom / 19;
1078     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1079     expect(r.right / 14, mchit.pt.x);
1080     expect(18 * r.bottom / 19, mchit.pt.y);
1081     expect(mchit.uHit, res);
1082     expect_hex(MCHT_TODAYLINK, res);
1083
1084     /* in active area - today link */
1085     mchit.pt.x = r.right / 2;
1086     mchit.pt.y = 18 * r.bottom / 19;
1087     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1088     expect(r.right / 2, mchit.pt.x);
1089     expect(18 * r.bottom / 19, mchit.pt.y);
1090     expect(mchit.uHit, res);
1091     expect_hex(MCHT_TODAYLINK, res);
1092
1093     /* in active area - today link */
1094     mchit.pt.x = r.right / 10;
1095     mchit.pt.y = 18 * r.bottom / 19;
1096     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1097     expect(r.right / 10, mchit.pt.x);
1098     expect(18 * r.bottom / 19, mchit.pt.y);
1099     expect(mchit.uHit, res);
1100     expect_hex(MCHT_TODAYLINK, res);
1101
1102     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_hit_test_seq, "monthcal hit test", TRUE);
1103
1104     /* The horizontal position of title bar elements depends on locale (y pos
1105        is constant), so we sample across a horizontal line and make sure we
1106        find all elements. */
1107
1108     /* Get the format of the title */
1109     GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SYEARMONTH, yearmonth, 80);
1110     /* Find out if we have a month and/or year */
1111     locale_year = strstr(yearmonth, "y");
1112     locale_month = strstr(yearmonth, "M");
1113
1114     mchit.pt.x = 0;
1115     mchit.pt.y = (5/2) * r.bottom / 19;
1116     title_index = 0;
1117     old_res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1118     expect_hex(title_hits[title_index].ht, old_res);
1119
1120     in_the_middle = FALSE;
1121     month_count = year_count = 0;
1122     for (x = 0; x < r.right; x++){
1123         mchit.pt.x = x;
1124         res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1125         expect(x, mchit.pt.x);
1126         expect((5/2) * r.bottom / 19, mchit.pt.y);
1127         expect(mchit.uHit, res);
1128         if (res != old_res) {
1129
1130             if (old_res == MCHT_TITLEBTNPREV)
1131                 in_the_middle = TRUE;
1132
1133             if (res == MCHT_TITLEBTNNEXT)
1134                 in_the_middle = FALSE;
1135
1136             if (in_the_middle) {
1137                 if (res == MCHT_TITLEMONTH)
1138                     month_count++;
1139                 else if (res == MCHT_TITLEYEAR)
1140                     year_count++;
1141             } else {
1142                 title_index++;
1143
1144                 if (sizeof(title_hits) / sizeof(title_hits[0]) <= title_index)
1145                     break;
1146
1147                 if (title_hits[title_index].todo) {
1148                     todo_wine
1149                     ok(title_hits[title_index].ht == res, "Expected %x, got %x, pos %d\n",
1150                                                           title_hits[title_index].ht, res, x);
1151                 } else {
1152                     ok(title_hits[title_index].ht == res, "Expected %x, got %x, pos %d\n",
1153                                                           title_hits[title_index].ht, res, x);
1154                 }
1155             }
1156             old_res = res;
1157         }
1158     }
1159
1160     /* There are some limits, even if LOCALE_SYEARMONTH contains rubbish
1161      * or no month/year indicators at all */
1162     if (locale_month)
1163         todo_wine ok(month_count == 1, "Expected 1 month item, got %d\n", month_count);
1164     else
1165         ok(month_count <= 1, "Too many month items: %d\n", month_count);
1166
1167     if (locale_year)
1168         todo_wine ok(year_count == 1, "Expected 1 year item, got %d\n", year_count);
1169     else
1170         ok(year_count <= 1, "Too many year items: %d\n", year_count);
1171
1172     todo_wine ok(month_count + year_count >= 1, "Not enough month and year items\n");
1173
1174     ok(r.right <= x && title_index + 1 == sizeof(title_hits) / sizeof(title_hits[0]),
1175        "Wrong title layout\n");
1176
1177     DestroyWindow(hwnd);
1178 }
1179
1180 static void test_monthcal_todaylink(void)
1181 {
1182     MCHITTESTINFO mchit;
1183     SYSTEMTIME st_test, st_new;
1184     UINT res;
1185     HWND hwnd;
1186     RECT r;
1187
1188     memset(&mchit, 0, sizeof(MCHITTESTINFO));
1189
1190     hwnd = create_monthcal_control(0);
1191
1192     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r);
1193     MoveWindow(hwnd, 0, 0, r.right, r.bottom, FALSE);
1194
1195     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1196
1197     /* hit active area - today link */
1198     mchit.cbSize = MCHITTESTINFO_V1_SIZE;
1199     mchit.pt.x = r.right / 14;
1200     mchit.pt.y = 18 * r.bottom / 19;
1201     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1202     expect(r.right / 14, mchit.pt.x);
1203     expect(18 * r.bottom / 19, mchit.pt.y);
1204     expect(mchit.uHit, res);
1205     expect(MCHT_TODAYLINK, res);
1206
1207     st_test.wDay = 1;
1208     st_test.wMonth = 1;
1209     st_test.wYear = 2005;
1210
1211     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
1212
1213     memset(&st_new, 0, sizeof(st_new));
1214     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
1215     expect(1, res);
1216     expect(1, st_new.wDay);
1217     expect(1, st_new.wMonth);
1218     expect(2005, st_new.wYear);
1219
1220     res = SendMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELONG(mchit.pt.x, mchit.pt.y));
1221     expect(0, res);
1222
1223     memset(&st_new, 0, sizeof(st_new));
1224     res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_new);
1225     expect(1, res);
1226     expect(1, st_new.wDay);
1227     expect(1, st_new.wMonth);
1228     expect(2005, st_new.wYear);
1229
1230     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_todaylink_seq, "monthcal hit test", TRUE);
1231
1232     DestroyWindow(hwnd);
1233 }
1234
1235 static void test_monthcal_today(void)
1236 {
1237     SYSTEMTIME st_test, st_new;
1238     int res;
1239     HWND hwnd;
1240
1241     hwnd = create_monthcal_control(0);
1242
1243     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1244
1245     /* Setter and Getters for "today" information */
1246
1247     /* check for overflow, should be ok */
1248     st_test.wDay = 38;
1249     st_test.wMonth = 38;
1250
1251     st_new.wDay = 27;
1252     st_new.wMonth = 27;
1253
1254     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
1255
1256     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
1257     expect(1, res);
1258
1259     /* st_test should not change */
1260     expect(38, st_test.wDay);
1261     expect(38, st_test.wMonth);
1262
1263     /* st_new should change, overflow does not matter */
1264     expect(38, st_new.wDay);
1265     expect(38, st_new.wMonth);
1266
1267     /* check for zero, should be ok*/
1268     st_test.wDay = 0;
1269     st_test.wMonth = 0;
1270
1271     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
1272
1273     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
1274     expect(1, res);
1275
1276     /* st_test should not change */
1277     expect(0, st_test.wDay);
1278     expect(0, st_test.wMonth);
1279
1280     /* st_new should change to zero*/
1281     expect(0, st_new.wDay);
1282     expect(0, st_new.wMonth);
1283
1284     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_today_seq, "monthcal today", TRUE);
1285
1286     DestroyWindow(hwnd);
1287 }
1288
1289 static void test_monthcal_scroll(void)
1290 {
1291     int res;
1292     HWND hwnd;
1293
1294     hwnd = create_monthcal_control(0);
1295
1296     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1297
1298     /* Setter and Getters for scroll rate */
1299     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 2, 0);
1300     expect(0, res);
1301
1302     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 3, 0);
1303     expect(2, res);
1304     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1305     expect(3, res);
1306
1307     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 12, 0);
1308     expect(3, res);
1309     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1310     expect(12, res);
1311
1312     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 15, 0);
1313     expect(12, res);
1314     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1315     expect(15, res);
1316
1317     res = SendMessage(hwnd, MCM_SETMONTHDELTA, -5, 0);
1318     expect(15, res);
1319     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1320     expect(-5, res);
1321
1322     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_scroll_seq, "monthcal scroll", FALSE);
1323
1324     DestroyWindow(hwnd);
1325 }
1326
1327 static void test_monthcal_monthrange(void)
1328 {
1329     int res;
1330     SYSTEMTIME st_visible[2], st_daystate[2], st;
1331     HWND hwnd;
1332     RECT r;
1333
1334     hwnd = create_monthcal_control(0);
1335
1336     st_visible[0].wYear = 0;
1337     st_visible[0].wMonth = 0;
1338     st_visible[0].wDay = 0;
1339     st_daystate[1] = st_daystate[0] = st_visible[1] = st_visible[0];
1340
1341     st.wYear = 2000;
1342     st.wMonth = 11;
1343     st.wDay = 28;
1344     st.wHour = 11;
1345     st.wMinute = 59;
1346     st.wSecond = 30;
1347     st.wMilliseconds = 0;
1348     st.wDayOfWeek = 0;
1349
1350     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st);
1351     expect(1,res);
1352
1353     /* to be locale independent */
1354     SendMessage(hwnd, MCM_SETFIRSTDAYOFWEEK, 0, (LPARAM)6);
1355
1356     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1357
1358     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st_visible);
1359     todo_wine {
1360         expect(2, res);
1361     }
1362     expect(2000, st_visible[0].wYear);
1363     expect(11, st_visible[0].wMonth);
1364     expect(1, st_visible[0].wDay);
1365     expect(2000, st_visible[1].wYear);
1366
1367     todo_wine {
1368         expect(12, st_visible[1].wMonth);
1369         expect(31, st_visible[1].wDay);
1370     }
1371     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_DAYSTATE, (LPARAM)st_daystate);
1372     todo_wine {
1373         expect(4, res);
1374     }
1375     expect(2000, st_daystate[0].wYear);
1376     expect(10, st_daystate[0].wMonth);
1377     expect(29, st_daystate[0].wDay);
1378
1379     todo_wine {
1380         expect(2001, st_daystate[1].wYear);
1381         expect(1, st_daystate[1].wMonth);
1382         expect(6, st_daystate[1].wDay);
1383     }
1384
1385     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_monthrange_seq, "monthcal monthrange", FALSE);
1386
1387     /* resize control to display single Calendar */
1388     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r);
1389     MoveWindow(hwnd, 0, 0, r.right, r.bottom, FALSE);
1390
1391     memset(&st, 0, sizeof(st));
1392     st.wMonth = 9;
1393     st.wYear  = 1752;
1394     st.wDay   = 14;
1395
1396     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st);
1397     expect(1, res);
1398
1399     /* September 1752 has 19 days */
1400     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st_visible);
1401     expect(1, res);
1402
1403     expect(1752, st_visible[0].wYear);
1404     expect(9, st_visible[0].wMonth);
1405     ok(14 == st_visible[0].wDay ||
1406        broken(1 == st_visible[0].wDay), /* comctl32 <= 4.72 */
1407        "Expected 14, got %d\n", st_visible[0].wDay);
1408
1409     expect(1752, st_visible[1].wYear);
1410     expect(9, st_visible[1].wMonth);
1411     expect(19, st_visible[1].wDay);
1412
1413     DestroyWindow(hwnd);
1414 }
1415
1416 static void test_monthcal_maxselday(void)
1417 {
1418     int res;
1419     HWND hwnd;
1420     DWORD style;
1421
1422     hwnd = create_monthcal_control(0);
1423     /* if no style specified default to 1 */
1424     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1425     expect(1, res);
1426     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 5, 0);
1427     expect(0, res);
1428     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1429     expect(1, res);
1430
1431     /* try to set style */
1432     style = GetWindowLong(hwnd, GWL_STYLE);
1433     SetWindowLong(hwnd, GWL_STYLE, style | MCS_MULTISELECT);
1434     style = GetWindowLong(hwnd, GWL_STYLE);
1435     ok(!(style & MCS_MULTISELECT), "Expected MCS_MULTISELECT not to be set\n");
1436     DestroyWindow(hwnd);
1437
1438     hwnd = create_monthcal_control(MCS_MULTISELECT);
1439     /* try to remove style */
1440     style = GetWindowLong(hwnd, GWL_STYLE);
1441     SetWindowLong(hwnd, GWL_STYLE, style & ~MCS_MULTISELECT);
1442     style = GetWindowLong(hwnd, GWL_STYLE);
1443     ok(style & MCS_MULTISELECT, "Expected MCS_MULTISELECT to be set\n");
1444     DestroyWindow(hwnd);
1445
1446     hwnd = create_monthcal_control(MCS_MULTISELECT);
1447
1448     /* default width is a week */
1449     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1450     expect(7, res);
1451
1452     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1453
1454     /* Setter and Getters for max selected days */
1455     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 5, 0);
1456     expect(1, res);
1457     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1458     expect(5, res);
1459
1460     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 15, 0);
1461     expect(1, res);
1462     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1463     expect(15, res);
1464
1465     /* test invalid value */
1466     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, -1, 0);
1467     expect(0, res);
1468     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1469     expect(15, res);
1470
1471     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_max_sel_day_seq, "monthcal MaxSelDay", FALSE);
1472
1473     /* zero value is invalid too */
1474     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 0, 0);
1475     expect(0, res);
1476     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1477     expect(15, res);
1478
1479     DestroyWindow(hwnd);
1480 }
1481
1482 static void test_monthcal_size(void)
1483 {
1484     int res;
1485     RECT r1, r2;
1486     HFONT hFont1, hFont2;
1487     LOGFONTA logfont;
1488     HWND hwnd;
1489
1490     hwnd = create_monthcal_control(0);
1491
1492     lstrcpyA(logfont.lfFaceName, "Arial");
1493     memset(&logfont, 0, sizeof(logfont));
1494     logfont.lfHeight = 12;
1495     hFont1 = CreateFontIndirectA(&logfont);
1496
1497     logfont.lfHeight = 24;
1498     hFont2 = CreateFontIndirectA(&logfont);
1499
1500     /* initialize to a font we can compare against */
1501     SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont1, 0);
1502     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r1);
1503
1504     /* check that setting a larger font results in an larger rect */
1505     SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont2, 0);
1506     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r2);
1507
1508     OffsetRect(&r1, -r1.left, -r1.top);
1509     OffsetRect(&r2, -r2.left, -r2.top);
1510
1511     ok(r1.bottom < r2.bottom, "Failed to get larger rect with larger font\n");
1512
1513     DestroyWindow(hwnd);
1514 }
1515
1516 static void test_monthcal_create(void)
1517 {
1518     HWND hwnd;
1519
1520     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1521
1522     hwnd = create_monthcal_control(0);
1523     ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_control_seq, "create monthcal control", TRUE);
1524
1525     DestroyWindow(hwnd);
1526
1527     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1528     hwnd = create_monthcal_control(MCS_MULTISELECT);
1529     ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_multi_sel_style_seq, "create monthcal (multi sel style)", TRUE);
1530     DestroyWindow(hwnd);
1531 }
1532
1533 static void test_monthcal_destroy(void)
1534 {
1535     HWND hwnd;
1536
1537     hwnd = create_monthcal_control(0);
1538     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1539     DestroyWindow(hwnd);
1540     ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_monthcal_parent_msgs_seq, "Destroy monthcal (parent msg)", FALSE);
1541     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_child_msgs_seq, "Destroy monthcal (child msg)", FALSE);
1542
1543     /* MCS_MULTISELECT */
1544     hwnd = create_monthcal_control(MCS_MULTISELECT);
1545     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1546     DestroyWindow(hwnd);
1547     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_multi_sel_style_seq, "Destroy monthcal (multi sel style)", FALSE);
1548 }
1549
1550 static void test_monthcal_selrange(void)
1551 {
1552     HWND hwnd;
1553     SYSTEMTIME st, range[2], range2[2];
1554     BOOL ret, old_comctl32 = FALSE;
1555
1556     hwnd = create_monthcal_control(MCS_MULTISELECT);
1557
1558     /* just after creation selection should start and end today */
1559     ret = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st);
1560     expect(TRUE, ret);
1561
1562     memset(range, 0xcc, sizeof(range));
1563     ret = SendMessage(hwnd, MCM_GETSELRANGE, 0, (LPARAM)range);
1564     expect(TRUE, ret);
1565     expect(st.wYear,      range[0].wYear);
1566     expect(st.wMonth,     range[0].wMonth);
1567     expect(st.wDay,       range[0].wDay);
1568     if (range[0].wDayOfWeek != st.wDayOfWeek)
1569     {
1570         win_skip("comctl32 <= 4.70 doesn't set some values\n");
1571         old_comctl32 = TRUE;
1572     }
1573     else
1574     {
1575         expect(st.wDayOfWeek, range[0].wDayOfWeek);
1576         expect(st.wHour,      range[0].wHour);
1577         expect(st.wMinute,    range[0].wMinute);
1578         expect(st.wSecond,    range[0].wSecond);
1579         expect(st.wMilliseconds, range[0].wMilliseconds);
1580     }
1581
1582     expect(st.wYear,      range[1].wYear);
1583     expect(st.wMonth,     range[1].wMonth);
1584     expect(st.wDay,       range[1].wDay);
1585     if (!old_comctl32)
1586     {
1587         expect(st.wDayOfWeek, range[1].wDayOfWeek);
1588         expect(st.wHour,      range[1].wHour);
1589         expect(st.wMinute,    range[1].wMinute);
1590         expect(st.wSecond,    range[1].wSecond);
1591         expect(st.wMilliseconds, range[1].wMilliseconds);
1592     }
1593
1594     /* bounds are swapped if min > max */
1595     memset(&range[0], 0, sizeof(range[0]));
1596     range[0].wYear  = 2009;
1597     range[0].wMonth = 10;
1598     range[0].wDay   = 5;
1599     range[1] = range[0];
1600     range[1].wDay   = 3;
1601
1602     ret = SendMessage(hwnd, MCM_SETSELRANGE, 0, (LPARAM)range);
1603     expect(TRUE, ret);
1604
1605     ret = SendMessage(hwnd, MCM_GETSELRANGE, 0, (LPARAM)range2);
1606     expect(TRUE, ret);
1607
1608     expect(range[1].wYear,      range2[0].wYear);
1609     expect(range[1].wMonth,     range2[0].wMonth);
1610     expect(range[1].wDay,       range2[0].wDay);
1611     expect(6, range2[0].wDayOfWeek);
1612     expect(range[1].wHour,      range2[0].wHour);
1613     expect(range[1].wMinute,    range2[0].wMinute);
1614     expect(range[1].wSecond,    range2[0].wSecond);
1615     expect(range[1].wMilliseconds, range2[0].wMilliseconds);
1616
1617     expect(range[0].wYear,      range2[1].wYear);
1618     expect(range[0].wMonth,     range2[1].wMonth);
1619     expect(range[0].wDay,       range2[1].wDay);
1620     expect(1, range2[1].wDayOfWeek);
1621     expect(range[0].wHour,      range2[1].wHour);
1622     expect(range[0].wMinute,    range2[1].wMinute);
1623     expect(range[0].wSecond,    range2[1].wSecond);
1624     expect(range[0].wMilliseconds, range2[1].wMilliseconds);
1625
1626     /* try with range larger than maximum configured */
1627     memset(&range[0], 0, sizeof(range[0]));
1628     range[0].wYear  = 2009;
1629     range[0].wMonth = 10;
1630     range[0].wDay   = 1;
1631     range[1] = range[0];
1632
1633     ret = SendMessage(hwnd, MCM_SETSELRANGE, 0, (LPARAM)range);
1634     expect(TRUE, ret);
1635
1636     range[1] = range[0];
1637     /* default max. range is 7 days */
1638     range[1].wDay = 8;
1639
1640     ret = SendMessage(hwnd, MCM_SETSELRANGE, 0, (LPARAM)range);
1641     expect(FALSE, ret);
1642
1643     ret = SendMessage(hwnd, MCM_GETSELRANGE, 0, (LPARAM)range2);
1644     expect(TRUE, ret);
1645
1646     expect(range[0].wYear,  range2[0].wYear);
1647     expect(range[0].wMonth, range2[0].wMonth);
1648     expect(range[0].wDay,   range2[0].wDay);
1649     expect(range[0].wYear,  range2[1].wYear);
1650     expect(range[0].wMonth, range2[1].wMonth);
1651     expect(range[0].wDay,   range2[1].wDay);
1652
1653     DestroyWindow(hwnd);
1654 }
1655
1656 static void test_killfocus(void)
1657 {
1658     HWND hwnd;
1659     DWORD style;
1660
1661     hwnd = create_monthcal_control(0);
1662
1663     /* make parent invisible */
1664     style = GetWindowLong(parent_wnd, GWL_STYLE);
1665     SetWindowLong(parent_wnd, GWL_STYLE, style &~ WS_VISIBLE);
1666
1667     SendMessage(hwnd, WM_KILLFOCUS, (WPARAM)GetDesktopWindow(), 0);
1668
1669     style = GetWindowLong(hwnd, GWL_STYLE);
1670     ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
1671
1672     style = GetWindowLong(parent_wnd, GWL_STYLE);
1673     SetWindowLong(parent_wnd, GWL_STYLE, style | WS_VISIBLE);
1674
1675     DestroyWindow(hwnd);
1676 }
1677
1678 START_TEST(monthcal)
1679 {
1680     HMODULE hComctl32;
1681     BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
1682     INITCOMMONCONTROLSEX iccex;
1683
1684     hComctl32 = GetModuleHandleA("comctl32.dll");
1685     pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
1686     if (!pInitCommonControlsEx)
1687     {
1688         skip("InitCommonControlsEx() is missing. Skipping the tests\n");
1689         return;
1690     }
1691     iccex.dwSize = sizeof(iccex);
1692     iccex.dwICC  = ICC_DATE_CLASSES;
1693     pInitCommonControlsEx(&iccex);
1694
1695     test_monthcal();
1696
1697     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1698
1699     parent_wnd = create_parent_window();
1700
1701     test_monthcal_create();
1702     test_monthcal_destroy();
1703     test_monthcal_color();
1704     test_monthcal_currdate();
1705     test_monthcal_firstDay();
1706     test_monthcal_unicode();
1707     test_monthcal_today();
1708     test_monthcal_scroll();
1709     test_monthcal_monthrange();
1710     test_monthcal_hittest();
1711     test_monthcal_todaylink();
1712     test_monthcal_size();
1713     test_monthcal_maxselday();
1714     test_monthcal_selrange();
1715     test_killfocus();
1716
1717     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1718     DestroyWindow(parent_wnd);
1719     ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_parent_seq, "Destroy parent window", FALSE);
1720 }