kernelbase: Reimplement SetLocaleInfoW().
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
5014a44e3c
commit
78a33f9684
|
@ -3796,28 +3796,81 @@ static void test_EnumLanguageGroupLocalesA(void)
|
|||
pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
|
||||
}
|
||||
|
||||
static void test_SetLocaleInfoA(void)
|
||||
static void test_SetLocaleInfo(void)
|
||||
{
|
||||
BOOL bRet;
|
||||
LCID lcid = GetUserDefaultLCID();
|
||||
BOOL bRet;
|
||||
LCID lcid = GetUserDefaultLCID();
|
||||
UINT i;
|
||||
|
||||
/* Null data */
|
||||
SetLastError(0);
|
||||
bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
|
||||
ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
|
||||
"Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
|
||||
/* Null data */
|
||||
SetLastError(0xdeadbeef);
|
||||
bRet = SetLocaleInfoA(lcid, LOCALE_SSHORTDATE, NULL);
|
||||
ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
|
||||
"Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
|
||||
|
||||
/* IDATE */
|
||||
SetLastError(0);
|
||||
bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
|
||||
ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
|
||||
"Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError());
|
||||
SetLastError(0xdeadbeef);
|
||||
bRet = SetLocaleInfoW(lcid, LOCALE_SSHORTDATE, NULL);
|
||||
ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
|
||||
"Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
|
||||
|
||||
/* ILDATE */
|
||||
SetLastError(0);
|
||||
bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
|
||||
ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
|
||||
"Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError());
|
||||
SetLastError(0xdeadbeef);
|
||||
bRet = SetLocaleInfoW(lcid, LOCALE_SDAYNAME1, NULL);
|
||||
ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
|
||||
"Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
|
||||
|
||||
for (i = 0; i <= 0x1014; i++)
|
||||
{
|
||||
WCHAR buffer[80];
|
||||
if (!GetLocaleInfoW( LOCALE_USER_DEFAULT, i, buffer, ARRAY_SIZE(buffer) )) continue;
|
||||
SetLastError(0xdeadbeef);
|
||||
bRet = SetLocaleInfoW(lcid, i, buffer);
|
||||
switch (i)
|
||||
{
|
||||
case LOCALE_ICALENDARTYPE:
|
||||
case LOCALE_ICURRDIGITS:
|
||||
case LOCALE_ICURRENCY:
|
||||
case LOCALE_IDIGITS:
|
||||
case LOCALE_IDIGITSUBSTITUTION:
|
||||
case LOCALE_IFIRSTDAYOFWEEK:
|
||||
case LOCALE_IFIRSTWEEKOFYEAR:
|
||||
case LOCALE_ILZERO:
|
||||
case LOCALE_IMEASURE:
|
||||
case LOCALE_INEGCURR:
|
||||
case LOCALE_INEGNUMBER:
|
||||
case LOCALE_IPAPERSIZE:
|
||||
case LOCALE_ITIME:
|
||||
case LOCALE_S1159:
|
||||
case LOCALE_S2359:
|
||||
case LOCALE_SCURRENCY:
|
||||
case LOCALE_SDATE:
|
||||
case LOCALE_SDECIMAL:
|
||||
case LOCALE_SGROUPING:
|
||||
case LOCALE_SLIST:
|
||||
case LOCALE_SLONGDATE:
|
||||
case LOCALE_SMONDECIMALSEP:
|
||||
case LOCALE_SMONGROUPING:
|
||||
case LOCALE_SMONTHOUSANDSEP:
|
||||
case LOCALE_SNATIVEDIGITS:
|
||||
case LOCALE_SNEGATIVESIGN:
|
||||
case LOCALE_SPOSITIVESIGN:
|
||||
case LOCALE_SSHORTDATE:
|
||||
case LOCALE_SSHORTTIME:
|
||||
case LOCALE_STHOUSAND:
|
||||
case LOCALE_STIME:
|
||||
case LOCALE_STIMEFORMAT:
|
||||
case LOCALE_SYEARMONTH:
|
||||
ok( bRet, "%04x: failed err %lu\n", i, GetLastError() );
|
||||
break;
|
||||
case LOCALE_SINTLSYMBOL:
|
||||
ok( bRet || broken(!bRet), /* win10 <= 1507 */
|
||||
"%04x: failed err %lu\n", i, GetLastError() );
|
||||
break;
|
||||
default:
|
||||
ok( !bRet, "%04x: succeeded\n", i );
|
||||
ok( GetLastError() == ERROR_INVALID_FLAGS, "%04x: wrong error %lu\n", i, GetLastError() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
|
||||
|
@ -7417,7 +7470,7 @@ START_TEST(locale)
|
|||
test_EnumSystemLanguageGroupsA();
|
||||
test_EnumSystemLocalesEx();
|
||||
test_EnumLanguageGroupLocalesA();
|
||||
test_SetLocaleInfoA();
|
||||
test_SetLocaleInfo();
|
||||
test_EnumUILanguageA();
|
||||
test_GetCPInfo();
|
||||
test_GetStringTypeW();
|
||||
|
|
|
@ -85,58 +85,6 @@ static struct registry_entry entry_sthousand = { L"sThousand" };
|
|||
static struct registry_entry entry_stimeformat = { L"sTimeFormat" };
|
||||
static struct registry_entry entry_syearmonth = { L"sYearMonth" };
|
||||
|
||||
static const struct registry_value
|
||||
{
|
||||
DWORD lctype;
|
||||
const WCHAR *name;
|
||||
} registry_values[] =
|
||||
{
|
||||
{ LOCALE_ICALENDARTYPE, L"iCalendarType" },
|
||||
{ LOCALE_ICURRDIGITS, L"iCurrDigits" },
|
||||
{ LOCALE_ICURRENCY, L"iCurrency" },
|
||||
{ LOCALE_IDIGITS, L"iDigits" },
|
||||
{ LOCALE_IFIRSTDAYOFWEEK, L"iFirstDayOfWeek" },
|
||||
{ LOCALE_IFIRSTWEEKOFYEAR, L"iFirstWeekOfYear" },
|
||||
{ LOCALE_ILZERO, L"iLZero" },
|
||||
{ LOCALE_IMEASURE, L"iMeasure" },
|
||||
{ LOCALE_INEGCURR, L"iNegCurr" },
|
||||
{ LOCALE_INEGNUMBER, L"iNegNumber" },
|
||||
{ LOCALE_IPAPERSIZE, L"iPaperSize" },
|
||||
{ LOCALE_ITIME, L"iTime" },
|
||||
{ LOCALE_S1159, L"s1159" },
|
||||
{ LOCALE_S2359, L"s2359" },
|
||||
{ LOCALE_SCURRENCY, L"sCurrency" },
|
||||
{ LOCALE_SDATE, L"sDate" },
|
||||
{ LOCALE_SDECIMAL, L"sDecimal" },
|
||||
{ LOCALE_SGROUPING, L"sGrouping" },
|
||||
{ LOCALE_SLIST, L"sList" },
|
||||
{ LOCALE_SLONGDATE, L"sLongDate" },
|
||||
{ LOCALE_SMONDECIMALSEP, L"sMonDecimalSep" },
|
||||
{ LOCALE_SMONGROUPING, L"sMonGrouping" },
|
||||
{ LOCALE_SMONTHOUSANDSEP, L"sMonThousandSep" },
|
||||
{ LOCALE_SNEGATIVESIGN, L"sNegativeSign" },
|
||||
{ LOCALE_SPOSITIVESIGN, L"sPositiveSign" },
|
||||
{ LOCALE_SSHORTDATE, L"sShortDate" },
|
||||
{ LOCALE_STHOUSAND, L"sThousand" },
|
||||
{ LOCALE_STIME, L"sTime" },
|
||||
{ LOCALE_STIMEFORMAT, L"sTimeFormat" },
|
||||
{ LOCALE_SYEARMONTH, L"sYearMonth" },
|
||||
/* The following are not listed under MSDN as supported,
|
||||
* but seem to be used and also stored in the registry.
|
||||
*/
|
||||
{ LOCALE_SNAME, L"LocaleName" },
|
||||
{ LOCALE_ICOUNTRY, L"iCountry" },
|
||||
{ LOCALE_IDATE, L"iDate" },
|
||||
{ LOCALE_ILDATE, L"iLDate" },
|
||||
{ LOCALE_ITLZERO, L"iTLZero" },
|
||||
{ LOCALE_SCOUNTRY, L"sCountry" },
|
||||
{ LOCALE_SABBREVLANGNAME, L"sLanguage" },
|
||||
{ LOCALE_IDIGITSUBSTITUTION, L"Numshape" },
|
||||
{ LOCALE_SNATIVEDIGITS, L"sNativeDigits" },
|
||||
{ LOCALE_ITIMEMARKPOSN, L"iTimePrefix" },
|
||||
};
|
||||
|
||||
static WCHAR *registry_cache[ARRAY_SIZE(registry_values)];
|
||||
|
||||
static const struct { UINT cp; const WCHAR *name; } codepage_names[] =
|
||||
{
|
||||
|
@ -883,6 +831,30 @@ static int locale_return_data( const WCHAR *data, int datalen, LCTYPE type, WCHA
|
|||
}
|
||||
|
||||
|
||||
static BOOL set_registry_entry( struct registry_entry *entry, const WCHAR *data )
|
||||
{
|
||||
DWORD size = (wcslen(data) + 1) * sizeof(WCHAR);
|
||||
LSTATUS ret;
|
||||
|
||||
if (size > sizeof(entry->data))
|
||||
{
|
||||
SetLastError( ERROR_INVALID_FLAGS );
|
||||
return FALSE;
|
||||
}
|
||||
TRACE( "setting %s to %s\n", debugstr_w(entry->value), debugstr_w(data) );
|
||||
|
||||
RtlEnterCriticalSection( &locale_section );
|
||||
if (!(ret = RegSetValueExW( intl_key, entry->value, 0, REG_SZ, (BYTE *)data, size )))
|
||||
{
|
||||
wcscpy( entry->data, data );
|
||||
entry->status = CACHED;
|
||||
}
|
||||
RtlLeaveCriticalSection( &locale_section );
|
||||
if (ret) SetLastError( ret );
|
||||
return !ret;
|
||||
}
|
||||
|
||||
|
||||
static int locale_return_reg_string( struct registry_entry *entry, LCTYPE type, WCHAR *buffer, int len )
|
||||
{
|
||||
DWORD size;
|
||||
|
@ -1074,6 +1046,30 @@ static WCHAR *find_format( WCHAR *str, const WCHAR *accept )
|
|||
}
|
||||
|
||||
|
||||
/* replace the separator in a date/time format string */
|
||||
static WCHAR *locale_replace_separator( WCHAR *buffer, const WCHAR *sep )
|
||||
{
|
||||
UINT pos = 0;
|
||||
WCHAR res[80];
|
||||
WCHAR *next, *str = find_format( buffer, L"dMyHhms" );
|
||||
|
||||
if (!str) return buffer;
|
||||
pos = str - buffer;
|
||||
memcpy( res, buffer, pos * sizeof(WCHAR) );
|
||||
for (;;)
|
||||
{
|
||||
res[pos++] = *str++;
|
||||
while (str[0] == str[-1]) res[pos++] = *str++; /* copy repeated chars */
|
||||
if (!(next = find_format( str, L"dMyHhms" ))) break;
|
||||
wcscpy( res + pos, sep );
|
||||
pos += wcslen(sep);
|
||||
str = next;
|
||||
}
|
||||
wcscpy( res + pos, str );
|
||||
return wcscpy( buffer, res );
|
||||
}
|
||||
|
||||
|
||||
/* FIXME: hardcoded, sortname is apparently not available in locale.nls */
|
||||
static const WCHAR *get_locale_sortname( LCID lcid )
|
||||
{
|
||||
|
@ -1928,16 +1924,6 @@ static int get_value_base_by_lctype( LCTYPE lctype )
|
|||
}
|
||||
|
||||
|
||||
static const struct registry_value *get_locale_registry_value( DWORD lctype )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE( registry_values ); i++)
|
||||
if (registry_values[i].lctype == lctype) return ®istry_values[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static const CPTABLEINFO *get_codepage_table( UINT codepage )
|
||||
{
|
||||
unsigned int i;
|
||||
|
@ -6433,63 +6419,82 @@ INT WINAPI DECLSPEC_HOTPATCH ResolveLocaleName( LPCWSTR name, LPWSTR buffer, INT
|
|||
*/
|
||||
BOOL WINAPI DECLSPEC_HOTPATCH SetLocaleInfoW( LCID lcid, LCTYPE lctype, const WCHAR *data )
|
||||
{
|
||||
const struct registry_value *value;
|
||||
DWORD index;
|
||||
LSTATUS status;
|
||||
WCHAR *str, tmp[80];
|
||||
|
||||
lctype = LOWORD(lctype);
|
||||
value = get_locale_registry_value( lctype );
|
||||
|
||||
if (!data || !value)
|
||||
if (!data)
|
||||
{
|
||||
SetLastError( ERROR_INVALID_PARAMETER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (lctype == LOCALE_IDATE || lctype == LOCALE_ILDATE)
|
||||
switch (LOWORD(lctype))
|
||||
{
|
||||
SetLastError( ERROR_INVALID_FLAGS );
|
||||
return FALSE;
|
||||
case LOCALE_ICALENDARTYPE: return set_registry_entry( &entry_icalendartype, data );
|
||||
case LOCALE_ICURRDIGITS: return set_registry_entry( &entry_icurrdigits, data );
|
||||
case LOCALE_ICURRENCY: return set_registry_entry( &entry_icurrency, data );
|
||||
case LOCALE_IDIGITS: return set_registry_entry( &entry_idigits, data );
|
||||
case LOCALE_IDIGITSUBSTITUTION: return set_registry_entry( &entry_idigitsubstitution, data );
|
||||
case LOCALE_IFIRSTDAYOFWEEK: return set_registry_entry( &entry_ifirstdayofweek, data );
|
||||
case LOCALE_IFIRSTWEEKOFYEAR: return set_registry_entry( &entry_ifirstweekofyear, data );
|
||||
case LOCALE_ILZERO: return set_registry_entry( &entry_ilzero, data );
|
||||
case LOCALE_IMEASURE: return set_registry_entry( &entry_imeasure, data );
|
||||
case LOCALE_INEGCURR: return set_registry_entry( &entry_inegcurr, data );
|
||||
case LOCALE_INEGNUMBER: return set_registry_entry( &entry_inegnumber, data );
|
||||
case LOCALE_IPAPERSIZE: return set_registry_entry( &entry_ipapersize, data );
|
||||
case LOCALE_S1159: return set_registry_entry( &entry_s1159, data );
|
||||
case LOCALE_S2359: return set_registry_entry( &entry_s2359, data );
|
||||
case LOCALE_SCURRENCY: return set_registry_entry( &entry_scurrency, data );
|
||||
case LOCALE_SDECIMAL: return set_registry_entry( &entry_sdecimal, data );
|
||||
case LOCALE_SGROUPING: return set_registry_entry( &entry_sgrouping, data );
|
||||
case LOCALE_SLIST: return set_registry_entry( &entry_slist, data );
|
||||
case LOCALE_SLONGDATE: return set_registry_entry( &entry_slongdate, data );
|
||||
case LOCALE_SMONDECIMALSEP: return set_registry_entry( &entry_smondecimalsep, data );
|
||||
case LOCALE_SMONGROUPING: return set_registry_entry( &entry_smongrouping, data );
|
||||
case LOCALE_SMONTHOUSANDSEP: return set_registry_entry( &entry_smonthousandsep, data );
|
||||
case LOCALE_SNATIVEDIGITS: return set_registry_entry( &entry_snativedigits, data );
|
||||
case LOCALE_SNEGATIVESIGN: return set_registry_entry( &entry_snegativesign, data );
|
||||
case LOCALE_SPOSITIVESIGN: return set_registry_entry( &entry_spositivesign, data );
|
||||
case LOCALE_SSHORTTIME: return set_registry_entry( &entry_sshorttime, data );
|
||||
case LOCALE_STHOUSAND: return set_registry_entry( &entry_sthousand, data );
|
||||
case LOCALE_SYEARMONTH: return set_registry_entry( &entry_syearmonth, data );
|
||||
|
||||
case LOCALE_SDATE:
|
||||
if (!get_locale_info( user_locale, user_lcid, LOCALE_SSHORTDATE, tmp, ARRAY_SIZE(tmp) )) break;
|
||||
data = locale_replace_separator( tmp, data );
|
||||
/* fall through */
|
||||
case LOCALE_SSHORTDATE:
|
||||
if (!set_registry_entry( &entry_sshortdate, data )) return FALSE;
|
||||
update_registry_value( LOCALE_IDATE, L"iDate" );
|
||||
update_registry_value( LOCALE_SDATE, L"sDate" );
|
||||
return TRUE;
|
||||
|
||||
case LOCALE_STIME:
|
||||
if (!get_locale_info( user_locale, user_lcid, LOCALE_STIMEFORMAT, tmp, ARRAY_SIZE(tmp) )) break;
|
||||
data = locale_replace_separator( tmp, data );
|
||||
/* fall through */
|
||||
case LOCALE_STIMEFORMAT:
|
||||
if (!set_registry_entry( &entry_stimeformat, data )) return FALSE;
|
||||
update_registry_value( LOCALE_ITIME, L"iTime" );
|
||||
update_registry_value( LOCALE_ITIMEMARKPOSN, L"iTimePrefix" );
|
||||
update_registry_value( LOCALE_ITLZERO, L"iTLZero" );
|
||||
update_registry_value( LOCALE_STIME, L"sTime" );
|
||||
return TRUE;
|
||||
|
||||
case LOCALE_ITIME:
|
||||
if (!get_locale_info( user_locale, user_lcid, LOCALE_STIMEFORMAT, tmp, ARRAY_SIZE(tmp) )) break;
|
||||
if (!(str = find_format( tmp, L"Hh" ))) break;
|
||||
while (*str == 'h' || *str == 'H') *str++ = (*data == '0' ? 'h' : 'H');
|
||||
if (!set_registry_entry( &entry_stimeformat, tmp )) break;
|
||||
update_registry_value( LOCALE_ITIME, L"iTime" );
|
||||
return TRUE;
|
||||
|
||||
case LOCALE_SINTLSYMBOL:
|
||||
/* FIXME: also store sintlsymbol */
|
||||
set_registry_entry( &entry_scurrency, data );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
TRACE( "setting %lx (%s) to %s\n", lctype, debugstr_w(value->name), debugstr_w(data) );
|
||||
|
||||
/* FIXME: should check that data to set is sane */
|
||||
|
||||
status = RegSetValueExW( intl_key, value->name, 0, REG_SZ, (BYTE *)data, (lstrlenW(data)+1)*sizeof(WCHAR) );
|
||||
index = value - registry_values;
|
||||
|
||||
RtlEnterCriticalSection( &locale_section );
|
||||
HeapFree( GetProcessHeap(), 0, registry_cache[index] );
|
||||
registry_cache[index] = NULL;
|
||||
RtlLeaveCriticalSection( &locale_section );
|
||||
|
||||
if (lctype == LOCALE_SSHORTDATE || lctype == LOCALE_SLONGDATE)
|
||||
{
|
||||
/* Set I-value from S value */
|
||||
WCHAR *pD, *pM, *pY, buf[2];
|
||||
|
||||
pD = wcschr( data, 'd' );
|
||||
pM = wcschr( data, 'M' );
|
||||
pY = wcschr( data, 'y' );
|
||||
|
||||
if (pD <= pM) buf[0] = '1'; /* D-M-Y */
|
||||
else if (pY <= pM) buf[0] = '2'; /* Y-M-D */
|
||||
else buf[0] = '0'; /* M-D-Y */
|
||||
buf[1] = 0;
|
||||
|
||||
lctype = (lctype == LOCALE_SSHORTDATE) ? LOCALE_IDATE : LOCALE_ILDATE;
|
||||
value = get_locale_registry_value( lctype );
|
||||
index = value - registry_values;
|
||||
|
||||
RegSetValueExW( intl_key, value->name, 0, REG_SZ, (BYTE *)buf, sizeof(buf) );
|
||||
|
||||
RtlEnterCriticalSection( &locale_section );
|
||||
HeapFree( GetProcessHeap(), 0, registry_cache[index] );
|
||||
registry_cache[index] = NULL;
|
||||
RtlLeaveCriticalSection( &locale_section );
|
||||
}
|
||||
return set_ntstatus( status );
|
||||
SetLastError( ERROR_INVALID_FLAGS );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue