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 #include "v6util.h" 26 27 #define expect(EXPECTED, GOT) ok((GOT)==(EXPECTED), "Expected %d, got %ld\n", (EXPECTED), (GOT)) 28 29 #define expect_unsuccess(EXPECTED, GOT) ok((GOT)==(EXPECTED), "Expected %d(unsuccessful), got %ld(successful)\n", (EXPECTED), (GOT)) 30 31 #define NUM_MSG_SEQUENCES 1 32 #define DATETIME_SEQ_INDEX 0 33 34 static BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); 35 36 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES]; 37 38 static const struct message test_dtm_set_format_seq[] = { 39 { DTM_SETFORMATA, sent|wparam|lparam, 0, 0 }, 40 { DTM_SETFORMATA, sent|wparam, 0 }, 41 { 0 } 42 }; 43 44 static const struct message test_dtm_set_and_get_mccolor_seq[] = { 45 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0 }, 46 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(255, 255, 255) }, 47 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(100, 180, 220) }, 48 { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0 }, 49 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0 }, 50 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(255, 255, 255) }, 51 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(100, 180, 220) }, 52 { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0 }, 53 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TEXT, 0 }, 54 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(255, 255, 255) }, 55 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(100, 180, 220) }, 56 { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_TEXT, 0 }, 57 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0 }, 58 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(255, 255, 255) }, 59 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(100, 180, 220) }, 60 { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0 }, 61 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0 }, 62 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(255, 255, 255) }, 63 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(100, 180, 220) }, 64 { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0 }, 65 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0 }, 66 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(255, 255, 255) }, 67 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(100, 180, 220) }, 68 { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0 }, 69 { 0 } 70 }; 71 72 static const struct message test_dtm_set_and_get_mcfont_seq[] = { 73 { DTM_SETMCFONT, sent|lparam, 0, 1 }, 74 { DTM_GETMCFONT, sent|wparam|lparam, 0, 0 }, 75 { 0 } 76 }; 77 78 static const struct message test_dtm_get_monthcal_seq[] = { 79 { DTM_GETMONTHCAL, sent|wparam|lparam, 0, 0 }, 80 { 0 } 81 }; 82 83 static const struct message test_dtm_set_and_get_range_seq[] = { 84 { DTM_SETRANGE, sent|wparam, GDTR_MIN }, 85 { DTM_GETRANGE, sent|wparam, 0 }, 86 { DTM_SETRANGE, sent|wparam, GDTR_MAX }, 87 { DTM_SETRANGE, sent|wparam, GDTR_MAX }, 88 { DTM_GETRANGE, sent|wparam, 0 }, 89 { DTM_SETRANGE, sent|wparam, GDTR_MIN }, 90 { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX }, 91 { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX }, 92 { DTM_GETRANGE, sent|wparam, 0 }, 93 { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX }, 94 { DTM_GETRANGE, sent|wparam, 0 }, 95 { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX }, 96 { DTM_GETRANGE, sent|wparam, 0 }, 97 { 0 } 98 }; 99 100 static const struct message test_dtm_set_range_swap_min_max_seq[] = { 101 { DTM_SETSYSTEMTIME, sent|wparam, 0 }, 102 { DTM_GETSYSTEMTIME, sent|wparam, 0 }, 103 { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX }, 104 { DTM_GETRANGE, sent|wparam, 0 }, 105 { DTM_SETSYSTEMTIME, sent|wparam, 0 }, 106 { DTM_GETSYSTEMTIME, sent|wparam, 0 }, 107 { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX }, 108 { DTM_GETRANGE, sent|wparam, 0 }, 109 { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX }, 110 { DTM_GETRANGE, sent|wparam, 0 }, 111 { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX }, 112 { DTM_GETRANGE, sent|wparam, 0 }, 113 { 0 } 114 }; 115 116 static const struct message test_dtm_set_and_get_system_time_seq[] = { 117 { DTM_SETSYSTEMTIME, sent|wparam, GDT_NONE }, 118 { DTM_GETSYSTEMTIME, sent|wparam, 0 }, 119 { DTM_SETSYSTEMTIME, sent|wparam, 0 }, 120 { DTM_SETSYSTEMTIME, sent|wparam, 0 }, 121 { DTM_SETSYSTEMTIME, sent|wparam, 0 }, 122 { DTM_GETSYSTEMTIME, sent|wparam, 0 }, 123 { DTM_SETSYSTEMTIME, sent|wparam, 0 }, 124 { 0 } 125 }; 126 127 static const struct message test_dtm_set_and_get_systime_with_limits[] = { 128 { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX }, 129 { DTM_GETRANGE, sent|wparam, 0 }, 130 { DTM_SETSYSTEMTIME, sent|wparam, 0 }, 131 { DTM_GETSYSTEMTIME, sent|wparam, 0 }, 132 { DTM_SETSYSTEMTIME, sent|wparam, 0 }, 133 { DTM_GETSYSTEMTIME, sent|wparam, 0 }, 134 { DTM_SETSYSTEMTIME, sent|wparam, 0 }, 135 { DTM_GETSYSTEMTIME, sent|wparam, 0 }, 136 { 0 } 137 }; 138 139 static LRESULT WINAPI datetime_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 140 { 141 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); 142 static LONG defwndproc_counter = 0; 143 struct message msg = { 0 }; 144 LRESULT ret; 145 146 msg.message = message; 147 msg.flags = sent|wparam|lparam; 148 if (defwndproc_counter) msg.flags |= defwinproc; 149 msg.wParam = wParam; 150 msg.lParam = lParam; 151 add_message(sequences, DATETIME_SEQ_INDEX, &msg); 152 153 defwndproc_counter++; 154 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); 155 defwndproc_counter--; 156 157 return ret; 158 } 159 160 static HWND create_datetime_control(DWORD style) 161 { 162 WNDPROC oldproc; 163 HWND hWndDateTime = NULL; 164 165 hWndDateTime = CreateWindowExA(0, 166 DATETIMEPICK_CLASSA, 167 NULL, 168 style, 169 0,50,300,120, 170 NULL, 171 NULL, 172 NULL, 173 NULL); 174 175 if (!hWndDateTime) return NULL; 176 177 oldproc = (WNDPROC)SetWindowLongPtrA(hWndDateTime, GWLP_WNDPROC, 178 (LONG_PTR)datetime_subclass_proc); 179 SetWindowLongPtrA(hWndDateTime, GWLP_USERDATA, (LONG_PTR)oldproc); 180 181 return hWndDateTime; 182 } 183 184 static void test_dtm_set_format(void) 185 { 186 HWND hWnd; 187 CHAR txt[256]; 188 SYSTEMTIME systime; 189 LRESULT r; 190 191 hWnd = create_datetime_control(DTS_SHOWNONE); 192 193 flush_sequences(sequences, NUM_MSG_SEQUENCES); 194 195 r = SendMessageA(hWnd, DTM_SETFORMATA, 0, 0); 196 expect(1, r); 197 198 r = SendMessageA(hWnd, DTM_SETFORMATA, 0, 199 (LPARAM)"'Today is: 'hh':'m':'s dddd MMM dd', 'yyyy"); 200 expect(1, r); 201 202 ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_format_seq, "test_dtm_set_format", FALSE); 203 204 r = SendMessageA(hWnd, DTM_SETFORMATA, 0, (LPARAM)"'hh' hh"); 205 expect(1, r); 206 ZeroMemory(&systime, sizeof(systime)); 207 systime.wYear = 2000; 208 systime.wMonth = systime.wDay = 1; 209 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, 0, (LPARAM)&systime); 210 expect(1, r); 211 GetWindowTextA(hWnd, txt, 256); 212 ok(strcmp(txt, "hh 12") == 0, "String mismatch (\"%s\" vs \"hh 12\")\n", txt); 213 214 DestroyWindow(hWnd); 215 } 216 217 static void test_mccolor_types(HWND hWndDateTime, int mccolor_type, const char* mccolor_name) 218 { 219 COLORREF theColor, prevColor, crColor; 220 221 theColor=RGB(0,0,0); 222 crColor = SendMessageA(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor); 223 ok(crColor != ~0u, "%s: Set RGB(0,0,0): Expected COLORREF of previous value, got %d\n", mccolor_name, crColor); 224 prevColor=theColor; 225 theColor=RGB(255,255,255); 226 crColor = SendMessageA(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor); 227 ok(crColor==prevColor, "%s: Set RGB(255,255,255): Expected COLORREF of previous value, got %d\n", mccolor_name, crColor); 228 prevColor=theColor; 229 theColor=RGB(100,180,220); 230 crColor = SendMessageA(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor); 231 ok(crColor==prevColor, "%s: Set RGB(100,180,220): Expected COLORREF of previous value, got %d\n", mccolor_name, crColor); 232 crColor = SendMessageA(hWndDateTime, DTM_GETMCCOLOR, mccolor_type, 0); 233 ok(crColor==theColor, "%s: GETMCCOLOR: Expected %d, got %d\n", mccolor_name, theColor, crColor); 234 } 235 236 static void test_dtm_set_and_get_mccolor(void) 237 { 238 HWND hWnd; 239 240 hWnd = create_datetime_control(DTS_SHOWNONE); 241 242 flush_sequences(sequences, NUM_MSG_SEQUENCES); 243 244 test_mccolor_types(hWnd, MCSC_BACKGROUND, "MCSC_BACKGROUND"); 245 test_mccolor_types(hWnd, MCSC_MONTHBK, "MCSC_MONTHBK"); 246 test_mccolor_types(hWnd, MCSC_TEXT, "MCSC_TEXT"); 247 test_mccolor_types(hWnd, MCSC_TITLEBK, "MCSC_TITLEBK"); 248 test_mccolor_types(hWnd, MCSC_TITLETEXT, "MCSC_TITLETEXT"); 249 test_mccolor_types(hWnd, MCSC_TRAILINGTEXT, "MCSC_TRAILINGTEXT"); 250 251 ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_mccolor_seq, "test_dtm_set_and_get_mccolor", FALSE); 252 253 DestroyWindow(hWnd); 254 } 255 256 static void test_dtm_set_and_get_mcfont(void) 257 { 258 HFONT hFontOrig, hFontNew; 259 HWND hWnd; 260 261 hWnd = create_datetime_control(DTS_SHOWNONE); 262 263 flush_sequences(sequences, NUM_MSG_SEQUENCES); 264 265 hFontOrig = GetStockObject(DEFAULT_GUI_FONT); 266 SendMessageA(hWnd, DTM_SETMCFONT, (WPARAM)hFontOrig, TRUE); 267 hFontNew = (HFONT)SendMessageA(hWnd, DTM_GETMCFONT, 0, 0); 268 ok(hFontOrig == hFontNew, "Expected hFontOrig==hFontNew, hFontOrig=%p, hFontNew=%p\n", hFontOrig, hFontNew); 269 270 ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_mcfont_seq, "test_dtm_set_and_get_mcfont", FALSE); 271 DestroyWindow(hWnd); 272 } 273 274 static void test_dtm_get_monthcal(void) 275 { 276 LRESULT r; 277 HWND hWnd; 278 279 hWnd = create_datetime_control(DTS_SHOWNONE); 280 281 flush_sequences(sequences, NUM_MSG_SEQUENCES); 282 283 todo_wine { 284 r = SendMessageA(hWnd, DTM_GETMONTHCAL, 0, 0); 285 ok(r == 0, "Expected NULL(no child month calendar control), got %ld\n", r); 286 } 287 288 ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_get_monthcal_seq, "test_dtm_get_monthcal", FALSE); 289 DestroyWindow(hWnd); 290 } 291 292 static void fill_systime_struct(SYSTEMTIME *st, int year, int month, int dayofweek, int day, int hour, int minute, int second, int milliseconds) 293 { 294 st->wYear = year; 295 st->wMonth = month; 296 st->wDayOfWeek = dayofweek; 297 st->wDay = day; 298 st->wHour = hour; 299 st->wMinute = minute; 300 st->wSecond = second; 301 st->wMilliseconds = milliseconds; 302 } 303 304 static LPARAM compare_systime_date(SYSTEMTIME *st1, SYSTEMTIME *st2) 305 { 306 return (st1->wYear == st2->wYear) 307 && (st1->wMonth == st2->wMonth) 308 && (st1->wDayOfWeek == st2->wDayOfWeek) 309 && (st1->wDay == st2->wDay); 310 } 311 312 static LPARAM compare_systime_time(SYSTEMTIME *st1, SYSTEMTIME *st2) 313 { 314 return (st1->wHour == st2->wHour) 315 && (st1->wMinute == st2->wMinute) 316 && (st1->wSecond == st2->wSecond) 317 && (st1->wMilliseconds == st2->wMilliseconds); 318 } 319 320 static LPARAM compare_systime(SYSTEMTIME *st1, SYSTEMTIME *st2) 321 { 322 if(!compare_systime_date(st1, st2)) 323 return 0; 324 325 return compare_systime_time(st1, st2); 326 } 327 328 #define expect_systime(ST1, ST2) ok(compare_systime((ST1), (ST2))==1, "ST1 != ST2\n") 329 #define expect_systime_date(ST1, ST2) ok(compare_systime_date((ST1), (ST2))==1, "ST1.date != ST2.date\n") 330 #define expect_systime_time(ST1, ST2) ok(compare_systime_time((ST1), (ST2))==1, "ST1.time != ST2.time\n") 331 332 static void test_dtm_set_and_get_range(void) 333 { 334 LRESULT r; 335 SYSTEMTIME st[2]; 336 SYSTEMTIME getSt[2]; 337 HWND hWnd; 338 339 hWnd = create_datetime_control(DTS_SHOWNONE); 340 341 flush_sequences(sequences, NUM_MSG_SEQUENCES); 342 343 /* initialize st[0] to lowest possible value */ 344 fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0); 345 /* initialize st[1] to all invalid numbers */ 346 fill_systime_struct(&st[1], 0, 0, 7, 0, 24, 60, 60, 1000); 347 348 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN, (LPARAM)st); 349 expect(1, r); 350 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt); 351 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); 352 expect_systime(&st[0], &getSt[0]); 353 354 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MAX, (LPARAM)st); 355 expect_unsuccess(0, r); 356 357 /* set st[0] to all invalid numbers */ 358 fill_systime_struct(&st[0], 0, 0, 7, 0, 24, 60, 60, 1000); 359 /* set st[1] to highest possible value */ 360 fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999); 361 362 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MAX, (LPARAM)st); 363 expect(1, r); 364 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt); 365 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); 366 expect_systime(&st[1], &getSt[1]); 367 368 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN, (LPARAM)st); 369 expect_unsuccess(0, r); 370 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); 371 expect_unsuccess(0, r); 372 373 /* set st[0] to highest possible value */ 374 fill_systime_struct(&st[0], 30827, 12, 6, 31, 23, 59, 59, 999); 375 376 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); 377 expect(1, r); 378 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt); 379 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); 380 expect_systime(&st[0], &getSt[0]); 381 expect_systime(&st[1], &getSt[1]); 382 383 /* initialize st[0] to lowest possible value */ 384 fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0); 385 /* set st[1] to highest possible value */ 386 fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999); 387 388 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); 389 expect(1, r); 390 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt); 391 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); 392 expect_systime(&st[0], &getSt[0]); 393 expect_systime(&st[1], &getSt[1]); 394 395 /* set st[0] to value higher than minimum */ 396 fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465); 397 /* set st[1] to value lower than maximum */ 398 fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999); 399 400 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); 401 expect(1, r); 402 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt); 403 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); 404 expect_systime(&st[0], &getSt[0]); 405 expect_systime(&st[1], &getSt[1]); 406 407 ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_range_seq, "test_dtm_set_and_get_range", FALSE); 408 409 /* DTM_SETRANGE with 0 flags */ 410 r = SendMessageA(hWnd, DTM_SETRANGE, 0, (LPARAM)st); 411 ok(r, "got %lu\n", r); 412 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt); 413 ok(r == 0, "got %lu\n", r); 414 ok(getSt[0].wYear == 0 && getSt[1].wYear == 0, "got %u, %u\n", getSt[0].wYear, getSt[1].wYear); 415 416 DestroyWindow(hWnd); 417 } 418 419 /* when max<min for DTM_SETRANGE, Windows seems to swap the min and max values, 420 although that's undocumented. However, it doesn't seem to be implemented 421 correctly, causing some strange side effects */ 422 static void test_dtm_set_range_swap_min_max(void) 423 { 424 LRESULT r; 425 SYSTEMTIME st[2]; 426 SYSTEMTIME getSt[2]; 427 SYSTEMTIME origSt; 428 HWND hWnd; 429 430 hWnd = create_datetime_control(DTS_SHOWNONE); 431 flush_sequences(sequences, NUM_MSG_SEQUENCES); 432 433 fill_systime_struct(&st[0], 2007, 2, 4, 15, 2, 2, 2, 2); 434 435 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]); 436 expect(1, r); 437 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&origSt); 438 ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r); 439 expect_systime(&st[0], &origSt); 440 441 /* set st[0] to value higher than st[1] */ 442 fill_systime_struct(&st[0], 2007, 3, 2, 31, 23, 59, 59, 999); 443 fill_systime_struct(&st[1], 1980, 1, 3, 23, 14, 34, 37, 465); 444 445 /* since min>max, min and max values should be swapped by DTM_SETRANGE 446 automatically */ 447 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); 448 expect(1, r); 449 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt); 450 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); 451 todo_wine { 452 ok(compare_systime(&st[0], &getSt[0]) == 1 || 453 broken(compare_systime(&st[0], &getSt[1]) == 1), /* comctl32 version <= 5.80 */ 454 "ST1 != ST2\n"); 455 456 ok(compare_systime(&st[1], &getSt[1]) == 1 || 457 broken(compare_systime(&st[1], &getSt[0]) == 1), /* comctl32 version <= 5.80 */ 458 "ST1 != ST2\n"); 459 } 460 461 fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465); 462 463 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]); 464 expect(1, r); 465 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]); 466 ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r); 467 /* the time part seems to not change after swapping the min and max values 468 and doing DTM_SETSYSTEMTIME */ 469 expect_systime_date(&st[0], &getSt[0]); 470 todo_wine { 471 ok(compare_systime_time(&origSt, &getSt[0]) == 1 || 472 broken(compare_systime_time(&st[0], &getSt[0]) == 1), /* comctl32 version <= 5.80 */ 473 "ST1.time != ST2.time\n"); 474 } 475 476 /* set st[0] to value higher than minimum */ 477 fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465); 478 /* set st[1] to value lower than maximum */ 479 fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999); 480 481 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); 482 expect(1, r); 483 /* for some reason after we swapped the min and max values before, 484 whenever we do a DTM_SETRANGE, the DTM_GETRANGE will return the values 485 swapped*/ 486 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt); 487 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); 488 todo_wine { 489 ok(compare_systime(&st[0], &getSt[1]) == 1 || 490 broken(compare_systime(&st[0], &getSt[0]) == 1), /* comctl32 version <= 5.80 */ 491 "ST1 != ST2\n"); 492 493 ok(compare_systime(&st[1], &getSt[0]) == 1 || 494 broken(compare_systime(&st[1], &getSt[1]) == 1), /* comctl32 version <= 5.80 */ 495 "ST1 != ST2\n"); 496 } 497 498 /* set st[0] to value higher than st[1] */ 499 fill_systime_struct(&st[0], 2007, 3, 2, 31, 23, 59, 59, 999); 500 fill_systime_struct(&st[1], 1980, 1, 3, 23, 14, 34, 37, 465); 501 502 /* set min>max again, so that the return values of DTM_GETRANGE are no 503 longer swapped the next time we do a DTM SETRANGE and DTM_GETRANGE*/ 504 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); 505 expect(1, r); 506 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt); 507 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); 508 expect_systime(&st[0], &getSt[1]); 509 expect_systime(&st[1], &getSt[0]); 510 511 /* initialize st[0] to lowest possible value */ 512 fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0); 513 /* set st[1] to highest possible value */ 514 fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999); 515 516 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); 517 expect(1, r); 518 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt); 519 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); 520 expect_systime(&st[0], &getSt[0]); 521 expect_systime(&st[1], &getSt[1]); 522 523 ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_range_swap_min_max_seq, "test_dtm_set_range_swap_min_max", FALSE); 524 525 DestroyWindow(hWnd); 526 } 527 528 static void test_dtm_set_and_get_system_time(void) 529 { 530 LRESULT r; 531 SYSTEMTIME st, getSt, ref; 532 HWND hWnd; 533 534 hWnd = create_datetime_control(0); 535 ok(hWnd !=NULL, "Expected non NULL, got %p\n", hWnd); 536 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&st); 537 expect(0, r); 538 539 DestroyWindow(hWnd); 540 541 hWnd = create_datetime_control(DTS_SHOWNONE); 542 flush_sequences(sequences, NUM_MSG_SEQUENCES); 543 544 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&st); 545 expect(1, r); 546 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); 547 ok(r == GDT_NONE, "Expected %d, not %d(GDT_VALID) or %d(GDT_ERROR), got %ld\n", GDT_NONE, GDT_VALID, GDT_ERROR, r); 548 549 /* set st to lowest possible value */ 550 fill_systime_struct(&st, 1601, 1, 0, 1, 0, 0, 0, 0); 551 552 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); 553 expect(1, r); 554 555 /* set st to highest possible value */ 556 fill_systime_struct(&st, 30827, 12, 6, 31, 23, 59, 59, 999); 557 558 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); 559 expect(1, r); 560 561 /* set st to value between min and max */ 562 fill_systime_struct(&st, 1980, 1, 3, 23, 14, 34, 37, 465); 563 564 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); 565 expect(1, r); 566 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); 567 ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r); 568 expect_systime(&st, &getSt); 569 570 /* set st to invalid value */ 571 fill_systime_struct(&st, 0, 0, 7, 0, 24, 60, 60, 1000); 572 573 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); 574 expect_unsuccess(0, r); 575 576 ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_system_time_seq, "test_dtm_set_and_get_system_time", FALSE); 577 578 /* set to some valid value */ 579 GetSystemTime(&ref); 580 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&ref); 581 expect(1, r); 582 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); 583 expect(GDT_VALID, r); 584 expect_systime(&ref, &getSt); 585 586 /* year invalid */ 587 st = ref; 588 st.wYear = 0; 589 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); 590 todo_wine expect(1, r); 591 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); 592 expect(GDT_VALID, r); 593 expect_systime(&ref, &getSt); 594 /* month invalid */ 595 st = ref; 596 st.wMonth = 13; 597 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); 598 expect(0, r); 599 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); 600 expect(GDT_VALID, r); 601 expect_systime(&ref, &getSt); 602 /* day invalid */ 603 st = ref; 604 st.wDay = 32; 605 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); 606 expect(0, r); 607 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); 608 expect(GDT_VALID, r); 609 expect_systime(&ref, &getSt); 610 /* day invalid for current month */ 611 st = ref; 612 st.wDay = 30; 613 st.wMonth = 2; 614 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); 615 expect(0, r); 616 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); 617 expect(GDT_VALID, r); 618 expect_systime(&ref, &getSt); 619 /* day of week isn't validated */ 620 st = ref; 621 st.wDayOfWeek = 10; 622 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); 623 expect(1, r); 624 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); 625 expect(GDT_VALID, r); 626 expect_systime(&ref, &getSt); 627 /* hour invalid */ 628 st = ref; 629 st.wHour = 25; 630 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); 631 expect(0, r); 632 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); 633 expect(GDT_VALID, r); 634 expect_systime(&ref, &getSt); 635 /* minute invalid */ 636 st = ref; 637 st.wMinute = 60; 638 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); 639 expect(0, r); 640 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); 641 expect(GDT_VALID, r); 642 expect_systime(&ref, &getSt); 643 /* sec invalid */ 644 st = ref; 645 st.wSecond = 60; 646 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); 647 expect(0, r); 648 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); 649 expect(GDT_VALID, r); 650 expect_systime(&ref, &getSt); 651 /* msec invalid */ 652 st = ref; 653 st.wMilliseconds = 1000; 654 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); 655 expect(0, r); 656 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); 657 expect(GDT_VALID, r); 658 expect_systime(&ref, &getSt); 659 660 /* day of week should be calculated automatically, 661 actual day of week for this date is 4 */ 662 fill_systime_struct(&st, 2009, 10, 1, 1, 0, 0, 10, 200); 663 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st); 664 expect(1, r); 665 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt); 666 expect(GDT_VALID, r); 667 /* 01.10.2009 is Thursday */ 668 expect(4, (LRESULT)getSt.wDayOfWeek); 669 st.wDayOfWeek = 4; 670 expect_systime(&st, &getSt); 671 } 672 673 static void test_dtm_set_and_get_systemtime_with_limits(void) 674 { 675 LRESULT r; 676 SYSTEMTIME st[2], getSt[2], refSt; 677 HWND hWnd; 678 679 hWnd = create_datetime_control(DTS_SHOWNONE); 680 681 flush_sequences(sequences, NUM_MSG_SEQUENCES); 682 683 /* set range */ 684 fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465); 685 fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999); 686 687 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); 688 expect(1, r); 689 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt); 690 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); 691 expect_systime(&st[0], &getSt[0]); 692 expect_systime(&st[1], &getSt[1]); 693 694 /* Initially set a valid time */ 695 fill_systime_struct(&refSt, 1999, 9, 4, 9, 19, 9, 9, 999); 696 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&refSt); 697 expect(1, r); 698 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]); 699 ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r); 700 expect_systime(&refSt, &getSt[0]); 701 702 /* Now set an out-of-bounds time */ 703 fill_systime_struct(&st[0], 2010, 1, 0, 1, 0, 0, 0, 0); 704 705 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]); 706 expect(1, r); 707 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]); 708 ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r); 709 expect_systime(&refSt, &getSt[0]); 710 711 fill_systime_struct(&st[0], 1977, 1, 0, 1, 0, 0, 0, 0); 712 713 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]); 714 expect(1, r); 715 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]); 716 ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r); 717 expect_systime(&refSt, &getSt[0]); 718 719 ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_systime_with_limits, "test_dtm_set_and_get_systime_with_limits", FALSE); 720 721 DestroyWindow(hWnd); 722 } 723 724 static void test_dtm_get_ideal_size(void) 725 { 726 HWND hwnd; 727 HDC hdc; 728 HFONT hfont; 729 LOGFONTA lf; 730 TEXTMETRICA tm; 731 SIZE size; 732 BOOL r; 733 734 hwnd = create_datetime_control(0); 735 r = SendMessageA(hwnd, DTM_GETIDEALSIZE, 0, (LPARAM)&size); 736 if (!r) 737 { 738 win_skip("DTM_GETIDEALSIZE is not available\n"); 739 DestroyWindow(hwnd); 740 return; 741 } 742 743 /* Set font so that the test is consistent on Wine and Windows */ 744 ZeroMemory(&lf, sizeof(lf)); 745 lf.lfWeight = FW_NORMAL; 746 lf.lfHeight = 20; 747 lstrcpyA(lf.lfFaceName, "Tahoma"); 748 hfont = CreateFontIndirectA(&lf); 749 SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE); 750 751 hdc = GetDC(hwnd); 752 GetTextMetricsA(hdc, &tm); 753 ReleaseDC(hwnd, hdc); 754 755 r = SendMessageA(hwnd, DTM_GETIDEALSIZE, 0, (LPARAM)&size); 756 ok(r, "Expect DTM_GETIDEALSIZE message to return true\n"); 757 ok(size.cx > 0 && size.cy >= tm.tmHeight, 758 "Expect size.cx > 0 and size.cy >= %d, got cx:%d cy:%d\n", tm.tmHeight, size.cx, size.cy); 759 760 DestroyWindow(hwnd); 761 DeleteObject(hfont); 762 } 763 764 static void test_wm_set_get_text(void) 765 { 766 static const CHAR a_str[] = "a"; 767 CHAR buff[16], time[16], caltype[3]; 768 HWND hWnd; 769 LRESULT ret; 770 771 hWnd = create_datetime_control(0); 772 773 ret = SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)a_str); 774 ok(CB_ERR == ret || 775 broken(0 == ret) || /* comctl32 <= 4.72 */ 776 broken(1 == ret), /* comctl32 <= 4.70 */ 777 "Expected CB_ERR, got %ld\n", ret); 778 779 buff[0] = 0; 780 ret = SendMessageA(hWnd, WM_GETTEXT, sizeof(buff), (LPARAM)buff); 781 ok(strcmp(buff, a_str) != 0, "Expected text to change, got %s\n", buff); 782 ok(ret != 0, "Expected non-zero return value\n"); 783 784 SetLastError(0xdeadbeef); 785 ret = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ICALENDARTYPE, caltype, 3); 786 if (ret == 0) 787 skip("Must know local calendar type (%x)\n", GetLastError()); 788 else if (atoi(caltype) != CAL_GREGORIAN) 789 skip("DateTimePicker Control only supports Gregorian calendar (type: %s)\n", caltype); 790 else { 791 SetLastError(0xdeadbeef); 792 ret = GetDateFormatA(LOCALE_USER_DEFAULT, 0, NULL, NULL, time, sizeof(time)); 793 if (ret == 0) 794 skip("GetDateFormat failed, returned %ld, error %d\n", ret, GetLastError()); 795 else 796 ok(!strcmp(buff, time), "Expected %s, got %s\n", time, buff); 797 } 798 799 DestroyWindow(hWnd); 800 } 801 802 static void test_dts_shownone(void) 803 { 804 HWND hwnd; 805 DWORD style; 806 807 /* it isn't allowed to change DTS_SHOWNONE after creation */ 808 hwnd = create_datetime_control(0); 809 style = GetWindowLongA(hwnd, GWL_STYLE); 810 SetWindowLongA(hwnd, GWL_STYLE, style | DTS_SHOWNONE); 811 style = GetWindowLongA(hwnd, GWL_STYLE); 812 ok(!(style & DTS_SHOWNONE), "Expected DTS_SHOWNONE not to be set\n"); 813 DestroyWindow(hwnd); 814 815 hwnd = create_datetime_control(DTS_SHOWNONE); 816 style = GetWindowLongA(hwnd, GWL_STYLE); 817 SetWindowLongA(hwnd, GWL_STYLE, style & ~DTS_SHOWNONE); 818 style = GetWindowLongA(hwnd, GWL_STYLE); 819 ok(style & DTS_SHOWNONE, "Expected DTS_SHOWNONE to be set\n"); 820 DestroyWindow(hwnd); 821 } 822 823 static void init_functions(void) 824 { 825 HMODULE hComCtl32 = LoadLibraryA("comctl32.dll"); 826 827 #define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f); 828 X(InitCommonControlsEx); 829 #undef X 830 } 831 832 START_TEST(datetime) 833 { 834 INITCOMMONCONTROLSEX iccex; 835 ULONG_PTR cookie; 836 HANDLE ctxt; 837 838 init_functions(); 839 840 iccex.dwSize = sizeof(iccex); 841 iccex.dwICC = ICC_DATE_CLASSES; 842 pInitCommonControlsEx(&iccex); 843 844 init_msg_sequences(sequences, NUM_MSG_SEQUENCES); 845 846 test_dtm_set_format(); 847 test_dtm_set_and_get_mccolor(); 848 test_dtm_set_and_get_mcfont(); 849 test_dtm_get_monthcal(); 850 test_dtm_set_and_get_range(); 851 test_dtm_set_range_swap_min_max(); 852 test_dtm_set_and_get_system_time(); 853 test_dtm_set_and_get_systemtime_with_limits(); 854 test_wm_set_get_text(); 855 test_dts_shownone(); 856 857 if (!load_v6_module(&cookie, &ctxt)) 858 return; 859 860 test_dtm_set_format(); 861 test_dtm_set_and_get_mccolor(); 862 test_dtm_set_and_get_mcfont(); 863 test_dtm_get_monthcal(); 864 test_dtm_get_ideal_size(); 865 test_wm_set_get_text(); 866 test_dts_shownone(); 867 868 unload_v6_module(cookie, ctxt); 869 } 870