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