diff --git a/dlls/comctl32/pager.c b/dlls/comctl32/pager.c index 96a66806eeb..605141b9abf 100644 --- a/dlls/comctl32/pager.c +++ b/dlls/comctl32/pager.c @@ -1046,6 +1046,11 @@ static UINT PAGER_GetAnsiNtfCode(UINT code) case CBEN_DRAGBEGINW: return CBEN_DRAGBEGINA; case CBEN_ENDEDITW: return CBEN_ENDEDITA; case CBEN_GETDISPINFOW: return CBEN_GETDISPINFOA; + /* Date and Time Picker */ + case DTN_FORMATW: return DTN_FORMATA; + case DTN_FORMATQUERYW: return DTN_FORMATQUERYA; + case DTN_USERSTRINGW: return DTN_USERSTRINGA; + case DTN_WMKEYDOWNW: return DTN_WMKEYDOWNA; /* Toolbar */ case TBN_GETBUTTONINFOW: return TBN_GETBUTTONINFOA; case TBN_GETINFOTIPW: return TBN_GETINFOTIPA; @@ -1068,6 +1073,23 @@ static BOOL PAGER_AdjustBuffer(PAGER_INFO *infoPtr, INT size) return TRUE; } +/* Convert text to Unicode and return the original text address */ +static WCHAR *PAGER_ConvertText(WCHAR **text) +{ + WCHAR *oldText = *text; + *text = NULL; + Str_SetPtrWtoA((CHAR **)text, oldText); + return oldText; +} + +static void PAGER_RestoreText(WCHAR **text, WCHAR *oldText) +{ + if (!oldText) return; + + Free(*text); + *text = oldText; +} + static LRESULT PAGER_SendConvertedNotify(PAGER_INFO *infoPtr, NMHDR *hdr, UINT *mask, UINT requiredMask, WCHAR **text, INT *textMax, DWORD flags) { @@ -1166,6 +1188,49 @@ static LRESULT PAGER_Notify(PAGER_INFO *infoPtr, NMHDR *hdr) NULL, FALSE); return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)&nmedA); } + /* Date and Time Picker */ + case DTN_FORMATW: + { + NMDATETIMEFORMATW *nmdtf = (NMDATETIMEFORMATW *)hdr; + WCHAR *oldFormat; + INT textLength; + + hdr->code = PAGER_GetAnsiNtfCode(hdr->code); + oldFormat = PAGER_ConvertText((WCHAR **)&nmdtf->pszFormat); + ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)nmdtf); + PAGER_RestoreText((WCHAR **)&nmdtf->pszFormat, oldFormat); + + if (nmdtf->pszDisplay) + { + textLength = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)nmdtf->pszDisplay, -1, 0, 0); + if (!PAGER_AdjustBuffer(infoPtr, textLength * sizeof(WCHAR))) return ret; + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)nmdtf->pszDisplay, -1, infoPtr->pwszBuffer, textLength); + if (nmdtf->pszDisplay != nmdtf->szDisplay) + nmdtf->pszDisplay = infoPtr->pwszBuffer; + else + { + textLength = min(textLength, ARRAY_SIZE(nmdtf->szDisplay)); + memcpy(nmdtf->szDisplay, infoPtr->pwszBuffer, textLength * sizeof(WCHAR)); + } + } + + return ret; + } + case DTN_FORMATQUERYW: + { + NMDATETIMEFORMATQUERYW *nmdtfq = (NMDATETIMEFORMATQUERYW *)hdr; + return PAGER_SendConvertedNotify(infoPtr, hdr, NULL, 0, (WCHAR **)&nmdtfq->pszFormat, NULL, CONVERT_SEND); + } + case DTN_WMKEYDOWNW: + { + NMDATETIMEWMKEYDOWNW *nmdtkd = (NMDATETIMEWMKEYDOWNW *)hdr; + return PAGER_SendConvertedNotify(infoPtr, hdr, NULL, 0, (WCHAR **)&nmdtkd->pszFormat, NULL, CONVERT_SEND); + } + case DTN_USERSTRINGW: + { + NMDATETIMESTRINGW *nmdts = (NMDATETIMESTRINGW *)hdr; + return PAGER_SendConvertedNotify(infoPtr, hdr, NULL, 0, (WCHAR **)&nmdts->pszUserString, NULL, CONVERT_SEND); + } /* Toolbar */ case TBN_GETBUTTONINFOW: { diff --git a/dlls/comctl32/tests/pager.c b/dlls/comctl32/tests/pager.c index b689549aa57..89931187115 100644 --- a/dlls/comctl32/tests/pager.c +++ b/dlls/comctl32/tests/pager.c @@ -32,6 +32,8 @@ static INT notify_format; static BOOL notify_query_received; static WCHAR test_w[] = {'t', 'e', 's', 't', 0}; static CHAR test_a[] = {'t', 'e', 's', 't', 0}; +/* Double zero so that it's safe to cast it to WCHAR * */ +static CHAR te_a[] = {'t', 'e', 0, 0}; static WCHAR empty_w[] = {0}; static CHAR empty_a[] = {0}; static CHAR large_a[] = "You should have received a copy of the GNU Lesser General Public License along with this ..."; @@ -180,6 +182,29 @@ static const struct notify_test_tooltip {NULL, 0, large_a, NULL, large_truncated_80_w, sizeof(large_truncated_80_w), large_w} }; +static const struct notify_test_datetime_format +{ + /* Data send to parent */ + WCHAR *send_pszformat; + /* Data expected by parent */ + CHAR *expect_pszformat; + /* Data for parent to write */ + CHAR *write_szdisplay; + INT write_szdisplay_size; + CHAR *write_pszdisplay; + /* Data when message returned */ + WCHAR *return_szdisplay; + INT return_szdisplay_size; + WCHAR *return_pszdisplay; +} test_datetime_format_data[] = +{ + {test_w, test_a}, + {NULL, NULL, NULL, 0, test_a, empty_w, -1, test_w}, + {NULL, NULL, test_a, sizeof(test_a), NULL, test_w, -1, test_w}, + {NULL, NULL, test_a, 2, test_a, (WCHAR *)te_a, -1, test_w}, + {NULL, NULL, NULL, 0, large_a, NULL, 0, large_w} +}; + #define CHILD1_ID 1 #define CHILD2_ID 2 @@ -639,6 +664,18 @@ static void notify_tooltip_handler(NMTTDISPINFOA *nm) if (data->write_hinst) nm->hinst = data->write_hinst; } +static void notify_datetime_handler(NMDATETIMEFORMATA *nm) +{ + const struct notify_test_datetime_format *data = test_datetime_format_data + notify_test_info.sub_test_id; + if (data->expect_pszformat) + ok(!lstrcmpA(data->expect_pszformat, nm->pszFormat), "Sub test %d expect %s, got %s\n", + notify_test_info.sub_test_id, data->expect_pszformat, nm->pszFormat); + ok(nm->pszDisplay == nm->szDisplay, "Test %d expect %p, got %p\n", notify_test_info.sub_test_id, nm->szDisplay, + nm->pszDisplay); + if (data->write_szdisplay) memcpy(nm->szDisplay, data->write_szdisplay, data->write_szdisplay_size); + if (data->write_pszdisplay) nm->pszDisplay = data->write_pszdisplay; +} + static LRESULT WINAPI test_notify_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static const WCHAR test[] = {'t', 'e', 's', 't', 0}; @@ -690,6 +727,30 @@ static LRESULT WINAPI test_notify_proc(HWND hwnd, UINT message, WPARAM wParam, L notify_generic_text_handler(&nmcbe->ceItem.pszText, &nmcbe->ceItem.cchTextMax); break; } + /* Date and Time Picker */ + case DTN_FORMATA: + { + notify_datetime_handler((NMDATETIMEFORMATA *)hdr); + break; + } + case DTN_FORMATQUERYA: + { + NMDATETIMEFORMATQUERYA *nmdtfq = (NMDATETIMEFORMATQUERYA *)hdr; + notify_generic_text_handler((CHAR **)&nmdtfq->pszFormat, NULL); + break; + } + case DTN_WMKEYDOWNA: + { + NMDATETIMEWMKEYDOWNA *nmdtkd = (NMDATETIMEWMKEYDOWNA *)hdr; + notify_generic_text_handler((CHAR **)&nmdtkd->pszFormat, NULL); + break; + } + case DTN_USERSTRINGA: + { + NMDATETIMESTRINGA *nmdts = (NMDATETIMESTRINGA *)hdr; + notify_generic_text_handler((CHAR **)&nmdts->pszUserString, NULL); + break; + } /* Toolbar */ case TBN_SAVE: { @@ -896,6 +957,30 @@ static void test_wm_notify_comboboxex(HWND pager) ok(!lstrcmpW(nmcbeed.szText, test_w), "Expect %s, got %s\n", wine_dbgstr_w(test_w), wine_dbgstr_w(nmcbeed.szText)); } +static void test_wm_notify_datetime(HWND pager) +{ + const struct notify_test_datetime_format *data; + NMDATETIMEFORMATW nmdtf; + INT i; + + for (i = 0; i < ARRAY_SIZE(test_datetime_format_data); i++) + { + data = test_datetime_format_data + i; + notify_test_info.sub_test_id = i; + + memset(&nmdtf, 0, sizeof(nmdtf)); + if(data->send_pszformat) nmdtf.pszFormat = data->send_pszformat; + nmdtf.pszDisplay = nmdtf.szDisplay; + send_notify(pager, DTN_FORMATW, DTN_FORMATA, (LPARAM)&nmdtf, TRUE); + if (data->return_szdisplay) + ok(!lstrcmpW(nmdtf.szDisplay, data->return_szdisplay), "Sub test %d expect %s, got %s\n", i, + wine_dbgstr_w(data->return_szdisplay), wine_dbgstr_w(nmdtf.szDisplay)); + if (data->return_pszdisplay) + ok(!lstrcmpW(nmdtf.pszDisplay, data->return_pszdisplay), "Sub test %d expect %s, got %s\n", i, + wine_dbgstr_w(data->return_pszdisplay), wine_dbgstr_w(nmdtf.pszDisplay)); + } +} + static void test_wm_notify_tooltip(HWND pager) { NMTTDISPINFOW nmttdi; @@ -940,6 +1025,10 @@ static void test_wm_notify(void) HWND parent, pager; /* Combo Box Ex */ static NMCOMBOBOXEXW nmcbe; + /* Date and Time Picker */ + static NMDATETIMEFORMATQUERYW nmdtfq; + static NMDATETIMEWMKEYDOWNW nmdtkd; + static NMDATETIMESTRINGW nmdts; /* Tool Bar */ static NMTBRESTORE nmtbr; static NMTBSAVE nmtbs; @@ -955,6 +1044,13 @@ static void test_wm_notify(void) CBEN_DELETEITEM, CBEN_DELETEITEM, DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE}, {&nmcbe, sizeof(nmcbe), &nmcbe.ceItem.mask, CBEIF_TEXT, &nmcbe.ceItem.pszText, &nmcbe.ceItem.cchTextMax, CBEN_GETDISPINFOW, CBEN_GETDISPINFOA, ZERO_SEND | SET_NULL_IF_NO_MASK | DONT_CONVERT_SEND | CONVERT_RECEIVE}, + /* Date and Time Picker */ + {&nmdtfq, sizeof(nmdtfq), NULL, 0, (WCHAR **)&nmdtfq.pszFormat, NULL, DTN_FORMATQUERYW, DTN_FORMATQUERYA, + CONVERT_SEND}, + {&nmdtkd, sizeof(nmdtkd), NULL, 0, (WCHAR **)&nmdtkd.pszFormat, NULL, DTN_WMKEYDOWNW, DTN_WMKEYDOWNA, + CONVERT_SEND}, + {&nmdts, sizeof(nmdts), NULL, 0, (WCHAR **)&nmdts.pszUserString, NULL, DTN_USERSTRINGW, DTN_USERSTRINGA, + CONVERT_SEND}, /* Tool Bar */ {&nmtbs, sizeof(nmtbs), NULL, 0, (WCHAR **)&nmtbs.tbButton.iString, NULL, TBN_SAVE, TBN_SAVE, DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE}, @@ -984,6 +1080,7 @@ static void test_wm_notify(void) /* Tests for those that can't be covered by generic text test helper */ test_wm_notify_comboboxex(pager); + test_wm_notify_datetime(pager); test_wm_notify_tooltip(pager); DestroyWindow(parent);