From 1224cc461dc95608dfce31479cc06b503d3f32d2 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Sat, 26 Sep 2009 20:06:48 +0400 Subject: [PATCH] comctl32/monthcal: Fix timestamp storing on MCM_SETRANGE/MCM_SETSELRANGE. --- dlls/comctl32/monthcal.c | 49 +++++++++++++++++++++++++++------- dlls/comctl32/tests/monthcal.c | 30 ++++++++++++++++++++- 2 files changed, 69 insertions(+), 10 deletions(-) diff --git a/dlls/comctl32/monthcal.c b/dlls/comctl32/monthcal.c index 3aa069392ea..138962291e2 100644 --- a/dlls/comctl32/monthcal.c +++ b/dlls/comctl32/monthcal.c @@ -160,17 +160,35 @@ static inline BOOL MONTHCAL_IsDateEqual(const SYSTEMTIME *first, const SYSTEMTIM (first->wDay == second->wDay); } -/* make sure that time is valid */ -static BOOL MONTHCAL_ValidateTime(SYSTEMTIME time) +/* make sure that date fields are valid */ +static BOOL MONTHCAL_ValidateDate(const SYSTEMTIME *time) { - if(time.wMonth < 1 || time.wMonth > 12 ) return FALSE; - if(time.wDayOfWeek > 6) return FALSE; - if(time.wDay > MONTHCAL_MonthLength(time.wMonth, time.wYear)) + if(time->wMonth < 1 || time->wMonth > 12 ) return FALSE; + if(time->wDayOfWeek > 6) return FALSE; + if(time->wDay > MONTHCAL_MonthLength(time->wMonth, time->wYear)) return FALSE; return TRUE; } +/* Used in MCM_SETRANGE/MCM_SETSELRANGE to determine resulting time part. + Milliseconds are intentionaly not validated. */ +static BOOL MONTHCAL_ValidateTime(const SYSTEMTIME *time) +{ + if((time->wHour > 24) || (time->wMinute > 59) || (time->wSecond > 59)) + return FALSE; + else + return TRUE; +} + +/* Copies timestamp part only. Milliseconds are intentionaly not copied + cause it matches required behaviour for current use of this helper */ +static void MONTHCAL_CopyTime(const SYSTEMTIME *from, SYSTEMTIME *to) +{ + to->wHour = from->wHour; + to->wMinute = from->wMinute; + to->wSecond = from->wSecond; +} /* Note:Depending on DST, this may be offset by a day. Need to find out if we're on a DST place & adjust the clock accordingly. @@ -908,17 +926,23 @@ MONTHCAL_SetRange(MONTHCAL_INFO *infoPtr, SHORT limits, SYSTEMTIME *range) TRACE("%x %p\n", limits, range); - if ((limits & GDTR_MIN && !MONTHCAL_ValidateTime(range[0])) || - (limits & GDTR_MAX && !MONTHCAL_ValidateTime(range[1]))) + if ((limits & GDTR_MIN && !MONTHCAL_ValidateDate(&range[0])) || + (limits & GDTR_MAX && !MONTHCAL_ValidateDate(&range[1]))) return FALSE; if (limits & GDTR_MIN) { + if (!MONTHCAL_ValidateTime(&range[0])) + MONTHCAL_CopyTime(&infoPtr->todaysDate, &range[0]); + infoPtr->minDate = range[0]; infoPtr->rangeValid |= GDTR_MIN; } if (limits & GDTR_MAX) { + if (!MONTHCAL_ValidateTime(&range[1])) + MONTHCAL_CopyTime(&infoPtr->todaysDate, &range[1]); + infoPtr->maxDate = range[1]; infoPtr->rangeValid |= GDTR_MAX; } @@ -1003,7 +1027,7 @@ MONTHCAL_SetCurSel(MONTHCAL_INFO *infoPtr, SYSTEMTIME *curSel) if(!curSel) return FALSE; if(infoPtr->dwStyle & MCS_MULTISELECT) return FALSE; - if(!MONTHCAL_ValidateTime(*curSel)) return FALSE; + if(!MONTHCAL_ValidateDate(curSel)) return FALSE; infoPtr->minSel = *curSel; infoPtr->maxSel = *curSel; @@ -1067,8 +1091,15 @@ MONTHCAL_SetSelRange(MONTHCAL_INFO *infoPtr, SYSTEMTIME *range) if(infoPtr->dwStyle & MCS_MULTISELECT) { - infoPtr->maxSel = range[1]; + /* adjust timestamps */ + if(!MONTHCAL_ValidateTime(&range[0])) + MONTHCAL_CopyTime(&infoPtr->todaysDate, &range[0]); + if(!MONTHCAL_ValidateTime(&range[1])) + MONTHCAL_CopyTime(&infoPtr->todaysDate, &range[1]); + infoPtr->minSel = range[0]; + infoPtr->maxSel = range[1]; + TRACE("[min,max]=[%d %d]\n", infoPtr->minSel.wDay, infoPtr->maxSel.wDay); return TRUE; } diff --git a/dlls/comctl32/tests/monthcal.c b/dlls/comctl32/tests/monthcal.c index e5282ff340f..109d8a82a27 100644 --- a/dlls/comctl32/tests/monthcal.c +++ b/dlls/comctl32/tests/monthcal.c @@ -322,7 +322,7 @@ static const struct message destroy_parent_seq[] = { static void test_monthcal(void) { HWND hwnd; - SYSTEMTIME st[2], st1[2]; + SYSTEMTIME st[2], st1[2], today; int res, month_range; hwnd = CreateWindowA(MONTHCAL_CLASSA, "MonthCal", WS_POPUP | WS_VISIBLE, CW_USEDEFAULT, @@ -354,13 +354,41 @@ static void test_monthcal(void) GetSystemTime(&st[0]); st[1] = st[0]; + SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&today); + /* Invalid date/time */ st[0].wYear = 2000; /* Time should not matter */ st[1].wHour = st[1].wMinute = st[1].wSecond = 70; + st[1].wMilliseconds = 1200; ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set MAX limit\n"); + /* invalid timestamp is written back with today data and msecs untouched */ + expect(today.wHour, st[1].wHour); + expect(today.wMinute, st[1].wMinute); + expect(today.wSecond, st[1].wSecond); + expect(1200, st[1].wMilliseconds); + ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n"); ok(st1[0].wYear != 2000, "Lover limit changed\n"); + /* invalid timestamp should be replaced with today data, except msecs */ + expect(today.wHour, st1[1].wHour); + expect(today.wMinute, st1[1].wMinute); + expect(today.wSecond, st1[1].wSecond); + expect(1200, st1[1].wMilliseconds); + + /* Invalid date/time with invalid milliseconds only */ + GetSystemTime(&st[0]); + st[1] = st[0]; + /* Time should not matter */ + st[1].wMilliseconds = 1200; + ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set MAX limit\n"); + /* invalid milliseconds field doesn't lead to invalid timestamp */ + expect(st[0].wHour, st[1].wHour); + expect(st[0].wMinute, st[1].wMinute); + expect(st[0].wSecond, st[1].wSecond); + expect(1200, st[1].wMilliseconds); + + GetSystemTime(&st[0]); st[1].wMonth = 0; ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Should have failed to set limits\n");