quartz: Use proper alloc/free functions for COM objects.
[wine] / dlls / comctl32 / tests / datetime.c
1 /* Unit test suite for datetime control.
2 *
3 * Copyright 2007 Kanit Therdsteerasukdi
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include <windows.h>
21 #include <commctrl.h>
22
23 #include "wine/test.h"
24 #include "msg.h"
25
26 #define expect(EXPECTED, GOT) ok((GOT)==(EXPECTED), "Expected %d, got %ld\n", (EXPECTED), (GOT))
27
28 #define expect_unsuccess(EXPECTED, GOT) ok((GOT)==(EXPECTED), "Expected %d(unsuccessful), got %ld(successful)\n", (EXPECTED), (GOT))
29
30 #define NUM_MSG_SEQUENCES   1
31 #define DATETIME_SEQ_INDEX    0
32
33 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
34
35 static const struct message test_dtm_set_format_seq[] = {
36     { DTM_SETFORMATA, sent|wparam|lparam, 0x00000000, 0x00000000 },
37     { DTM_SETFORMATA, sent|wparam, 0x00000000 },
38     { 0 }
39 };
40
41 static const struct message test_dtm_set_and_get_mccolor_seq[] = {
42     { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 },
43     { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000000, 0x00ffffff },
44     { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000000, 0x00dcb464 },
45     { DTM_GETMCCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 },
46     { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000004, 0x00000000 },
47     { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000004, 0x00ffffff },
48     { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000004, 0x00dcb464 },
49     { DTM_GETMCCOLOR, sent|wparam|lparam, 0x00000004, 0x00000000 },
50     { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000001, 0x00000000 },
51     { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000001, 0x00ffffff },
52     { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000001, 0x00dcb464 },
53     { DTM_GETMCCOLOR, sent|wparam|lparam, 0x00000001, 0x00000000 },
54     { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000002, 0x00000000 },
55     { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000002, 0x00ffffff },
56     { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000002, 0x00dcb464 },
57     { DTM_GETMCCOLOR, sent|wparam|lparam, 0x00000002, 0x00000000 },
58     { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000003, 0x00000000 },
59     { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000003, 0x00ffffff },
60     { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000003, 0x00dcb464 },
61     { DTM_GETMCCOLOR, sent|wparam|lparam, 0x00000003, 0x00000000 },
62     { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000005, 0x00000000 },
63     { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000005, 0x00ffffff },
64     { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000005, 0x00dcb464 },
65     { DTM_GETMCCOLOR, sent|wparam|lparam, 0x00000005, 0x00000000 },
66     { 0 }
67 };
68
69 static const struct message test_dtm_set_and_get_mcfont_seq[] = {
70     { DTM_SETMCFONT, sent|lparam, 0, 0x00000001 },
71     { DTM_GETMCFONT, sent|wparam|lparam, 0x00000000, 0x00000000 },
72     { 0 }
73 };
74
75 static const struct message test_dtm_get_monthcal_seq[] = {
76     { DTM_GETMONTHCAL, sent|wparam|lparam, 0x00000000, 0x00000000 },
77     { 0 }
78 };
79
80 static const struct message test_dtm_set_and_get_range_seq[] = {
81     { DTM_SETRANGE, sent|wparam, 0x00000001 },
82     { DTM_GETRANGE, sent|wparam, 0x00000000 },
83     { DTM_SETRANGE, sent|wparam, 0x00000002 },
84     { DTM_SETRANGE, sent|wparam, 0x00000002 },
85     { DTM_GETRANGE, sent|wparam, 0x00000000},
86     { DTM_SETRANGE, sent|wparam, 0x00000001 },
87     { DTM_SETRANGE, sent|wparam, 0x00000003 },
88     { DTM_SETRANGE, sent|wparam, 0x00000003 },
89     { DTM_GETRANGE, sent|wparam, 0x00000000 },
90     { DTM_SETRANGE, sent|wparam, 0x00000003 },
91     { DTM_GETRANGE, sent|wparam, 0x00000000 },
92     { DTM_SETRANGE, sent|wparam, 0x00000003 },
93     { DTM_GETRANGE, sent|wparam, 0x00000000 },
94     { 0 }
95 };
96
97 static const struct message test_dtm_set_range_swap_min_max_seq[] = {
98     { DTM_SETSYSTEMTIME, sent|wparam, 0x00000000 },
99     { DTM_GETSYSTEMTIME, sent|wparam, 0x00000000 },
100     { DTM_SETRANGE, sent|wparam, 0x00000003 },
101     { DTM_GETRANGE, sent|wparam, 0x00000000 },
102     { DTM_SETSYSTEMTIME, sent|wparam, 0x00000000 },
103     { DTM_GETSYSTEMTIME, sent|wparam, 0x00000000 },
104     { DTM_SETRANGE, sent|wparam, 0x00000003 },
105     { DTM_GETRANGE, sent|wparam, 0x00000000 },
106     { DTM_SETRANGE, sent|wparam, 0x00000003 },
107     { DTM_GETRANGE, sent|wparam, 0x00000000 },
108     { DTM_SETRANGE, sent|wparam, 0x00000003 },
109     { DTM_GETRANGE, sent|wparam, 0x00000000 },
110     { 0 }
111 };
112
113 static const struct message test_dtm_set_and_get_system_time_seq[] = {
114     { DTM_SETSYSTEMTIME, sent|wparam, 0x00000001 },
115     { DTM_GETSYSTEMTIME, sent|wparam, 0x00000000 },
116     { DTM_SETSYSTEMTIME, sent|wparam, 0x00000000 },
117     { DTM_SETSYSTEMTIME, sent|wparam, 0x00000000 },
118     { DTM_SETSYSTEMTIME, sent|wparam, 0x00000000 },
119     { DTM_GETSYSTEMTIME, sent|wparam, 0x00000000 },
120     { DTM_SETSYSTEMTIME, sent|wparam, 0x00000000 },
121     { 0 }
122 };
123
124 static const struct message destroy_window_seq[] = {
125     { WM_DESTROY, sent|wparam|lparam, 0x00000000, 0x00000000 },
126     { WM_NCDESTROY, sent|wparam|lparam, 0x00000000, 0x00000000 },
127     { 0 }
128 };
129
130 struct subclass_info
131 {
132     WNDPROC oldproc;
133 };
134
135 static LRESULT WINAPI datetime_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
136 {
137     struct subclass_info *info = (struct subclass_info *)GetWindowLongA(hwnd, GWL_USERDATA);
138     static long defwndproc_counter = 0;
139     LRESULT ret;
140     struct message msg;
141
142     trace("datetime: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
143
144     msg.message = message;
145     msg.flags = sent|wparam|lparam;
146     if (defwndproc_counter) msg.flags |= defwinproc;
147     msg.wParam = wParam;
148     msg.lParam = lParam;
149     add_message(sequences, DATETIME_SEQ_INDEX, &msg);
150
151     defwndproc_counter++;
152     ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
153     defwndproc_counter--;
154
155     return ret;
156 }
157
158 static HWND create_datetime_control(DWORD style, DWORD exstyle)
159 {
160     struct subclass_info *info;
161     HWND hWndDateTime = NULL;
162
163     info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
164     if (!info)
165         return NULL;
166
167     hWndDateTime = CreateWindowEx(0,
168         DATETIMEPICK_CLASS,
169         NULL,
170         style,
171         0,50,300,120,
172         NULL,
173         NULL,
174         NULL,
175         NULL);
176
177     if (!hWndDateTime) {
178         HeapFree(GetProcessHeap(), 0, info);
179         return NULL;
180     }
181
182     info->oldproc = (WNDPROC)SetWindowLongA(hWndDateTime, GWL_WNDPROC,
183                                             (LONG)datetime_subclass_proc);
184     SetWindowLongA(hWndDateTime, GWL_USERDATA, (LONG)info);
185
186     return hWndDateTime;
187 }
188
189 static void test_dtm_set_format(HWND hWndDateTime)
190 {
191     LRESULT r;
192
193     todo_wine {
194         r = SendMessage(hWndDateTime, DTM_SETFORMAT, 0, (LPARAM)NULL);
195         expect(1, r);
196
197         r = SendMessage(hWndDateTime, DTM_SETFORMAT, 0,
198             (LPARAM)"'Today is: 'hh':'m':'s dddd MMM dd', 'yyyy");
199         expect(1, r);
200     }
201
202     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_format_seq, "test_dtm_set_format", FALSE);
203     flush_sequences(sequences, NUM_MSG_SEQUENCES);
204 }
205
206 void test_mccolor_types(HWND hWndDateTime, int mccolor_type, const char* mccolor_name)
207 {
208     LRESULT r;
209     COLORREF theColor, prevColor;
210
211     theColor=RGB(0,0,0);
212     r = SendMessage(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor);
213     ok(r != -1, "%s: Set RGB(0,0,0): Expected COLORREF of previous value, got %ld\n", mccolor_name, r);
214     prevColor=theColor;
215     theColor=RGB(255,255,255);
216     r = SendMessage(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor);
217     ok(r==prevColor, "%s: Set RGB(255,255,255): Expected COLORREF of previous value, got %ld\n", mccolor_name, r);
218     prevColor=theColor;
219     theColor=RGB(100,180,220);
220     r = SendMessage(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor);
221     ok(r==prevColor, "%s: Set RGB(100,180,220): Expected COLORREF of previous value, got %ld\n", mccolor_name, r);
222     r = SendMessage(hWndDateTime, DTM_GETMCCOLOR, mccolor_type, 0);
223     ok(r==theColor, "%s: GETMCCOLOR: Expected %d, got %ld\n", mccolor_name, theColor, r);
224 }
225
226 static void test_dtm_set_and_get_mccolor(HWND hWndDateTime)
227 {
228     test_mccolor_types(hWndDateTime, MCSC_BACKGROUND, "MCSC_BACKGROUND");
229     test_mccolor_types(hWndDateTime, MCSC_MONTHBK, "MCSC_MONTHBK");
230     test_mccolor_types(hWndDateTime, MCSC_TEXT, "MCSC_TEXT");
231     test_mccolor_types(hWndDateTime, MCSC_TITLEBK, "MCSC_TITLEBK");
232     test_mccolor_types(hWndDateTime, MCSC_TITLETEXT, "MCSC_TITLETEXT");
233     test_mccolor_types(hWndDateTime, MCSC_TRAILINGTEXT, "MCSC_TRAILINGTEXT");
234
235     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_mccolor_seq, "test_dtm_set_and_get_mccolor", FALSE);
236     flush_sequences(sequences, NUM_MSG_SEQUENCES);
237 }
238
239 static void test_dtm_set_and_get_mcfont(HWND hWndDateTime)
240 {
241     HFONT hFontOrig, hFontNew;
242
243     hFontOrig = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
244     SendMessage(hWndDateTime, DTM_SETMCFONT, (WPARAM)hFontOrig, TRUE);
245     hFontNew = (HFONT)SendMessage(hWndDateTime, DTM_GETMCFONT, 0, 0);
246     ok(hFontOrig == hFontNew, "Expected hFontOrig==hFontNew, hFontOrig=%p, hFontNew=%p\n", hFontOrig, hFontNew);
247
248     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_mcfont_seq, "test_dtm_set_and_get_mcfont", FALSE);
249     flush_sequences(sequences, NUM_MSG_SEQUENCES);
250 }
251
252 static void test_dtm_get_monthcal(HWND hWndDateTime)
253 {
254     LRESULT r;
255
256     todo_wine {
257         r = SendMessage(hWndDateTime, DTM_GETMONTHCAL, 0, 0);
258         ok(r == (LPARAM)NULL, "Expected NULL(no child month calendar control), got %ld\n", r);
259     }
260
261     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_get_monthcal_seq, "test_dtm_get_monthcal", FALSE);
262     flush_sequences(sequences, NUM_MSG_SEQUENCES);
263 }
264
265 void fill_systime_struct(SYSTEMTIME *st, int year, int month, int dayofweek, int day, int hour, int minute, int second, int milliseconds)
266 {
267     st->wYear = year;
268     st->wMonth = month;
269     st->wDayOfWeek = dayofweek;
270     st->wDay = day;
271     st->wHour = hour;
272     st->wMinute = minute;
273     st->wSecond = second;
274     st->wMilliseconds = milliseconds;
275 }
276
277 LPARAM compare_systime_date(SYSTEMTIME *st1, SYSTEMTIME *st2)
278 {
279     return (st1->wYear == st2->wYear)
280             && (st1->wMonth == st2->wMonth)
281             && (st1->wDayOfWeek == st2->wDayOfWeek)
282             && (st1->wDay == st2->wDay);
283 }
284
285 LPARAM compare_systime_time(SYSTEMTIME *st1, SYSTEMTIME *st2)
286 {
287     return (st1->wHour == st2->wHour)
288             && (st1->wMinute == st2->wMinute)
289             && (st1->wSecond == st2->wSecond)
290             && (st1->wMilliseconds == st2->wMilliseconds);
291 }
292
293 LPARAM compare_systime(SYSTEMTIME *st1, SYSTEMTIME *st2)
294 {
295     if(!compare_systime_date(st1, st2))
296         return 0;
297
298     return compare_systime_time(st1, st2);
299 }
300
301 #define expect_systime(ST1, ST2) ok(compare_systime((ST1), (ST2))==1, "ST1 != ST2\n")
302 #define expect_systime_date(ST1, ST2) ok(compare_systime_date((ST1), (ST2))==1, "ST1.date != ST2.date\n")
303 #define expect_systime_time(ST1, ST2) ok(compare_systime_time((ST1), (ST2))==1, "ST1.time != ST2.time\n")
304
305 static void test_dtm_set_and_get_range(HWND hWndDateTime)
306 {
307     LRESULT r;
308     SYSTEMTIME st[2];
309     SYSTEMTIME getSt[2];
310
311     /* initialize st[0] to lowest possible value */
312     fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0);
313     /* intialize st[1] to all invalid numbers */
314     fill_systime_struct(&st[1], 0, 0, 7, 0, 24, 60, 60, 1000);
315
316     r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN, (LPARAM)st);
317     expect(1, r);
318     r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
319     ok(r == GDTR_MIN, "Expected %x, not %x(GDTR_MAX) or %x(GDTR_MIN | GDTR_MAX), got %lx\n", GDTR_MIN, GDTR_MAX, GDTR_MIN | GDTR_MAX, r);
320     expect_systime(&st[0], &getSt[0]);
321
322     r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MAX, (LPARAM)st);
323     expect_unsuccess(0, r);
324
325     /* set st[0] to all invalid numbers */
326     fill_systime_struct(&st[0], 0, 0, 7, 0, 24, 60, 60, 1000);
327     /* set st[1] to highest possible value */
328     fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999);
329
330     r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MAX, (LPARAM)st);
331     expect(1, r);
332     r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
333     todo_wine {
334         ok(r == GDTR_MAX, "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MIN | GDTR_MAX), got %lx\n", GDTR_MAX, GDTR_MIN, GDTR_MIN | GDTR_MAX, r);
335     }
336     expect_systime(&st[1], &getSt[1]);
337
338     r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN, (LPARAM)st);
339     expect_unsuccess(0, r);
340     r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
341     expect_unsuccess(0, r);
342
343     /* set st[0] to highest possible value */
344     fill_systime_struct(&st[0], 30827, 12, 6, 31, 23, 59, 59, 999);
345
346     r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
347     expect(1, r);
348     r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
349     ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
350     expect_systime(&st[0], &getSt[0]);
351     expect_systime(&st[1], &getSt[1]);
352
353     /* initialize st[0] to lowest possible value */
354     fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0);
355     /* set st[1] to highest possible value */
356     fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999);
357
358     r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
359     expect(1, r);
360     r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
361     ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
362     expect_systime(&st[0], &getSt[0]);
363     expect_systime(&st[1], &getSt[1]);
364
365     /* set st[0] to value higher than minimum */
366     fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
367     /* set st[1] to value lower than maximum */
368     fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999);
369
370     r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
371     expect(1, r);
372     r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
373     ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
374     expect_systime(&st[0], &getSt[0]);
375     expect_systime(&st[1], &getSt[1]);
376
377     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_range_seq, "test_dtm_set_and_get_range", FALSE);
378     flush_sequences(sequences, NUM_MSG_SEQUENCES);
379 }
380
381 /* when max<min for DTM_SETRANGE, Windows seems to swap the min and max values,
382 although that's undocumented.  However, it doesn't seem to be implemented
383 correctly, causing some strange side effects */
384 static void test_dtm_set_range_swap_min_max(HWND hWndDateTime)
385 {
386     LRESULT r;
387     SYSTEMTIME st[2];
388     SYSTEMTIME getSt[2];
389     SYSTEMTIME origSt;
390
391     fill_systime_struct(&st[0], 2007, 2, 4, 15, 2, 2, 2, 2);
392
393     r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
394     expect(1, r);
395     r = SendMessage(hWndDateTime, DTM_GETSYSTEMTIME, 0, (LPARAM)&origSt);
396     ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
397     expect_systime(&st[0], &origSt);
398
399     /* set st[0] to value higher than st[1] */
400     fill_systime_struct(&st[0], 2007, 3, 2, 31, 23, 59, 59, 999);
401     fill_systime_struct(&st[1], 1980, 1, 3, 23, 14, 34, 37, 465);
402
403     /* since min>max, min and max values should be swapped by DTM_SETRANGE
404     automatically */
405     r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
406     expect(1, r);
407     r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
408     ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
409     todo_wine {
410         expect_systime(&st[0], &getSt[0]);
411     }
412     todo_wine {
413         expect_systime(&st[1], &getSt[1]);
414     }
415
416     fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
417
418     r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
419     expect(1, r);
420     r = SendMessage(hWndDateTime, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]);
421     ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
422     /* the time part seems to not change after swapping the min and max values
423     and doing DTM_SETSYSTEMTIME */
424     expect_systime_date(&st[0], &getSt[0]);
425     todo_wine {
426         expect_systime_time(&origSt, &getSt[0]);
427     }
428
429     /* set st[0] to value higher than minimum */
430     fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
431     /* set st[1] to value lower than maximum */
432     fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999);
433
434     r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
435     expect(1, r);
436     /* for some reason after we swapped the min and max values before,
437     whenever we do a DTM_SETRANGE, the DTM_GETRANGE will return the values
438     swapped*/
439     r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
440     ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
441     todo_wine {
442         expect_systime(&st[0], &getSt[1]);
443     }
444     todo_wine {
445         expect_systime(&st[1], &getSt[0]);
446     }
447
448     /* set st[0] to value higher than st[1] */
449     fill_systime_struct(&st[0], 2007, 3, 2, 31, 23, 59, 59, 999);
450     fill_systime_struct(&st[1], 1980, 1, 3, 23, 14, 34, 37, 465);
451
452     /* set min>max again, so that the return values of DTM_GETRANGE are no
453     longer swapped the next time we do a DTM SETRANGE and DTM_GETRANGE*/
454     r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
455     expect(1, r);
456     r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
457     ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
458     expect_systime(&st[0], &getSt[1]);
459     expect_systime(&st[1], &getSt[0]);
460
461     /* initialize st[0] to lowest possible value */
462     fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0);
463     /* set st[1] to highest possible value */
464     fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999);
465
466     r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
467     expect(1, r);
468     r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
469     ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
470     expect_systime(&st[0], &getSt[0]);
471     expect_systime(&st[1], &getSt[1]);
472
473     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_range_swap_min_max_seq, "test_dtm_set_range_swap_min_max", FALSE);
474     flush_sequences(sequences, NUM_MSG_SEQUENCES);
475 }
476
477 static void test_dtm_set_and_get_system_time(HWND hWndDateTime)
478 {
479     LRESULT r;
480     SYSTEMTIME st;
481     SYSTEMTIME getSt;
482
483     r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&st);
484     expect(1, r);
485     r = SendMessage(hWndDateTime, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
486     ok(r == GDT_NONE, "Expected %d, not %d(GDT_VALID) or %d(GDT_ERROR), got %ld\n", GDT_NONE, GDT_VALID, GDT_ERROR, r);
487
488     /* set st to lowest possible value */
489     fill_systime_struct(&st, 1601, 1, 0, 1, 0, 0, 0, 0);
490
491     r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
492     expect(1, r);
493
494     /* set st to highest possible value */
495     fill_systime_struct(&st, 30827, 12, 6, 31, 23, 59, 59, 999);
496
497     r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
498     expect(1, r);
499
500     /* set st to value between min and max */
501     fill_systime_struct(&st, 1980, 1, 3, 23, 14, 34, 37, 465);
502
503     r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
504     expect(1, r);
505     r = SendMessage(hWndDateTime, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
506     ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
507     expect_systime(&st, &getSt);
508
509     /* set st to invalid value */
510     fill_systime_struct(&st, 0, 0, 7, 0, 24, 60, 60, 1000);
511
512     todo_wine {
513         r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
514         expect_unsuccess(0, r);
515     }
516
517     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_system_time_seq, "test_dtm_set_and_get_system_time", FALSE);
518     flush_sequences(sequences, NUM_MSG_SEQUENCES);
519 }
520
521 static void test_datetime_control(void)
522 {
523     HWND hWndDateTime;
524
525     hWndDateTime = create_datetime_control(DTS_SHOWNONE, 0);
526
527     ok(hWndDateTime != NULL, "Expected non NULL, got %p\n", hWndDateTime);
528     if(hWndDateTime!=NULL) {
529         test_dtm_set_format(hWndDateTime);
530         test_dtm_set_and_get_mccolor(hWndDateTime);
531         test_dtm_set_and_get_mcfont(hWndDateTime);
532         test_dtm_get_monthcal(hWndDateTime);
533         test_dtm_set_and_get_range(hWndDateTime);
534         test_dtm_set_range_swap_min_max(hWndDateTime);
535         test_dtm_set_and_get_system_time(hWndDateTime);
536     }
537     else {
538         skip("hWndDateTime is NULL\n");
539     }
540
541     DestroyWindow(hWndDateTime);
542     ok_sequence(sequences, DATETIME_SEQ_INDEX, destroy_window_seq, "test_dtm_set_and_get_system_time", TRUE);
543 }
544
545 START_TEST(datetime)
546 {
547     INITCOMMONCONTROLSEX icex;
548
549     icex.dwSize = sizeof(icex);
550     icex.dwICC = ICC_DATE_CLASSES;
551     InitCommonControlsEx(&icex);
552     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
553
554     test_datetime_control();
555 }