From f65c2f1d636b16f2b613ab0da49104b42c607a07 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Mon, 5 Oct 2009 20:29:31 +0400 Subject: [PATCH] comctl32/monthcal: Check configured selection range max width in MCM_SETSELRANGE handler. --- dlls/comctl32/monthcal.c | 108 ++++++++++++++++++++------------- dlls/comctl32/tests/monthcal.c | 27 +++++++++ 2 files changed, 94 insertions(+), 41 deletions(-) diff --git a/dlls/comctl32/monthcal.c b/dlls/comctl32/monthcal.c index 9c25472991b..cccdaf3d1da 100644 --- a/dlls/comctl32/monthcal.c +++ b/dlls/comctl32/monthcal.c @@ -258,6 +258,66 @@ static BOOL MONTHCAL_IsDateInValidRange(const MONTHCAL_INFO *infoPtr, const SYST return TRUE; } +/* Checks passed range width with configured maximum selection count + * + * PARAMETERS + * + * [I] infoPtr : valid pointer to control data + * [I] range0 : pointer to valid date data (requested bound) + * [I] range1 : pointer to valid date data (primary bound) + * [O] adjust : returns adjusted range bound to fit maximum range (optional) + * + * Adjust value computed basing on primary bound and current maximum selection + * count. For simple range check (without adjusted value required) (range0, range1) + * relation means nothing. + * + * RETURN VALUE + * + * TRUE - range is shorter or equal to maximum + * FALSE - range is larger than maximum + */ +static BOOL MONTHCAL_IsSelRangeValid(const MONTHCAL_INFO *infoPtr, + const SYSTEMTIME *range0, + const SYSTEMTIME *range1, + SYSTEMTIME *adjust) +{ + ULARGE_INTEGER ul_range0, ul_range1, ul_diff; + FILETIME ft_range0, ft_range1; + LONG cmp; + + SystemTimeToFileTime(range0, &ft_range0); + SystemTimeToFileTime(range1, &ft_range1); + + ul_range0.LowPart = ft_range0.dwLowDateTime; + ul_range0.HighPart = ft_range0.dwHighDateTime; + ul_range1.LowPart = ft_range1.dwLowDateTime; + ul_range1.HighPart = ft_range1.dwHighDateTime; + + cmp = CompareFileTime(&ft_range0, &ft_range1); + + if(cmp == 1) + ul_diff.QuadPart = ul_range0.QuadPart - ul_range1.QuadPart; + else + ul_diff.QuadPart = -ul_range0.QuadPart + ul_range1.QuadPart; + + if(ul_diff.QuadPart >= DAYSTO100NSECS(infoPtr->maxSelCount)) { + + if(adjust) { + if(cmp == 1) + ul_range0.QuadPart = ul_range1.QuadPart + DAYSTO100NSECS(infoPtr->maxSelCount - 1); + else + ul_range0.QuadPart = ul_range1.QuadPart - DAYSTO100NSECS(infoPtr->maxSelCount - 1); + + ft_range0.dwLowDateTime = ul_range0.LowPart; + ft_range0.dwHighDateTime = ul_range0.HighPart; + FileTimeToSystemTime(&ft_range0, adjust); + } + + return FALSE; + } + else 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) @@ -1249,6 +1309,9 @@ MONTHCAL_SetSelRange(MONTHCAL_INFO *infoPtr, SYSTEMTIME *range) if(!MONTHCAL_ValidateTime(&range[1])) MONTHCAL_CopyTime(&infoPtr->todaysDate, &range[1]); + /* maximum range exceeded */ + if(!MONTHCAL_IsSelRangeValid(infoPtr, &range[0], &range[1], NULL)) return FALSE; + old_range[0] = infoPtr->minSel; old_range[1] = infoPtr->maxSel; @@ -1825,22 +1888,17 @@ MONTHCAL_MouseMove(MONTHCAL_INFO *infoPtr, LPARAM lParam) if(infoPtr->dwStyle & MCS_MULTISELECT) { SYSTEMTIME st[2]; - FILETIME ft_ht, ft_first; - ULARGE_INTEGER ul_ht, ul_first, ul_diff; int i; LONG cmp; MONTHCAL_GetSelRange(infoPtr, st); i = MONTHCAL_IsDateEqual(&infoPtr->firstSel, &st[0]) ? 1 : 0; - SystemTimeToFileTime(&st_ht, &ft_ht); - SystemTimeToFileTime(&infoPtr->firstSel, &ft_first); - - cmp = CompareFileTime(&ft_ht, &ft_first); + cmp = MONTHCAL_CompareSystemTime(&st_ht, &infoPtr->firstSel); if(MONTHCAL_IsDateEqual(&infoPtr->firstSel, &st[1])) { /* If we're still at the first selected date and range is empty, return. - If range isn't empty we should change range to a singel firstSel */ + If range isn't empty we should change range to a single firstSel */ if(MONTHCAL_IsDateEqual(&infoPtr->firstSel, &st_ht) && MONTHCAL_IsDateEqual(&st[0], &st[1])) goto done; @@ -1848,46 +1906,14 @@ MONTHCAL_MouseMove(MONTHCAL_INFO *infoPtr, LPARAM lParam) if(cmp == -1) i = 0; } - ul_ht.LowPart = ft_ht.dwLowDateTime; - ul_ht.HighPart = ft_ht.dwHighDateTime; - ul_first.LowPart = ft_first.dwLowDateTime; - ul_first.HighPart = ft_first.dwHighDateTime; - - /* new selected date is later */ - if(cmp == 1) - ul_diff.QuadPart = ul_ht.QuadPart - ul_first.QuadPart; - else - ul_diff.QuadPart = -ul_ht.QuadPart + ul_first.QuadPart; - - if(ul_diff.QuadPart >= DAYSTO100NSECS(infoPtr->maxSelCount)) { - if(cmp == 1) - ul_ht.QuadPart = ul_first.QuadPart + DAYSTO100NSECS(infoPtr->maxSelCount - 1); - else - ul_ht.QuadPart = ul_first.QuadPart - DAYSTO100NSECS(infoPtr->maxSelCount - 1); - - ft_ht.dwLowDateTime = ul_ht.LowPart; - ft_ht.dwHighDateTime = ul_ht.HighPart; - FileTimeToSystemTime(&ft_ht, &st_ht); - } + MONTHCAL_IsSelRangeValid(infoPtr, &st_ht, &infoPtr->firstSel, &st_ht); if(!MONTHCAL_IsDateEqual(&st[i], &st_ht)) { - FILETIME ft_range0, ft_range1; - st[i] = st_ht; - SystemTimeToFileTime(&st[0], &ft_range0); - SystemTimeToFileTime(&st[1], &ft_range1); - - /* swap bounds if needed */ - if(CompareFileTime(&ft_range0, &ft_range1) == 1) { - SYSTEMTIME swap = st[1]; - - st[1] = st[0]; - st[0] = swap; - } - MONTHCAL_CopyTime(&infoPtr->todaysDate, &st[0]); MONTHCAL_CopyTime(&infoPtr->todaysDate, &st[1]); + /* bounds will be swapped here if needed */ MONTHCAL_SetSelRange(infoPtr, st); } } diff --git a/dlls/comctl32/tests/monthcal.c b/dlls/comctl32/tests/monthcal.c index 491cfa2bd5a..3b38e822fa6 100644 --- a/dlls/comctl32/tests/monthcal.c +++ b/dlls/comctl32/tests/monthcal.c @@ -1592,6 +1592,33 @@ static void test_monthcal_selrange(void) expect(range[0].wSecond, range2[1].wSecond); expect(range[0].wMilliseconds, range2[1].wMilliseconds); + /* try with range larger than maximum configured */ + memset(&range[0], 0, sizeof(range[0])); + range[0].wYear = 2009; + range[0].wMonth = 10; + range[0].wDay = 1; + range[1] = range[0]; + + ret = SendMessage(hwnd, MCM_SETSELRANGE, 0, (LPARAM)range); + expect(TRUE, ret); + + range[1] = range[0]; + /* default max. range is 7 days */ + range[1].wDay = 8; + + ret = SendMessage(hwnd, MCM_SETSELRANGE, 0, (LPARAM)range); + expect(FALSE, ret); + + ret = SendMessage(hwnd, MCM_GETSELRANGE, 0, (LPARAM)range2); + expect(TRUE, ret); + + expect(range[0].wYear, range2[0].wYear); + expect(range[0].wMonth, range2[0].wMonth); + expect(range[0].wDay, range2[0].wDay); + expect(range[0].wYear, range2[1].wYear); + expect(range[0].wMonth, range2[1].wMonth); + expect(range[0].wDay, range2[1].wDay); + DestroyWindow(hwnd); }