Index: reactos/dll/win32/kernel32_vista/CMakeLists.txt =================================================================== --- reactos/dll/win32/kernel32_vista/CMakeLists.txt (revision 72401) +++ reactos/dll/win32/kernel32_vista/CMakeLists.txt (working copy) @@ -10,6 +10,7 @@ GetFileInformationByHandleEx.c GetTickCount64.c InitOnceExecuteOnce.c + locale.c ${CMAKE_CURRENT_BINARY_DIR}/kernel32_vista.def) add_library(kernel32_vista SHARED ${SOURCE}) Index: reactos/dll/win32/kernel32_vista/k32_vista.h =================================================================== --- reactos/dll/win32/kernel32_vista/k32_vista.h (revision 72401) +++ reactos/dll/win32/kernel32_vista/k32_vista.h (working copy) @@ -5,7 +5,10 @@ #define WIN32_NO_STATUS #include #include +#include +#include +#include + #include #include - Index: reactos/dll/win32/kernel32_vista/kernel32_vista.spec =================================================================== --- reactos/dll/win32/kernel32_vista/kernel32_vista.spec (revision 72401) +++ reactos/dll/win32/kernel32_vista/kernel32_vista.spec (working copy) @@ -1,4 +1,7 @@ - @ stdcall InitOnceExecuteOnce(ptr ptr ptr ptr) @ stdcall GetFileInformationByHandleEx(long long ptr long) @ stdcall -ret64 GetTickCount64() +@ stdcall GetDateFormatEx(ptr long ptr ptr ptr long ptr) +@ stdcall GetTimeFormatEx(ptr long ptr ptr ptr long) +@ stdcall GetNumberFormatEx(ptr long ptr ptr ptr long) +@ stdcall GetCurrencyFormatEx(ptr long ptr ptr ptr long) Index: reactos/dll/win32/kernel32_vista/locale.c =================================================================== --- reactos/dll/win32/kernel32_vista/locale.c (nonexistent) +++ reactos/dll/win32/kernel32_vista/locale.c (working copy) @@ -0,0 +1,311 @@ +/* + * PROJECT: ReactOS kernel32_vista + * LICENSE: GNU LGPL + * PURPOSE: Provides locale functions on Vista+ + * PROGRAMMERS: Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + */ +#include "k32_vista.h" + +typedef struct LOCALE_NAME +{ + WCHAR win_name[128]; /* Windows name ("en-US") */ + WCHAR lang[128]; /* language ("en") (NOTE: buffer contains the other strings too) */ + WCHAR *country; /* country ("US") */ + WCHAR *script; /* script ("Latn") */ + WCHAR *modifier; /* modifier or sort order */ + LCID lcid; /* corresponding LCID */ + int matches; /* number of elements matching LCID (0..4) */ +} LOCALE_NAME; + +/*********************************************************************** + * find_locale_id_callback + */ +static BOOL CALLBACK +find_locale_id_callback(HMODULE hModule, LPCWSTR type, LPCWSTR name, WORD LangID, + LPARAM lParam) +{ + LOCALE_NAME *data = (LOCALE_NAME *)lParam; + WCHAR buffer[128]; + int matches = 0; + LCID lcid = MAKELCID(LangID, SORT_DEFAULT); /* FIXME: handle sort order */ + + if (PRIMARYLANGID(LangID) == LANG_NEUTRAL) return TRUE; /* continue search */ + + /* first check exact name */ + if (data->win_name[0] && + GetLocaleInfoW(lcid, LOCALE_SNAME | LOCALE_NOUSEROVERRIDE, + buffer, _countof(buffer))) + { + if (!lstrcmpW(data->win_name, buffer)) + { + matches = 4; /* everything matches */ + goto done; + } + } + + if (!GetLocaleInfoW(lcid, LOCALE_SISO639LANGNAME | LOCALE_NOUSEROVERRIDE, + buffer, _countof(buffer))) + { + return TRUE; + } + if (lstrcmpW(buffer, data->lang)) + return TRUE; + matches++; /* language name matched */ + + if (data->country) + { + if (GetLocaleInfoW(lcid, LOCALE_SISO3166CTRYNAME|LOCALE_NOUSEROVERRIDE, + buffer, _countof(buffer))) + { + if (lstrcmpW(buffer, data->country)) + goto done; + matches++; /* country name matched */ + } + } + else /* match default language */ + { + if (SUBLANGID(LangID) == SUBLANG_DEFAULT) matches++; + } + + /* FIXME: check sort order */ + +done: + if (matches > data->matches) + { + data->lcid = lcid; + data->matches = matches; + } + return (data->matches < 4); /* no need to continue for perfect match */ +} + +/*********************************************************************** + * parse_locale_name + * + * Parse a locale name into a LOCALE_NAME, handling Windows formats only. + * Windows format is: lang[-script][-country][_modifier] + */ +static void parse_locale_name(const WCHAR *str, LOCALE_NAME *name) +{ + static const WCHAR sepW[] = {'-','_','.','@',0}; + static const WCHAR winsepW[] = {'-','_',0}; + static const WCHAR posixW[] = {'P','O','S','I','X',0}; + static const WCHAR cW[] = {'C',0}; + WCHAR *p; + HINSTANCE kernel32 = GetModuleHandleA("kernel32"); + + name->country = name->script = name->modifier = NULL; + name->lcid = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), SORT_DEFAULT); + name->matches = 0; + name->win_name[0] = 0; + lstrcpynW(name->lang, str, _countof(name->lang)); + + if (!*name->lang) + { + name->lcid = LOCALE_INVARIANT; + name->matches = 4; + return; + } + + p = wcspbrk(name->lang, sepW); + if (p == NULL) + { + if (!lstrcmpW(name->lang, posixW) || !lstrcmpW(name->lang, cW)) + { + name->matches = 4; /* perfect match for default English lcid */ + return; + } + lstrcpyW(name->win_name, name->lang); + } + else if (*p == '-') /* Windows format */ + { + lstrcpyW(name->win_name, name->lang); + *p++ = 0; + name->country = p; + + p = wcspbrk(p, winsepW); + if (p == NULL) + goto done; + if (*p == '-') + { + *p++ = 0; + name->script = name->country; + name->country = p; + if (!(p = wcspbrk(p, winsepW))) goto done; + } + *p++ = 0; + name->modifier = p; + } +done: + EnumResourceLanguagesW(kernel32, (LPCWSTR)RT_STRING, (LPCWSTR)LOCALE_ILANGUAGE, + find_locale_id_callback, (LPARAM)name); +} + +/*********************************************************************** + * LocaleNameToLCID (KERNEL32.@) + */ +LCID WINAPI LocaleNameToLCID(LPCWSTR name, DWORD flags) +{ + LOCALE_NAME locale_name; + + if (flags) + { + /* FIXME("unsupported flags %x\n", flags); */ + } + + if (name == LOCALE_NAME_USER_DEFAULT) + return GetUserDefaultLCID(); + + /* string parsing */ + parse_locale_name(name, &locale_name); + + if (!locale_name.matches) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + if (locale_name.matches == 1) + { + /* WARN("locale %s not recognized, defaulting to %s\n", + debugstr_w(name), debugstr_w(locale_name.lang)); */ + } + + return locale_name.lcid; +} + +/****************************************************************************** + * GetDateFormatEx [KERNEL32.@] + * + * Format a date for a given locale. + * + * PARAMS + * localename [I] Locale to format for + * flags [I] LOCALE_ and DATE_ flags from "winnls.h" + * date [I] Date to format + * format [I] Format string, or NULL to use the locale defaults + * outbuf [O] Destination for formatted string + * bufsize [I] Size of outbuf, or 0 to calculate the resulting size + * calendar [I] Reserved, must be NULL + * + * See GetDateFormat for notes. + * + * RETURNS + * Success: The number of characters written to outbuf, or that would have + * been written if bufsize is 0. + * Failure: 0. Use GetLastError() to determine the cause. + */ +INT WINAPI GetDateFormatEx(LPCWSTR localename, DWORD flags, + const SYSTEMTIME* date, LPCWSTR format, + LPWSTR outbuf, INT bufsize, LPCWSTR calendar) +{ + LCID lcid; + + /* Parameter is currently reserved and Windows errors if set */ + if (calendar) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + lcid = LocaleNameToLCID(localename, 0); + return GetDateFormatW(lcid, flags, date, format, outbuf, bufsize); +} + +/****************************************************************************** + * GetTimeFormatEx [KERNEL32.@] + * + * Format a date for a given locale. + * + * PARAMS + * localename [I] Locale to format for + * flags [I] LOCALE_ and TIME_ flags from "winnls.h" + * time [I] Time to format + * format [I] Formatting overrides + * outbuf [O] Destination for formatted string + * bufsize [I] Size of outbuf, or 0 to calculate the resulting size + * + * See GetTimeFormat for notes. + * + * RETURNS + * Success: The number of characters written to outbuf, or that would have + * have been written if bufsize is 0. + * Failure: 0. Use GetLastError() to determine the cause. + */ +INT WINAPI GetTimeFormatEx(LPCWSTR localename, DWORD flags, + const SYSTEMTIME* time, LPCWSTR format, + LPWSTR outbuf, INT bufsize) +{ + LCID lcid = LocaleNameToLCID(localename, 0); + return GetTimeFormatW(lcid, flags, time, format, outbuf, bufsize); +} + +/****************************************************************************** + * GetNumberFormatEx [KERNEL32.@] + * + * Format a number for a given locale. + * + * PARAMS + * lpLocaleName [I] Locale to format for + * dwFlags [I] LOCALE_ flags from "winnls.h" + * lpValue [I] value to format + * lpFormat [I] Formatting overrides + * lpNumberStr [O] Destination for formatted string + * cchNumber [I] Size of lpNumberStr, or 0 to calculate the resulting size + * + * See GetNumberFormat for notes. + * + * RETURNS + * Success: The number of characters written to lpNumberStr, or that would have + * have been written if cchNumber is 0. + * Failure: 0. Use GetLastError() to determine the cause. + */ +int WINAPI GetNumberFormatEx(LPCWSTR lpLocaleName, DWORD dwFlags, + LPCWSTR lpValue, CONST NUMBERFMTW *lpFormat, + LPWSTR lpNumberStr, int cchNumber) +{ + LCID lcid = LocaleNameToLCID(lpLocaleName, 0); + return GetNumberFormatW(lcid, dwFlags, lpValue, lpFormat, lpNumberStr, + cchNumber); +} + +/****************************************************************************** + * GetCurrencyFormatEx [KERNEL32.@] + * + * Format a currency price for a given locale. + * + * PARAMS + * lpLocaleName [I] Locale to format for + * dwFlags [I] LOCALE_ flags from "winnls.h" + * lpValue [I] value to format + * lpFormat [I] Formatting overrides + * lpCurrencyStr [O] Destination for formatted string + * cchCurrency [I] Size of lpCurrencyStr, or 0 to calculate the resulting size + * + * See GetCurrencyFormat for notes. + * + * RETURNS + * Success: The number of characters written to lpCurrencyStr, or that would have + * have been written if cchNumber is 0. + * Failure: 0. Use GetLastError() to determine the cause. + */ +int WINAPI GetCurrencyFormatEx(LPCWSTR lpLocaleName, DWORD dwFlags, + LPCWSTR lpValue, CONST CURRENCYFMTW *lpFormat, + LPWSTR lpCurrencyStr, int cchCurrency) +{ + LCID lcid = LocaleNameToLCID(lpLocaleName, 0); + return GetCurrencyFormatW(lcid, dwFlags, lpValue, lpFormat, lpCurrencyStr, + cchCurrency); +} + +/* FIXME & TODO: add GetDurationFormat and GetDurationFormatEx to psdk */ +#if 0 +int WINAPI GetDurationFormatEx(LPCWSTR lpLocaleName, DWORD dwFlags, + CONST SYSTEMTIME *lpDuration, + ULONGLONG ullDuration, LPCWSTR lpFormat, + LPWSTR lpDurationStr, int cchDuration) +{ + LCID lcid = LocaleNameToLCID(lpLocaleName, 0); + return GetDurationFormatW(lcid, dwFlags, lpDuration, ullDuration, lpFormat, + lpFormat, lpDurationStr, cchDuration); +} +#endif