winejoystick.drv: Use CP_UNIXCP instead of CP_ACP when converting a string that comes...
[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
37 #define NUM_MSG_SEQUENCES   2
38 #define PARENT_SEQ_INDEX    0
39 #define MONTHCAL_SEQ_INDEX  1
40
41 struct subclass_info
42 {
43     WNDPROC oldproc;
44 };
45
46 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
47
48 static const struct message create_parent_window_seq[] = {
49     { WM_GETMINMAXINFO, sent },
50     { WM_NCCREATE, sent },
51     { WM_NCCALCSIZE, sent|wparam, 0 },
52     { WM_CREATE, sent },
53     { WM_SHOWWINDOW, sent|wparam, 1 },
54     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
55     { WM_QUERYNEWPALETTE, sent|optional },
56     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
57     { WM_ACTIVATEAPP, sent|wparam, 1 },
58     { WM_NCACTIVATE, sent|wparam, 1 },
59     { WM_ACTIVATE, sent|wparam, 1 },
60     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
61     { WM_IME_NOTIFY, sent|defwinproc|optional },
62     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
63     /* Win9x adds SWP_NOZORDER below */
64     { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
65     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
66     { WM_SIZE, sent },
67     { WM_MOVE, sent },
68     { 0 }
69 };
70
71 static const struct message create_monthcal_control_seq[] = {
72     { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY },
73     { WM_QUERYUISTATE, sent|optional },
74     { WM_GETFONT, sent },
75     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE},
76     { 0 }
77 };
78
79 static const struct message create_monthcal_multi_sel_style_seq[] = {
80     { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY },
81     { WM_QUERYUISTATE, sent|optional },
82     { WM_GETFONT, 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     { WM_ERASEBKGND, sent|lparam|defwinproc, 0},
129     { MCM_SETCURSEL, sent|wparam, 0},
130     { MCM_SETCURSEL, sent|wparam, 0},
131     { MCM_GETCURSEL, sent|wparam, 0},
132     { MCM_GETCURSEL, sent|wparam|lparam, 0, 0},
133     { 0 }
134 };
135
136 static const struct message monthcal_first_day_seq[] = {
137     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
138
139     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -5},
140     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
141
142     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -4},
143     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
144
145     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -3},
146     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
147
148     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -2},
149     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
150
151     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -1},
152     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
153
154     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
155     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
156
157     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 1},
158     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
159
160     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 2},
161     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
162
163     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 3},
164     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
165
166     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 4},
167     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
168
169     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 5},
170     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
171
172     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 6},
173     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
174
175     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 7},
176     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
177
178     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 8},
179     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
180
181     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 9},
182     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
183
184     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 10},
185     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
186
187     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 11},
188     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
189     { 0 }
190 };
191
192 static const struct message monthcal_unicode_seq[] = {
193     { MCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0},
194     { MCM_SETUNICODEFORMAT, sent|wparam|lparam, 1, 0},
195     { MCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0},
196     { MCM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0},
197     { MCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0},
198     { MCM_SETUNICODEFORMAT, sent|wparam|lparam, 1, 0},
199     { 0 }
200 };
201
202 static const struct message monthcal_hit_test_seq[] = {
203     { MCM_SETCURSEL, sent|wparam, 0},
204     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 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     { MCM_HITTEST, sent|wparam, 0},
215     { MCM_HITTEST, sent|wparam, 0},
216     { MCM_HITTEST, sent|wparam, 0},
217     { MCM_HITTEST, sent|wparam, 0},
218     { 0 }
219 };
220
221 static const struct message monthcal_todaylink_seq[] = {
222     { MCM_HITTEST, sent|wparam, 0},
223     { MCM_SETTODAY, sent|wparam, 0},
224     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
225     { MCM_GETTODAY, sent|wparam, 0},
226     { WM_LBUTTONDOWN, sent|wparam|lparam, MK_LBUTTON, MAKELONG(70, 370)},
227     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0},
228     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
229     { MCM_GETCURSEL, sent|wparam, 0},
230     { 0 }
231 };
232
233 static const struct message monthcal_today_seq[] = {
234     { MCM_SETTODAY, sent|wparam, 0},
235     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
236     { MCM_GETTODAY, sent|wparam, 0},
237     { MCM_SETTODAY, sent|wparam, 0},
238     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
239     { MCM_GETTODAY, sent|wparam, 0},
240     { 0 }
241 };
242
243 static const struct message monthcal_scroll_seq[] = {
244     { MCM_SETMONTHDELTA, sent|wparam|lparam, 2, 0},
245     { MCM_SETMONTHDELTA, sent|wparam|lparam, 3, 0},
246     { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
247     { MCM_SETMONTHDELTA, sent|wparam|lparam, 12, 0},
248     { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
249     { MCM_SETMONTHDELTA, sent|wparam|lparam, 15, 0},
250     { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
251     { MCM_SETMONTHDELTA, sent|wparam|lparam, -5, 0},
252     { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
253     { 0 }
254 };
255
256 static const struct message monthcal_monthrange_seq[] = {
257     { MCM_GETMONTHRANGE, sent|wparam, GMR_VISIBLE},
258     { MCM_GETMONTHRANGE, sent|wparam, GMR_DAYSTATE},
259     { 0 }
260 };
261
262 static const struct message monthcal_max_sel_day_seq[] = {
263     { MCM_SETMAXSELCOUNT, sent|wparam|lparam, 5, 0},
264     { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0},
265     { MCM_SETMAXSELCOUNT, sent|wparam|lparam, 15, 0},
266     { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0},
267     { MCM_SETMAXSELCOUNT, sent|wparam|lparam, -1, 0},
268     { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0},
269     { 0 }
270 };
271
272 /* expected message sequence for parent*/
273 static const struct message destroy_monthcal_parent_msgs_seq[] = {
274     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY},
275     { 0 }
276 };
277
278 /* expected message sequence for child*/
279 static const struct message destroy_monthcal_child_msgs_seq[] = {
280     { 0x0090, sent|optional }, /* Vista */
281     { WM_SHOWWINDOW, sent|wparam|lparam, 0, 0},
282     { WM_WINDOWPOSCHANGING, sent|wparam, 0},
283     { WM_WINDOWPOSCHANGED, sent|wparam, 0},
284     { WM_DESTROY, sent|wparam|lparam, 0, 0},
285     { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
286     { 0 }
287 };
288
289 static const struct message destroy_monthcal_multi_sel_style_seq[] = {
290     { 0x0090, sent|optional }, /* Vista */
291     { WM_DESTROY, sent|wparam|lparam, 0, 0},
292     { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
293     { 0 }
294 };
295
296 /* expected message sequence for parent window*/
297 static const struct message destroy_parent_seq[] = {
298     { 0x0090, sent|optional }, /* Vista */
299     { WM_WINDOWPOSCHANGING, sent|wparam, 0},
300     { WM_WINDOWPOSCHANGED, sent|wparam, 0},
301     { WM_NCACTIVATE, sent|wparam, 0},
302     { WM_ACTIVATE, sent|wparam, 0},
303     { WM_NCACTIVATE, sent|wparam|lparam|optional, 0, 0},
304     { WM_ACTIVATE, sent|wparam|lparam|optional, 0, 0},
305     { WM_ACTIVATEAPP, sent|wparam, 0},
306     { WM_KILLFOCUS, sent|wparam|lparam, 0, 0},
307     { WM_IME_SETCONTEXT, sent|wparam|optional, 0},
308     { WM_IME_NOTIFY, sent|wparam|lparam|defwinproc|optional, 1, 0},
309     { WM_DESTROY, sent|wparam|lparam, 0, 0},
310     { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
311     { 0 }
312 };
313
314 static void test_monthcal(void)
315 {
316     HWND hwnd;
317     SYSTEMTIME st[2], st1[2];
318     int res, month_range;
319
320     hwnd = CreateWindowA(MONTHCAL_CLASSA, "MonthCal", WS_POPUP | WS_VISIBLE, CW_USEDEFAULT,
321                          0, 300, 300, 0, 0, NULL, NULL);
322     ok(hwnd != NULL, "Failed to create MonthCal\n");
323     GetSystemTime(&st[0]);
324     st[1] = st[0];
325
326     /* Invalid date/time */
327     st[0].wYear  = 2000;
328     /* Time should not matter */
329     st[1].wHour = st[1].wMinute = st[1].wSecond = 70;
330     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set MAX limit\n");
331     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
332     ok(st1[0].wYear != 2000, "Lover limit changed\n");
333
334     st[1].wMonth = 0;
335     ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Should have failed to set limits\n");
336     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
337     ok(st1[0].wYear != 2000, "Lover limit changed\n");
338     ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Should have failed to set MAX limit\n");
339     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
340     ok(st1[0].wYear != 2000, "Lover limit changed\n");
341
342     GetSystemTime(&st[0]);
343     st[0].wDay = 20;
344     st[0].wMonth = 5;
345     st[1] = st[0];
346
347     month_range = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
348     st[1].wMonth--;
349     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
350     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
351     ok(res == month_range, "Invalid month range (%d)\n", res);
352     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == (GDTR_MIN|GDTR_MAX), "Limits should be set\n");
353
354     st[1].wMonth += 2;
355     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
356     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
357     ok(res == month_range, "Invalid month range (%d)\n", res);
358
359     st[1].wYear --;
360     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
361     st[1].wYear += 1;
362     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
363
364     st[1].wMonth -= 3;
365     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
366     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "Only MAX limit should be set\n");
367     st[1].wMonth += 4;
368     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
369     st[1].wYear -= 3;
370     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
371     st[1].wYear += 4;
372     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
373     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "Only MAX limit should be set\n");
374
375     DestroyWindow(hwnd);
376 }
377
378 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
379 {
380     static long defwndproc_counter = 0;
381     LRESULT ret;
382     struct message msg;
383
384     /* log system messages, except for painting */
385     if (message < WM_USER &&
386         message != WM_PAINT &&
387         message != WM_ERASEBKGND &&
388         message != WM_NCPAINT &&
389         message != WM_NCHITTEST &&
390         message != WM_GETTEXT &&
391         message != WM_GETICON &&
392         message != WM_DEVICECHANGE)
393     {
394         trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
395
396         msg.message = message;
397         msg.flags = sent|wparam|lparam;
398         if (defwndproc_counter) msg.flags |= defwinproc;
399         msg.wParam = wParam;
400         msg.lParam = lParam;
401         add_message(sequences, PARENT_SEQ_INDEX, &msg);
402     }
403
404     defwndproc_counter++;
405     ret = DefWindowProcA(hwnd, message, wParam, lParam);
406     defwndproc_counter--;
407
408     return ret;
409 }
410
411 static BOOL register_parent_wnd_class(void)
412 {
413     WNDCLASSA cls;
414
415     cls.style = 0;
416     cls.lpfnWndProc = parent_wnd_proc;
417     cls.cbClsExtra = 0;
418     cls.cbWndExtra = 0;
419     cls.hInstance = GetModuleHandleA(NULL);
420     cls.hIcon = 0;
421     cls.hCursor = LoadCursorA(0, IDC_ARROW);
422     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
423     cls.lpszMenuName = NULL;
424     cls.lpszClassName = "Month-Cal test parent class";
425     return RegisterClassA(&cls);
426 }
427
428 static HWND create_parent_window(void)
429 {
430     HWND hwnd;
431
432     InitCommonControls();
433
434     /* flush message sequences, so we can check the new sequence by the end of function */
435     flush_sequences(sequences, NUM_MSG_SEQUENCES);
436
437     if (!register_parent_wnd_class())
438         return NULL;
439
440     hwnd = CreateWindowEx(0, "Month-Cal test parent class",
441                           "Month-Cal test parent window",
442                           WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
443                           WS_MAXIMIZEBOX | WS_VISIBLE,
444                           0, 0, 500, 500,
445                           GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
446
447     assert(hwnd);
448
449     /* check for message sequences */
450     ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_window_seq, "create parent window", TRUE);
451
452     return hwnd;
453 }
454
455 static LRESULT WINAPI monthcal_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
456 {
457     struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
458     static long defwndproc_counter = 0;
459     LRESULT ret;
460     struct message msg;
461
462     msg.message = message;
463     msg.flags = sent|wparam|lparam;
464     if (defwndproc_counter) msg.flags |= defwinproc;
465     msg.wParam = wParam;
466     msg.lParam = lParam;
467     add_message(sequences, MONTHCAL_SEQ_INDEX, &msg);
468
469     defwndproc_counter++;
470     ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
471     defwndproc_counter--;
472
473     return ret;
474 }
475
476 static HWND create_monthcal_control(DWORD style, HWND parent_window)
477 {
478     struct subclass_info *info;
479     HWND hwnd;
480
481     info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
482     if (!info)
483         return NULL;
484
485     hwnd = CreateWindowEx(0,
486                     MONTHCAL_CLASS,
487                     "",
488                     style,
489                     0, 0, 300, 400,
490                     parent_window, NULL, GetModuleHandleA(NULL), NULL);
491
492     if (!hwnd)
493     {
494         HeapFree(GetProcessHeap(), 0, info);
495         return NULL;
496     }
497
498     info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
499                                             (LONG_PTR)monthcal_subclass_proc);
500     SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
501
502     return hwnd;
503 }
504
505
506 /* Setter and Getters Tests */
507
508 static void test_monthcal_color(HWND hwnd)
509 {
510     int res, temp;
511
512     flush_sequences(sequences, NUM_MSG_SEQUENCES);
513
514     /* Setter and Getters for color*/
515     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0);
516     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_BACKGROUND, RGB(0,0,0));
517     expect(temp, res);
518     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0);
519     expect(RGB(0,0,0), temp);
520     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_BACKGROUND, RGB(255,255,255));
521     expect(temp, res);
522     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0);
523     expect(RGB(255,255,255), temp);
524
525     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0);
526     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_MONTHBK, RGB(0,0,0));
527     expect(temp, res);
528     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0);
529     expect(RGB(0,0,0), temp);
530     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_MONTHBK, RGB(255,255,255));
531     expect(temp, res);
532     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0);
533     expect(RGB(255,255,255), temp);
534
535     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0);
536     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TEXT, RGB(0,0,0));
537     expect(temp, res);
538     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0);
539     expect(RGB(0,0,0), temp);
540     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TEXT, RGB(255,255,255));
541     expect(temp, res);
542     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0);
543     expect(RGB(255,255,255), temp);
544
545     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0);
546     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLEBK, RGB(0,0,0));
547     expect(temp, res);
548     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0);
549     expect(RGB(0,0,0), temp);
550     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLEBK, RGB(255,255,255));
551     expect(temp, res);
552     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0);
553     expect(RGB(255,255,255), temp);
554
555     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0);
556     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLETEXT, RGB(0,0,0));
557     expect(temp, res);
558     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0);
559     expect(RGB(0,0,0), temp);
560     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLETEXT, RGB(255,255,255));
561     expect(temp, res);
562     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0);
563     expect(RGB(255,255,255), temp);
564
565     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0);
566     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TRAILINGTEXT, RGB(0,0,0));
567     expect(temp, res);
568     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0);
569     expect(RGB(0,0,0), temp);
570     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TRAILINGTEXT, RGB(255,255,255));
571     expect(temp, res);
572     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0);
573     expect(RGB(255,255,255), temp);
574
575     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_color_seq, "monthcal color", FALSE);
576 }
577
578 static void test_monthcal_currDate(HWND hwnd)
579 {
580     SYSTEMTIME st_original, st_new, st_test;
581     int res;
582
583     flush_sequences(sequences, NUM_MSG_SEQUENCES);
584
585     /* Setter and Getters for current date selected */
586     st_original.wYear = 2000;
587     st_original.wMonth = 11;
588     st_original.wDay = 28;
589     st_original.wHour = 11;
590     st_original.wMinute = 59;
591     st_original.wSecond = 30;
592     st_original.wMilliseconds = 0;
593     st_original.wDayOfWeek = 0;
594
595     st_new = st_test = st_original;
596
597     /* Should not validate the time */
598     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test);
599     expect(1,res);
600
601     /* Overflow matters, check for wDay */
602     st_test.wDay += 4;
603     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test);
604     expect(0,res);
605
606     /* correct wDay before checking for wMonth */
607     st_test.wDay -= 4;
608     expect(st_original.wDay, st_test.wDay);
609
610     /* Overflow matters, check for wMonth */
611     st_test.wMonth += 4;
612     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test);
613     expect(0,res);
614
615     /* checking if gets the information right, modify st_new */
616     st_new.wYear += 4;
617     st_new.wMonth += 4;
618     st_new.wDay += 4;
619     st_new.wHour += 4;
620     st_new.wMinute += 4;
621     st_new.wSecond += 4;
622
623     res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_new);
624     expect(1, res);
625
626     /* st_new change to st_origin, above settings with overflow */
627     /* should not change the current settings */
628     expect(st_original.wYear, st_new.wYear);
629     expect(st_original.wMonth, st_new.wMonth);
630     expect(st_original.wDay, st_new.wDay);
631     expect(st_original.wHour, st_new.wHour);
632     expect(st_original.wMinute, st_new.wMinute);
633     expect(st_original.wSecond, st_new.wSecond);
634
635     /* lparam cannot be NULL */
636     res = SendMessage(hwnd, MCM_GETCURSEL, 0, 0);
637     expect(0, res);
638
639     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_curr_date_seq, "monthcal currDate", TRUE);
640 }
641
642 static void test_monthcal_firstDay(HWND hwnd)
643 {
644     int res, fday, i, prev;
645     TCHAR b[128];
646     LCID lcid = LOCALE_USER_DEFAULT;
647
648     flush_sequences(sequences, NUM_MSG_SEQUENCES);
649
650     /* Setter and Getters for first day of week */
651     /* check for locale first day */
652     if(GetLocaleInfo(lcid, LOCALE_IFIRSTDAYOFWEEK, b, 128)){
653         fday = atoi(b);
654         trace("fday: %d\n", fday);
655         res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0);
656         expect(fday, res);
657         prev = fday;
658
659         /* checking for the values that actually will be stored as */
660         /* current first day when we set a new value */
661         for (i = -5; i < 12; i++){
662             res = SendMessage(hwnd, MCM_SETFIRSTDAYOFWEEK, 0, (LPARAM) i);
663             expect(prev, res);
664             res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0);
665             prev = res;
666
667             if (i == -1){
668                 expect(MAKELONG(fday, FALSE), res);
669             }else if (i >= 7){
670                 /* out of range sets max first day of week, locale is ignored */
671                 expect(MAKELONG(6, TRUE), res);
672             }else{
673                 expect(MAKELONG(i, TRUE), res);
674             }
675         }
676
677         ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_first_day_seq, "monthcal firstDay", FALSE);
678
679     }else{
680         skip("Cannot retrieve first day of the week\n");
681     }
682
683 }
684
685 static void test_monthcal_unicode(HWND hwnd)
686 {
687     int res, temp;
688
689     flush_sequences(sequences, NUM_MSG_SEQUENCES);
690
691     /* Setter and Getters for Unicode format */
692
693     /* getting the current settings */
694     temp = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
695
696     /* setting to 1, should return previous settings */
697     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 1, 0);
698     expect(temp, res);
699
700     /* current setting is 1, so, should return 1 */
701     res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
702     todo_wine {expect(1, res);}
703
704     /* setting to 0, should return previous settings */
705     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 0, 0);
706     todo_wine {expect(1, res);}
707
708     /* current setting is 0, so, it should return 0 */
709     res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
710     expect(0, res);
711
712     /* should return previous settings */
713     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 1, 0);
714     expect(0, res);
715
716     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_unicode_seq, "monthcal unicode", FALSE);
717 }
718
719 static void test_monthcal_HitTest(HWND hwnd)
720 {
721     MCHITTESTINFO mchit;
722     UINT res;
723     SYSTEMTIME st;
724     LONG x;
725     UINT title_index;
726     static const UINT title_hits[] =
727         { MCHT_NOWHERE, MCHT_TITLEBK, MCHT_TITLEBTNPREV, MCHT_TITLEBK,
728           MCHT_TITLEMONTH, MCHT_TITLEBK, MCHT_TITLEYEAR, MCHT_TITLEBK,
729           MCHT_TITLEBTNNEXT, MCHT_TITLEBK, MCHT_NOWHERE };
730
731     memset(&mchit, 0, sizeof(MCHITTESTINFO));
732
733     flush_sequences(sequences, NUM_MSG_SEQUENCES);
734
735     st.wYear = 2007;
736     st.wMonth = 4;
737     st.wDay = 11;
738     st.wHour = 1;
739     st.wMinute = 0;
740     st.wSecond = 0;
741     st.wMilliseconds = 0;
742     st.wDayOfWeek = 0;
743
744     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st);
745     expect(1,res);
746
747     /* (0, 0) is the top left of the control and should not be active */
748     mchit.cbSize = sizeof(MCHITTESTINFO);
749     mchit.pt.x = 0;
750     mchit.pt.y = 0;
751     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
752     expect(0, mchit.pt.x);
753     expect(0, mchit.pt.y);
754     expect(mchit.uHit, res);
755     todo_wine {expect(MCHT_NOWHERE, res);}
756
757     /* (300, 400) is the bottom right of the control and should not be active */
758     mchit.pt.x = 300;
759     mchit.pt.y = 400;
760     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
761     expect(300, mchit.pt.x);
762     expect(400, mchit.pt.y);
763     expect(mchit.uHit, res);
764     todo_wine {expect(MCHT_NOWHERE, res);}
765
766     /* (500, 500) is completely out of the control and should not be active */
767     mchit.pt.x = 500;
768     mchit.pt.y = 500;
769     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
770     expect(500, mchit.pt.x);
771     expect(500, mchit.pt.y);
772     expect(mchit.uHit, res);
773     todo_wine {expect(MCHT_NOWHERE, res);}
774
775     /* (120, 180) is in active area - calendar background */
776     mchit.pt.x = 120;
777     mchit.pt.y = 180;
778     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
779     expect(120, mchit.pt.x);
780     expect(180, mchit.pt.y);
781     expect(mchit.uHit, res);
782     expect(MCHT_CALENDARBK, res);
783
784     /* (70, 70) is in active area - day of the week */
785     mchit.pt.x = 70;
786     mchit.pt.y = 70;
787     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
788     expect(70, mchit.pt.x);
789     expect(70, mchit.pt.y);
790     expect(mchit.uHit, res);
791     todo_wine {expect(MCHT_CALENDARDAY, res);}
792
793     /* (70, 90) is in active area - date from prev month */
794     mchit.pt.x = 70;
795     mchit.pt.y = 90;
796     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
797     expect(70, mchit.pt.x);
798     expect(90, mchit.pt.y);
799     expect(mchit.uHit, res);
800     todo_wine {expect(MCHT_CALENDARDATEPREV, res);}
801
802 #if 0
803     /* (125, 115) is in active area - date from this month */
804     mchit.pt.x = 125;
805     mchit.pt.y = 115;
806     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
807     expect(125, mchit.pt.x);
808     expect(115, mchit.pt.y);
809     expect(mchit.uHit, res);
810     expect(MCHT_CALENDARDATE, res);
811 #endif
812
813     /* (80, 220) is in active area - background section of the title */
814     mchit.pt.x = 80;
815     mchit.pt.y = 220;
816     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
817     expect(80, mchit.pt.x);
818     expect(220, mchit.pt.y);
819     expect(mchit.uHit, res);
820     todo_wine {expect(MCHT_TITLEBK, res);}
821
822     /* (140, 215) is in active area - month section of the title */
823     mchit.pt.x = 140;
824     mchit.pt.y = 215;
825     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
826     expect(140, mchit.pt.x);
827     expect(215, mchit.pt.y);
828     expect(mchit.uHit, res);
829     todo_wine {expect(MCHT_TITLEMONTH, res);}
830
831     /* (170, 215) is in active area - year section of the title */
832     mchit.pt.x = 170;
833     mchit.pt.y = 215;
834     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
835     expect(170, mchit.pt.x);
836     expect(215, mchit.pt.y);
837     expect(mchit.uHit, res);
838     todo_wine {expect(MCHT_TITLEYEAR, res);}
839
840     /* (150, 260) is in active area - date from this month */
841     mchit.pt.x = 150;
842     mchit.pt.y = 260;
843     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
844     expect(150, mchit.pt.x);
845     expect(260, mchit.pt.y);
846     expect(mchit.uHit, res);
847     todo_wine {expect(MCHT_CALENDARDATE, res);}
848
849     /* (150, 350) is in active area - date from next month */
850     mchit.pt.x = 150;
851     mchit.pt.y = 350;
852     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
853     expect(150, mchit.pt.x);
854     expect(350, mchit.pt.y);
855     expect(mchit.uHit, res);
856     todo_wine {expect(MCHT_CALENDARDATENEXT, res);}
857
858     /* (150, 370) is in active area - today link */
859     mchit.pt.x = 150;
860     mchit.pt.y = 370;
861     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
862     expect(150, mchit.pt.x);
863     expect(370, mchit.pt.y);
864     expect(mchit.uHit, res);
865     todo_wine {expect(MCHT_TODAYLINK, res);}
866
867     /* (70, 370) is in active area - today link */
868     mchit.pt.x = 70;
869     mchit.pt.y = 370;
870     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
871     expect(70, mchit.pt.x);
872     expect(370, mchit.pt.y);
873     expect(mchit.uHit, res);
874     todo_wine {expect(MCHT_TODAYLINK, res);}
875
876     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_hit_test_seq, "monthcal hit test", TRUE);
877
878     /* The horizontal position of title bar elements depends on locale (y pos
879        is constant), so we sample across a horizontal line and make sure we
880        find all elements. */
881     mchit.pt.y = 40;
882     title_index = 0;
883     for (x = 0; x < 300; x++){
884         mchit.pt.x = x;
885         res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
886         expect(x, mchit.pt.x);
887         expect(40, mchit.pt.y);
888         expect(mchit.uHit, res);
889         if (res != title_hits[title_index]){
890             title_index++;
891             if (sizeof(title_hits) / sizeof(title_hits[0]) <= title_index)
892                 break;
893             todo_wine {expect(title_hits[title_index], res);}
894         }
895     }
896     todo_wine {ok(300 <= x && title_index + 1 == sizeof(title_hits) / sizeof(title_hits[0]),
897         "Wrong title layout\n");}
898 }
899
900 static void test_monthcal_todaylink(HWND hwnd)
901 {
902     MCHITTESTINFO mchit;
903     SYSTEMTIME st_test, st_new;
904     BOOL error = FALSE;
905     UINT res;
906
907     memset(&mchit, 0, sizeof(MCHITTESTINFO));
908
909     flush_sequences(sequences, NUM_MSG_SEQUENCES);
910
911     /* (70, 370) is in active area - today link */
912     mchit.cbSize = sizeof(MCHITTESTINFO);
913     mchit.pt.x = 70;
914     mchit.pt.y = 370;
915     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
916     expect(70, mchit.pt.x);
917     expect(370, mchit.pt.y);
918     expect(mchit.uHit, res);
919     todo_wine {expect(MCHT_TODAYLINK, res);}
920     if (70 != mchit.pt.x || 370 != mchit.pt.y || mchit.uHit != res
921         || MCHT_TODAYLINK != res)
922         error = TRUE;
923
924     st_test.wDay = 1;
925     st_test.wMonth = 1;
926     st_test.wYear = 2005;
927     memset(&st_new, 0, sizeof(SYSTEMTIME));
928
929     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
930
931     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
932     expect(1, res);
933     expect(1, st_new.wDay);
934     expect(1, st_new.wMonth);
935     expect(2005, st_new.wYear);
936     if (1 != res || 1 != st_new.wDay || 1 != st_new.wMonth
937         || 2005 != st_new.wYear)
938         error = TRUE;
939
940     if (error) {
941         skip("cannot perform today link test\n");
942         return;
943     }
944
945     res = SendMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELONG(70, 370));
946     expect(0, res);
947
948     memset(&st_new, 0, sizeof(SYSTEMTIME));
949     res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_new);
950     expect(1, res);
951     expect(1, st_new.wDay);
952     expect(1, st_new.wMonth);
953     expect(2005, st_new.wYear);
954
955     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_todaylink_seq, "monthcal hit test", TRUE);
956 }
957
958 static void test_monthcal_today(HWND hwnd)
959 {
960     SYSTEMTIME st_test, st_new;
961     int res;
962
963     flush_sequences(sequences, NUM_MSG_SEQUENCES);
964
965     /* Setter and Getters for "today" information */
966
967     /* check for overflow, should be ok */
968     st_test.wDay = 38;
969     st_test.wMonth = 38;
970
971     st_new.wDay = 27;
972     st_new.wMonth = 27;
973
974     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
975
976     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
977     expect(1, res);
978
979     /* st_test should not change */
980     expect(38, st_test.wDay);
981     expect(38, st_test.wMonth);
982
983     /* st_new should change, overflow does not matter */
984     expect(38, st_new.wDay);
985     expect(38, st_new.wMonth);
986
987     /* check for zero, should be ok*/
988     st_test.wDay = 0;
989     st_test.wMonth = 0;
990
991     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
992
993     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
994     expect(1, res);
995
996     /* st_test should not change */
997     expect(0, st_test.wDay);
998     expect(0, st_test.wMonth);
999
1000     /* st_new should change to zero*/
1001     expect(0, st_new.wDay);
1002     expect(0, st_new.wMonth);
1003
1004     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_today_seq, "monthcal today", TRUE);
1005 }
1006
1007 static void test_monthcal_scroll(HWND hwnd)
1008 {
1009     int res;
1010
1011     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1012
1013     /* Setter and Getters for scroll rate */
1014     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 2, 0);
1015     expect(0, res);
1016
1017     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 3, 0);
1018     expect(2, res);
1019     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1020     expect(3, res);
1021
1022     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 12, 0);
1023     expect(3, res);
1024     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1025     expect(12, res);
1026
1027     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 15, 0);
1028     expect(12, res);
1029     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1030     expect(15, res);
1031
1032     res = SendMessage(hwnd, MCM_SETMONTHDELTA, -5, 0);
1033     expect(15, res);
1034     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1035     expect(-5, res);
1036
1037     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_scroll_seq, "monthcal scroll", FALSE);
1038 }
1039
1040 static void test_monthcal_monthrange(HWND hwnd)
1041 {
1042     int res;
1043     SYSTEMTIME st_visible[2], st_daystate[2];
1044
1045     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1046     st_visible[0].wYear = 0;
1047     st_visible[0].wMonth = 0;
1048     st_visible[0].wDay = 0;
1049     st_daystate[1] = st_daystate[0] = st_visible[1] = st_visible[0];
1050
1051     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st_visible);
1052     todo_wine {
1053         expect(2, res);
1054         expect(2000, st_visible[0].wYear);
1055         expect(11, st_visible[0].wMonth);
1056         expect(1, st_visible[0].wDay);
1057         expect(2000, st_visible[1].wYear);
1058         expect(12, st_visible[1].wMonth);
1059         expect(31, st_visible[1].wDay);
1060     }
1061     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_DAYSTATE, (LPARAM)st_daystate);
1062     todo_wine {
1063         expect(4, res);
1064         expect(2000, st_daystate[0].wYear);
1065         expect(10, st_daystate[0].wMonth);
1066         expect(29, st_daystate[0].wDay);
1067         expect(2001, st_daystate[1].wYear);
1068         expect(1, st_daystate[1].wMonth);
1069         expect(6, st_daystate[1].wDay);
1070     }
1071
1072     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_monthrange_seq, "monthcal monthrange", FALSE);
1073 }
1074
1075 static void test_monthcal_MaxSelDay(HWND hwnd)
1076 {
1077     int res;
1078
1079     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1080
1081     /* Setter and Getters for max selected days */
1082     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 5, 0);
1083     expect(1, res);
1084     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1085     expect(5, res);
1086
1087     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 15, 0);
1088     expect(1, res);
1089     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1090     expect(15, res);
1091
1092     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, -1, 0);
1093     todo_wine {expect(0, res);}
1094     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1095     todo_wine {expect(15, res);}
1096
1097     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_max_sel_day_seq, "monthcal MaxSelDay", FALSE);
1098 }
1099
1100 static void test_monthcal_size(HWND hwnd)
1101 {
1102     int res;
1103     RECT r1, r2;
1104     HFONT hFont1, hFont2;
1105     LOGFONTA logfont;
1106
1107     lstrcpyA(logfont.lfFaceName, "Arial");
1108     memset(&logfont, 0, sizeof(logfont));
1109     logfont.lfHeight = 12;
1110     hFont1 = CreateFontIndirectA(&logfont);
1111
1112     logfont.lfHeight = 24;
1113     hFont2 = CreateFontIndirectA(&logfont);
1114
1115     /* initialize to a font we can compare against */
1116     SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont1, 0);
1117     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r1);
1118
1119     /* check that setting a larger font results in an larger rect */
1120     SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont2, 0);
1121     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r2);
1122
1123     OffsetRect(&r1, -r1.left, -r1.top);
1124     OffsetRect(&r2, -r2.left, -r2.top);
1125
1126     ok(r1.bottom < r2.bottom, "Failed to get larger rect with larger font\n");
1127 }
1128
1129 START_TEST(monthcal)
1130 {
1131     HMODULE hComctl32;
1132     BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
1133     INITCOMMONCONTROLSEX iccex;
1134     HWND hwnd, parent_wnd;
1135
1136     hComctl32 = GetModuleHandleA("comctl32.dll");
1137     pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
1138     if (!pInitCommonControlsEx)
1139     {
1140         skip("InitCommonControlsEx() is missing. Skipping the tests\n");
1141         return;
1142     }
1143     iccex.dwSize = sizeof(iccex);
1144     iccex.dwICC  = ICC_DATE_CLASSES;
1145     pInitCommonControlsEx(&iccex);
1146
1147     test_monthcal();
1148
1149     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1150
1151     parent_wnd = create_parent_window();
1152
1153     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1154     hwnd = create_monthcal_control(WS_CHILD | WS_BORDER | WS_VISIBLE, parent_wnd);
1155     assert(hwnd);
1156     ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_control_seq, "create monthcal control", TRUE);
1157
1158     SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0);
1159
1160     test_monthcal_color(hwnd);
1161     test_monthcal_currDate(hwnd);
1162     test_monthcal_firstDay(hwnd);
1163     test_monthcal_unicode(hwnd);
1164     test_monthcal_today(hwnd);
1165     test_monthcal_scroll(hwnd);
1166     test_monthcal_monthrange(hwnd);
1167     test_monthcal_HitTest(hwnd);
1168     test_monthcal_todaylink(hwnd);
1169     test_monthcal_size(hwnd);
1170
1171     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1172     DestroyWindow(hwnd);
1173     ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_monthcal_parent_msgs_seq, "Destroy monthcal (parent msg)", FALSE);
1174     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_child_msgs_seq, "Destroy monthcal (child msg)", FALSE);
1175
1176     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1177     hwnd = create_monthcal_control(MCS_MULTISELECT, parent_wnd);
1178     assert(hwnd);
1179     ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_multi_sel_style_seq, "create monthcal (multi sel style)", TRUE);
1180
1181     test_monthcal_MaxSelDay(hwnd);
1182
1183     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1184     DestroyWindow(hwnd);
1185     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_multi_sel_style_seq, "Destroy monthcal (multi sel style)", FALSE);
1186
1187     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1188     DestroyWindow(parent_wnd);
1189     ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_parent_seq, "Destroy parent window", FALSE);
1190 }