comctl32: Fix monthcal hit tests.
[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_WINDOWPOSCHANGING, sent|wparam, 0 },
56     { WM_ACTIVATEAPP, sent|wparam, 1 },
57     { WM_NCACTIVATE, sent|wparam, 1 },
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 },
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 },
81     { WM_GETFONT, sent },
82     { 0 }
83 };
84
85 static const struct message monthcal_color_seq[] = {
86     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0},
87     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(0,0,0)},
88     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0},
89     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(255,255,255)},
90     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0},
91
92     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0},
93     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(0,0,0)},
94     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0},
95     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(255,255,255)},
96     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0},
97
98     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0},
99     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(0,0,0)},
100     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0},
101     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(255,255,255)},
102     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0},
103
104     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0},
105     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(0,0,0)},
106     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0},
107     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(255,255,255)},
108     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0},
109
110     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0},
111     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(0,0,0)},
112     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0},
113     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(255,255,255)},
114     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0},
115
116     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0},
117     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(0,0,0)},
118     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0},
119     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(255,255,255)},
120     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0},
121     { 0 }
122 };
123
124 static const struct message monthcal_curr_date_seq[] = {
125     { MCM_SETCURSEL, sent|wparam, 0},
126     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
127     { WM_NCPAINT, sent|wparam|lparam|defwinproc, 1, 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     { WM_NCPAINT, sent|wparam|lparam|defwinproc, 1, 0},
206     { WM_ERASEBKGND, sent|lparam|defwinproc, 0},
207     { WM_SETFONT, sent|lparam, 0, 0},
208     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
209     { WM_ERASEBKGND, sent|lparam|defwinproc, 0},
210     { MCM_HITTEST, sent|wparam, 0},
211     { MCM_HITTEST, sent|wparam, 0},
212     { MCM_HITTEST, sent|wparam, 0},
213     { MCM_HITTEST, sent|wparam, 0},
214     { MCM_HITTEST, sent|wparam, 0},
215     { MCM_HITTEST, sent|wparam, 0},
216     { MCM_HITTEST, sent|wparam, 0},
217     { MCM_HITTEST, sent|wparam, 0},
218     { MCM_HITTEST, sent|wparam, 0},
219     { MCM_HITTEST, sent|wparam, 0},
220     { MCM_HITTEST, sent|wparam, 0},
221     { MCM_HITTEST, sent|wparam, 0},
222     { MCM_HITTEST, sent|wparam, 0},
223     { MCM_HITTEST, sent|wparam, 0},
224     { MCM_HITTEST, sent|wparam, 0},
225     { MCM_HITTEST, sent|wparam, 0},
226     { MCM_HITTEST, sent|wparam, 0},
227     { 0 }
228 };
229
230 static const struct message monthcal_today_seq[] = {
231     { MCM_SETTODAY, sent|wparam, 0},
232     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
233     { WM_NCPAINT, sent|wparam|lparam|defwinproc, 1, 0},
234     { WM_ERASEBKGND, sent|lparam|defwinproc, 0},
235     { MCM_GETTODAY, sent|wparam, 0},
236     { MCM_SETTODAY, sent|wparam, 0},
237     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
238     { MCM_GETTODAY, sent|wparam, 0},
239     { 0 }
240 };
241
242 static const struct message monthcal_scroll_seq[] = {
243     { MCM_SETMONTHDELTA, sent|wparam|lparam, 2, 0},
244     { MCM_SETMONTHDELTA, sent|wparam|lparam, 3, 0},
245     { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
246     { MCM_SETMONTHDELTA, sent|wparam|lparam, 12, 0},
247     { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
248     { MCM_SETMONTHDELTA, sent|wparam|lparam, 15, 0},
249     { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
250     { MCM_SETMONTHDELTA, sent|wparam|lparam, -5, 0},
251     { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
252     { 0 }
253 };
254
255 static const struct message monthcal_monthrange_seq[] = {
256     { MCM_GETMONTHRANGE, sent|wparam, GMR_VISIBLE},
257     { MCM_GETMONTHRANGE, sent|wparam, GMR_DAYSTATE},
258     { 0 }
259 };
260
261 static const struct message monthcal_max_sel_day_seq[] = {
262     { MCM_SETMAXSELCOUNT, sent|wparam|lparam, 5, 0},
263     { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0},
264     { MCM_SETMAXSELCOUNT, sent|wparam|lparam, 15, 0},
265     { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0},
266     { MCM_SETMAXSELCOUNT, sent|wparam|lparam, -1, 0},
267     { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0},
268     { 0 }
269 };
270
271 /* expected message sequence for parent*/
272 static const struct message destroy_monthcal_parent_msgs_seq[] = {
273     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY},
274     { 0 }
275 };
276
277 /* expected message sequence for child*/
278 static const struct message destroy_monthcal_child_msgs_seq[] = {
279     { WM_SHOWWINDOW, sent|wparam|lparam, 0, 0},
280     { WM_WINDOWPOSCHANGING, sent|wparam, 0},
281     { WM_WINDOWPOSCHANGED, sent|wparam, 0},
282     { WM_DESTROY, sent|wparam|lparam, 0, 0},
283     { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
284     { 0 }
285 };
286
287 static const struct message destroy_monthcal_multi_sel_style_seq[] = {
288     { WM_DESTROY, sent|wparam|lparam, 0, 0},
289     { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
290     { 0 }
291 };
292
293 /* expected message sequence for parent window*/
294 static const struct message destroy_parent_seq[] = {
295     { WM_WINDOWPOSCHANGING, sent|wparam, 0},
296     { WM_WINDOWPOSCHANGED, sent|wparam, 0},
297     { WM_NCACTIVATE, sent|wparam|lparam, 0, 0},
298     { WM_ACTIVATE, sent|wparam|lparam, 0, 0},
299     { WM_ACTIVATEAPP, sent|wparam, 0},
300     { WM_KILLFOCUS, sent|wparam|lparam, 0, 0},
301     { WM_IME_SETCONTEXT, sent|wparam|optional, 0},
302     { WM_IME_NOTIFY, sent|wparam|lparam|defwinproc|optional, 1, 0},
303     { WM_DESTROY, sent|wparam|lparam, 0, 0},
304     { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
305     { 0 }
306 };
307
308 static void test_monthcal(void)
309 {
310     HWND hwnd;
311     SYSTEMTIME st[2], st1[2];
312     INITCOMMONCONTROLSEX ic = {sizeof(INITCOMMONCONTROLSEX), ICC_DATE_CLASSES};
313     int res, month_range;
314
315     InitCommonControlsEx(&ic);
316     hwnd = CreateWindowA(MONTHCAL_CLASSA, "MonthCal", WS_POPUP | WS_VISIBLE, CW_USEDEFAULT,
317                          0, 300, 300, 0, 0, NULL, NULL);
318     ok(hwnd != NULL, "Failed to create MonthCal\n");
319     GetSystemTime(&st[0]);
320     st[1] = st[0];
321
322     /* Invalid date/time */
323     st[0].wYear  = 2000;
324     /* Time should not matter */
325     st[1].wHour = st[1].wMinute = st[1].wSecond = 70;
326     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set MAX limit\n");
327     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
328     ok(st1[0].wYear != 2000, "Lover limit changed\n");
329
330     st[1].wMonth = 0;
331     ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Should have failed to set limits\n");
332     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
333     ok(st1[0].wYear != 2000, "Lover limit changed\n");
334     ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Should have failed to set MAX limit\n");
335     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
336     ok(st1[0].wYear != 2000, "Lover limit changed\n");
337
338     GetSystemTime(&st[0]);
339     st[0].wDay = 20;
340     st[0].wMonth = 5;
341     st[1] = st[0];
342
343     month_range = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
344     st[1].wMonth--;
345     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
346     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
347     ok(res == month_range, "Invalid month range (%d)\n", res);
348     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == (GDTR_MIN|GDTR_MAX), "Limits should be set\n");
349
350     st[1].wMonth += 2;
351     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
352     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
353     ok(res == month_range, "Invalid month range (%d)\n", res);
354
355     st[1].wYear --;
356     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
357     st[1].wYear += 1;
358     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
359
360     st[1].wMonth -= 3;
361     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
362     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "Only MAX limit should be set\n");
363     st[1].wMonth += 4;
364     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
365     st[1].wYear -= 3;
366     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
367     st[1].wYear += 4;
368     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
369     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "Only MAX limit should be set\n");
370
371     DestroyWindow(hwnd);
372 }
373
374 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
375 {
376     static long defwndproc_counter = 0;
377     LRESULT ret;
378     struct message msg;
379
380     /* do not log painting messages */
381     if (message != WM_PAINT &&
382         message != WM_ERASEBKGND &&
383         message != WM_NCPAINT &&
384         message != WM_NCHITTEST &&
385         message != WM_GETTEXT &&
386         message != WM_GETICON &&
387         message != WM_DEVICECHANGE)
388     {
389         trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
390
391         msg.message = message;
392         msg.flags = sent|wparam|lparam;
393         if (defwndproc_counter) msg.flags |= defwinproc;
394         msg.wParam = wParam;
395         msg.lParam = lParam;
396         add_message(sequences, PARENT_SEQ_INDEX, &msg);
397     }
398
399     defwndproc_counter++;
400     ret = DefWindowProcA(hwnd, message, wParam, lParam);
401     defwndproc_counter--;
402
403     return ret;
404 }
405
406 static BOOL register_parent_wnd_class(void)
407 {
408     WNDCLASSA cls;
409
410     cls.style = 0;
411     cls.lpfnWndProc = parent_wnd_proc;
412     cls.cbClsExtra = 0;
413     cls.cbWndExtra = 0;
414     cls.hInstance = GetModuleHandleA(NULL);
415     cls.hIcon = 0;
416     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
417     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
418     cls.lpszMenuName = NULL;
419     cls.lpszClassName = "Month-Cal test parent class";
420     return RegisterClassA(&cls);
421 }
422
423 static HWND create_parent_window(void)
424 {
425     HWND hwnd;
426
427     InitCommonControls();
428
429     /* flush message sequences, so we can check the new sequence by the end of function */
430     flush_sequences(sequences, NUM_MSG_SEQUENCES);
431
432     if (!register_parent_wnd_class())
433         return NULL;
434
435     hwnd = CreateWindowEx(0, "Month-Cal test parent class",
436                           "Month-Cal test parent window",
437                           WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
438                           WS_MAXIMIZEBOX | WS_VISIBLE,
439                           0, 0, 500, 500,
440                           GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
441
442     assert(hwnd);
443
444     /* check for message sequences */
445     ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_window_seq, "create parent window", TRUE);
446
447     return hwnd;
448 }
449
450 static LRESULT WINAPI monthcal_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
451 {
452     struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
453     static long defwndproc_counter = 0;
454     LRESULT ret;
455     struct message msg;
456
457     trace("monthcal: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
458
459     msg.message = message;
460     msg.flags = sent|wparam|lparam;
461     if (defwndproc_counter) msg.flags |= defwinproc;
462     msg.wParam = wParam;
463     msg.lParam = lParam;
464     add_message(sequences, MONTHCAL_SEQ_INDEX, &msg);
465
466     defwndproc_counter++;
467     ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
468     defwndproc_counter--;
469
470     return ret;
471 }
472
473 static HWND create_monthcal_control(DWORD style, HWND parent_window)
474 {
475     struct subclass_info *info;
476     HWND hwnd;
477     static const INITCOMMONCONTROLSEX ic = {sizeof(INITCOMMONCONTROLSEX), ICC_DATE_CLASSES};
478
479     InitCommonControlsEx(&ic);
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, (LPARAM) NULL);
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         res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0);
655         expect(fday, res);
656         prev = fday;
657
658         /* checking for the values that actually will be stored as */
659         /* current first day when we set a new value */
660         for (i = -5; i < 12; i++){
661             res = SendMessage(hwnd, MCM_SETFIRSTDAYOFWEEK, 0, (LPARAM) i);
662             expect(prev, res);
663             res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0);
664             prev = res;
665
666             if (i == -1){
667                 expect(MAKELONG(fday, FALSE), res);
668             }else if (i >= 7){
669                 expect(MAKELONG(fday, TRUE), res);
670             }else{
671                 expect(MAKELONG(i, TRUE), res);
672             }
673         }
674
675         ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_first_day_seq, "monthcal firstDay", FALSE);
676
677     }else{
678         skip("Cannot retrieve first day of the week\n");
679     }
680
681 }
682
683 static void test_monthcal_unicode(HWND hwnd)
684 {
685     int res, temp;
686
687     flush_sequences(sequences, NUM_MSG_SEQUENCES);
688
689     /* Setter and Getters for Unicode format */
690
691     /* getting the current settings */
692     temp = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
693
694     /* setting to 1, should return previous settings */
695     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 1, 0);
696     expect(temp, res);
697
698     /* current setting is 1, so, should return 1 */
699     res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
700     todo_wine {expect(1, res);}
701
702     /* setting to 0, should return previous settings */
703     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 0, 0);
704     todo_wine {expect(1, res);}
705
706     /* current setting is 0, so, it should return 0 */
707     res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
708     expect(0, res);
709
710     /* should return previous settings */
711     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 1, 0);
712     expect(0, res);
713
714     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_unicode_seq, "monthcal unicode", FALSE);
715 }
716
717 static void test_monthcal_HitTest(HWND parent_wnd)
718 {
719     MCHITTESTINFO mchit;
720     int res;
721     HWND hwnd;
722     SYSTEMTIME st;
723
724     hwnd = create_monthcal_control(WS_CHILD | WS_BORDER | WS_VISIBLE, parent_wnd);
725     assert(hwnd);
726     memset(&mchit, 0, sizeof(MCHITTESTINFO));
727
728     flush_sequences(sequences, NUM_MSG_SEQUENCES);
729
730     st.wYear = 2007;
731     st.wMonth = 4;
732     st.wDay = 11;
733     st.wHour = 1;
734     st.wMinute = 0;
735     st.wSecond = 0;
736     st.wMilliseconds = 0;
737     st.wDayOfWeek = 0;
738
739     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st);
740     expect(1,res);
741
742     SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0);
743
744     /* (0, 0) is the top left of the control and should not be active */
745     mchit.cbSize = sizeof(MCHITTESTINFO);
746     mchit.pt.x = 0;
747     mchit.pt.y = 0;
748     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
749     expect(0, mchit.pt.x);
750     expect(0, mchit.pt.y);
751     expect(mchit.uHit, res);
752     todo_wine {expect(MCHT_NOWHERE, res);}
753
754     /* (300, 400) is the bottom right of the control and should not be active */
755     mchit.pt.x = 300;
756     mchit.pt.y = 400;
757     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
758     expect(300, mchit.pt.x);
759     expect(400, mchit.pt.y);
760     expect(mchit.uHit, res);
761     todo_wine {expect(MCHT_NOWHERE, res);}
762
763     /* (500, 500) is completely out of the control and should not be active */
764     mchit.pt.x = 500;
765     mchit.pt.y = 500;
766     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
767     expect(500, mchit.pt.x);
768     expect(500, mchit.pt.y);
769     expect(mchit.uHit, res);
770     todo_wine {expect(MCHT_NOWHERE, res);}
771
772     /* (120, 180) is in active area - calendar background */
773     mchit.pt.x = 120;
774     mchit.pt.y = 180;
775     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
776     expect(120, mchit.pt.x);
777     expect(180, mchit.pt.y);
778     expect(mchit.uHit, res);
779     expect(MCHT_CALENDARBK, res);
780
781     /* (50, 40) is in active area - previous month button */
782     mchit.pt.x = 50;
783     mchit.pt.y = 40;
784     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
785     expect(50, mchit.pt.x);
786     expect(40, mchit.pt.y);
787     expect(mchit.uHit, res);
788     todo_wine {expect(MCHT_TITLEBTNPREV, res);}
789
790     /* (90, 40) is in active area - background section of the title */
791     mchit.pt.x = 90;
792     mchit.pt.y = 40;
793     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
794     expect(90, mchit.pt.x);
795     expect(40, mchit.pt.y);
796     expect(mchit.uHit, res);
797     todo_wine {expect(MCHT_TITLE, res);}
798
799     /* (140, 40) is in active area - month section of the title */
800     mchit.pt.x = 140;
801     mchit.pt.y = 40;
802     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
803     expect(140, mchit.pt.x);
804     expect(40, mchit.pt.y);
805     expect(mchit.uHit, res);
806     todo_wine {expect(MCHT_TITLEMONTH, res);}
807
808     /* (250, 40) is in active area - next month button */
809     mchit.pt.x = 250;
810     mchit.pt.y = 40;
811     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
812     expect(250, mchit.pt.x);
813     expect(40, mchit.pt.y);
814     expect(mchit.uHit, res);
815     todo_wine {expect(MCHT_TITLEBTNNEXT, res);}
816
817     /* (70, 70) is in active area - day of the week */
818     mchit.pt.x = 70;
819     mchit.pt.y = 70;
820     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
821     expect(70, mchit.pt.x);
822     expect(70, mchit.pt.y);
823     expect(mchit.uHit, res);
824     todo_wine {expect(MCHT_CALENDARDAY, res);}
825
826     /* (70, 90) is in active area - date from prev month */
827     mchit.pt.x = 70;
828     mchit.pt.y = 90;
829     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
830     expect(70, mchit.pt.x);
831     expect(90, mchit.pt.y);
832     expect(mchit.uHit, res);
833     todo_wine {expect(MCHT_CALENDARDATEPREV, res);}
834
835 #if 0
836     /* (125, 115) is in active area - date from this month */
837     mchit.pt.x = 125;
838     mchit.pt.y = 115;
839     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
840     expect(125, mchit.pt.x);
841     expect(115, mchit.pt.y);
842     expect(mchit.uHit, res);
843     expect(MCHT_CALENDARDATE, res);
844 #endif
845
846     /* (80, 220) is in active area - background section of the title */
847     mchit.pt.x = 80;
848     mchit.pt.y = 220;
849     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
850     expect(80, mchit.pt.x);
851     expect(220, mchit.pt.y);
852     expect(mchit.uHit, res);
853     todo_wine {expect(MCHT_TITLEBK, res);}
854
855     /* (140, 215) is in active area - month section of the title */
856     mchit.pt.x = 140;
857     mchit.pt.y = 215;
858     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
859     expect(140, mchit.pt.x);
860     expect(215, mchit.pt.y);
861     expect(mchit.uHit, res);
862     todo_wine {expect(MCHT_TITLEMONTH, res);}
863
864     /* (170, 215) is in active area - year section of the title */
865     mchit.pt.x = 170;
866     mchit.pt.y = 215;
867     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
868     expect(170, mchit.pt.x);
869     expect(215, mchit.pt.y);
870     expect(mchit.uHit, res);
871     todo_wine {expect(MCHT_TITLEYEAR, res);}
872
873     /* (150, 260) is in active area - date from this month */
874     mchit.pt.x = 150;
875     mchit.pt.y = 260;
876     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
877     expect(150, mchit.pt.x);
878     expect(260, mchit.pt.y);
879     expect(mchit.uHit, res);
880     todo_wine {expect(MCHT_CALENDARDATE, res);}
881
882     /* (150, 350) is in active area - date from next month */
883     mchit.pt.x = 150;
884     mchit.pt.y = 350;
885     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
886     expect(150, mchit.pt.x);
887     expect(350, mchit.pt.y);
888     expect(mchit.uHit, res);
889     todo_wine {expect(MCHT_CALENDARDATENEXT, res);}
890
891     /* (150, 370) is in active area - today link */
892     mchit.pt.x = 150;
893     mchit.pt.y = 370;
894     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
895     expect(150, mchit.pt.x);
896     expect(370, mchit.pt.y);
897     expect(mchit.uHit, res);
898     todo_wine {expect(MCHT_TODAYLINK, res);}
899
900     /* (70, 370) is in active area - today link */
901     mchit.pt.x = 70;
902     mchit.pt.y = 370;
903     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
904     expect(70, mchit.pt.x);
905     expect(370, mchit.pt.y);
906     expect(mchit.uHit, res);
907     todo_wine {expect(MCHT_TODAYLINK, res);}
908
909     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_hit_test_seq, "monthcal hit test", TRUE);
910
911     DestroyWindow(hwnd);
912 }
913
914 static void test_monthcal_today(HWND hwnd)
915 {
916     SYSTEMTIME st_test, st_new;
917     int res;
918
919     flush_sequences(sequences, NUM_MSG_SEQUENCES);
920
921     /* Setter and Getters for "today" information */
922
923     /* check for overflow, should be ok */
924     st_test.wDay = 38;
925     st_test.wMonth = 38;
926
927     st_new.wDay = 27;
928     st_new.wMonth = 27;
929
930     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
931
932     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
933     expect(1, res);
934
935     /* st_test should not change */
936     expect(38, st_test.wDay);
937     expect(38, st_test.wMonth);
938
939     /* st_new should change, overflow does not matter */
940     expect(38, st_new.wDay);
941     expect(38, st_new.wMonth);
942
943     /* check for zero, should be ok*/
944     st_test.wDay = 0;
945     st_test.wMonth = 0;
946
947     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
948
949     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
950     expect(1, res);
951
952     /* st_test should not change */
953     expect(0, st_test.wDay);
954     expect(0, st_test.wMonth);
955
956     /* st_new should change to zero*/
957     expect(0, st_new.wDay);
958     expect(0, st_new.wMonth);
959
960     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_today_seq, "monthcal today", TRUE);
961 }
962
963 static void test_monthcal_scroll(HWND hwnd)
964 {
965     int res;
966
967     flush_sequences(sequences, NUM_MSG_SEQUENCES);
968
969     /* Setter and Getters for scroll rate */
970     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 2, 0);
971     expect(0, res);
972
973     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 3, 0);
974     expect(2, res);
975     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
976     expect(3, res);
977
978     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 12, 0);
979     expect(3, res);
980     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
981     expect(12, res);
982
983     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 15, 0);
984     expect(12, res);
985     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
986     expect(15, res);
987
988     res = SendMessage(hwnd, MCM_SETMONTHDELTA, -5, 0);
989     expect(15, res);
990     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
991     expect(-5, res);
992
993     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_scroll_seq, "monthcal scroll", FALSE);
994 }
995
996 static void test_monthcal_monthrange(HWND hwnd)
997 {
998     int res;
999     SYSTEMTIME st_visible[2], st_daystate[2];
1000
1001     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1002     st_visible[0].wYear = 0;
1003     st_visible[0].wMonth = 0;
1004     st_visible[0].wDay = 0;
1005     st_daystate[1] = st_daystate[0] = st_visible[1] = st_visible[0];
1006
1007     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st_visible);
1008     todo_wine {
1009         expect(2, res);
1010         expect(2000, st_visible[0].wYear);
1011         expect(11, st_visible[0].wMonth);
1012         expect(1, st_visible[0].wDay);
1013         expect(2000, st_visible[1].wYear);
1014         expect(12, st_visible[1].wMonth);
1015         expect(31, st_visible[1].wDay);
1016     }
1017     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_DAYSTATE, (LPARAM)st_daystate);
1018     todo_wine {
1019         expect(4, res);
1020         expect(2000, st_daystate[0].wYear);
1021         expect(10, st_daystate[0].wMonth);
1022         expect(29, st_daystate[0].wDay);
1023         expect(2001, st_daystate[1].wYear);
1024         expect(1, st_daystate[1].wMonth);
1025         expect(6, st_daystate[1].wDay);
1026     }
1027
1028     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_monthrange_seq, "monthcal monthrange", FALSE);
1029 }
1030
1031 static void test_monthcal_MaxSelDay(HWND hwnd)
1032 {
1033     int res;
1034
1035     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1036
1037     /* Setter and Getters for max selected days */
1038     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 5, 0);
1039     expect(1, res);
1040     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1041     expect(5, res);
1042
1043     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 15, 0);
1044     expect(1, res);
1045     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1046     expect(15, res);
1047
1048     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, -1, 0);
1049     todo_wine {expect(0, res);}
1050     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1051     todo_wine {expect(15, res);}
1052
1053     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_max_sel_day_seq, "monthcal MaxSelDay", FALSE);
1054 }
1055
1056
1057 START_TEST(monthcal)
1058 {
1059     HWND hwnd, parent_wnd;
1060     test_monthcal();
1061
1062     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1063
1064     parent_wnd = create_parent_window();
1065
1066     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1067     hwnd = create_monthcal_control(WS_CHILD | WS_BORDER | WS_VISIBLE, parent_wnd);
1068     assert(hwnd);
1069     ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_control_seq, "create monthcal control", TRUE);
1070
1071     test_monthcal_color(hwnd);
1072     test_monthcal_currDate(hwnd);
1073     test_monthcal_firstDay(hwnd);
1074     test_monthcal_unicode(hwnd);
1075     test_monthcal_HitTest(parent_wnd);
1076     test_monthcal_today(hwnd);
1077     test_monthcal_scroll(hwnd);
1078     test_monthcal_monthrange(hwnd);
1079
1080     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1081     DestroyWindow(hwnd);
1082     ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_monthcal_parent_msgs_seq, "Destroy monthcal (parent msg)", FALSE);
1083     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_child_msgs_seq, "Destroy monthcal (child msg)", FALSE);
1084
1085     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1086     hwnd = create_monthcal_control(MCS_MULTISELECT, parent_wnd);
1087     assert(hwnd);
1088     ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_multi_sel_style_seq, "create monthcal (multi sel style)", TRUE);
1089
1090     test_monthcal_MaxSelDay(hwnd);
1091
1092     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1093     DestroyWindow(hwnd);
1094     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_multi_sel_style_seq, "Destroy monthcal (multi sel style)", FALSE);
1095
1096     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1097     DestroyWindow(parent_wnd);
1098     ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_parent_seq, "Destroy parent window", FALSE);
1099 }