kernel32: Cache locale info from the registry.
Vincent Povirk
madewokherd at gmail.com
Thu Feb 27 16:42:45 CST 2014
For bug 35530.
-------------- next part --------------
From a2ddb29ba783e2e15928f54451d0f3b107d174e6 Mon Sep 17 00:00:00 2001
From: Vincent Povirk <vincent at codeweavers.com>
Date: Thu, 27 Feb 2014 16:10:58 -0600
Subject: [PATCH] kernel32: Cache locale info from the registry.
---
dlls/kernel32/locale.c | 221 +++++++++++++++++++++++++++++++------------------
1 file changed, 141 insertions(+), 80 deletions(-)
diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c
index 22903d5..84e9d86 100644
--- a/dlls/kernel32/locale.c
+++ b/dlls/kernel32/locale.c
@@ -160,6 +160,17 @@ static LCID lcid_LC_PAPER;
static LCID lcid_LC_MEASUREMENT;
static LCID lcid_LC_TELEPHONE;
+static WCHAR *cached_registry_values[39];
+
+static CRITICAL_SECTION cache_section;
+static CRITICAL_SECTION_DEBUG critsect_debug =
+{
+ 0, 0, &cache_section,
+ { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
+ 0, 0, { (DWORD_PTR)(__FILE__ ": cache_section") }
+};
+static CRITICAL_SECTION cache_section = { &critsect_debug, -1, 0, 0, 0, 0 };
+
/* Copy Ascii string to Unicode without using codepages */
static inline void strcpynAtoW( WCHAR *dst, const char *src, size_t n )
{
@@ -1027,7 +1038,7 @@ INT WINAPI LCIDToLocaleName( LCID lcid, LPWSTR name, INT count, DWORD flags )
*
* Gets the registry value name for a given lctype.
*/
-static const WCHAR *get_locale_value_name( DWORD lctype )
+static const WCHAR *get_locale_value_name( DWORD lctype, int *cache_index )
{
static const WCHAR iCalendarTypeW[] = {'i','C','a','l','e','n','d','a','r','T','y','p','e',0};
static const WCHAR iCountryW[] = {'i','C','o','u','n','t','r','y',0};
@@ -1074,51 +1085,51 @@ static const WCHAR *get_locale_value_name( DWORD lctype )
/* These values are used by SetLocaleInfo and GetLocaleInfo, and
* the values are stored in the registry, confirmed under Windows.
*/
- case LOCALE_ICALENDARTYPE: return iCalendarTypeW;
- case LOCALE_ICURRDIGITS: return iCurrDigitsW;
- case LOCALE_ICURRENCY: return iCurrencyW;
- case LOCALE_IDIGITS: return iDigitsW;
- case LOCALE_IFIRSTDAYOFWEEK: return iFirstDayOfWeekW;
- case LOCALE_IFIRSTWEEKOFYEAR: return iFirstWeekOfYearW;
- case LOCALE_ILZERO: return iLZeroW;
- case LOCALE_IMEASURE: return iMeasureW;
- case LOCALE_INEGCURR: return iNegCurrW;
- case LOCALE_INEGNUMBER: return iNegNumberW;
- case LOCALE_IPAPERSIZE: return iPaperSizeW;
- case LOCALE_ITIME: return iTimeW;
- case LOCALE_S1159: return s1159W;
- case LOCALE_S2359: return s2359W;
- case LOCALE_SCURRENCY: return sCurrencyW;
- case LOCALE_SDATE: return sDateW;
- case LOCALE_SDECIMAL: return sDecimalW;
- case LOCALE_SGROUPING: return sGroupingW;
- case LOCALE_SLIST: return sListW;
- case LOCALE_SLONGDATE: return sLongDateW;
- case LOCALE_SMONDECIMALSEP: return sMonDecimalSepW;
- case LOCALE_SMONGROUPING: return sMonGroupingW;
- case LOCALE_SMONTHOUSANDSEP: return sMonThousandSepW;
- case LOCALE_SNEGATIVESIGN: return sNegativeSignW;
- case LOCALE_SPOSITIVESIGN: return sPositiveSignW;
- case LOCALE_SSHORTDATE: return sShortDateW;
- case LOCALE_STHOUSAND: return sThousandW;
- case LOCALE_STIME: return sTimeW;
- case LOCALE_STIMEFORMAT: return sTimeFormatW;
- case LOCALE_SYEARMONTH: return sYearMonthW;
+ case LOCALE_ICALENDARTYPE: *cache_index = 0; return iCalendarTypeW;
+ case LOCALE_ICURRDIGITS: *cache_index = 1; return iCurrDigitsW;
+ case LOCALE_ICURRENCY: *cache_index = 2; return iCurrencyW;
+ case LOCALE_IDIGITS: *cache_index = 3; return iDigitsW;
+ case LOCALE_IFIRSTDAYOFWEEK: *cache_index = 4; return iFirstDayOfWeekW;
+ case LOCALE_IFIRSTWEEKOFYEAR: *cache_index = 5; return iFirstWeekOfYearW;
+ case LOCALE_ILZERO: *cache_index = 6; return iLZeroW;
+ case LOCALE_IMEASURE: *cache_index = 7; return iMeasureW;
+ case LOCALE_INEGCURR: *cache_index = 8; return iNegCurrW;
+ case LOCALE_INEGNUMBER: *cache_index = 9; return iNegNumberW;
+ case LOCALE_IPAPERSIZE: *cache_index = 10; return iPaperSizeW;
+ case LOCALE_ITIME: *cache_index = 11; return iTimeW;
+ case LOCALE_S1159: *cache_index = 12; return s1159W;
+ case LOCALE_S2359: *cache_index = 13; return s2359W;
+ case LOCALE_SCURRENCY: *cache_index = 14; return sCurrencyW;
+ case LOCALE_SDATE: *cache_index = 15; return sDateW;
+ case LOCALE_SDECIMAL: *cache_index = 16; return sDecimalW;
+ case LOCALE_SGROUPING: *cache_index = 17; return sGroupingW;
+ case LOCALE_SLIST: *cache_index = 18; return sListW;
+ case LOCALE_SLONGDATE: *cache_index = 19; return sLongDateW;
+ case LOCALE_SMONDECIMALSEP: *cache_index = 20; return sMonDecimalSepW;
+ case LOCALE_SMONGROUPING: *cache_index = 21; return sMonGroupingW;
+ case LOCALE_SMONTHOUSANDSEP: *cache_index = 22; return sMonThousandSepW;
+ case LOCALE_SNEGATIVESIGN: *cache_index = 23; return sNegativeSignW;
+ case LOCALE_SPOSITIVESIGN: *cache_index = 24; return sPositiveSignW;
+ case LOCALE_SSHORTDATE: *cache_index = 25; return sShortDateW;
+ case LOCALE_STHOUSAND: *cache_index = 26; return sThousandW;
+ case LOCALE_STIME: *cache_index = 27; return sTimeW;
+ case LOCALE_STIMEFORMAT: *cache_index = 28; return sTimeFormatW;
+ case LOCALE_SYEARMONTH: *cache_index = 29; return sYearMonthW;
/* The following are not listed under MSDN as supported,
* but seem to be used and also stored in the registry.
*/
- case LOCALE_ICOUNTRY: return iCountryW;
- case LOCALE_IDATE: return iDateW;
- case LOCALE_ILDATE: return iLDateW;
- case LOCALE_ITLZERO: return iTLZeroW;
- case LOCALE_SCOUNTRY: return sCountryW;
- case LOCALE_SABBREVLANGNAME: return sLanguageW;
+ case LOCALE_ICOUNTRY: *cache_index = 30; return iCountryW;
+ case LOCALE_IDATE: *cache_index = 31; return iDateW;
+ case LOCALE_ILDATE: *cache_index = 32; return iLDateW;
+ case LOCALE_ITLZERO: *cache_index = 33; return iTLZeroW;
+ case LOCALE_SCOUNTRY: *cache_index = 34; return sCountryW;
+ case LOCALE_SABBREVLANGNAME: *cache_index = 35; return sLanguageW;
/* The following are used in XP and later */
- case LOCALE_IDIGITSUBSTITUTION: return NumShapeW;
- case LOCALE_SNATIVEDIGITS: return sNativeDigitsW;
- case LOCALE_ITIMEMARKPOSN: return iTimePrefixW;
+ case LOCALE_IDIGITSUBSTITUTION: *cache_index = 36; return NumShapeW;
+ case LOCALE_SNATIVEDIGITS: *cache_index = 37; return sNativeDigitsW;
+ case LOCALE_ITIMEMARKPOSN: *cache_index = 38; return iTimePrefixW;
}
return NULL;
}
@@ -1130,7 +1141,7 @@ static const WCHAR *get_locale_value_name( DWORD lctype )
* Retrieve user-modified locale info from the registry.
* Return length, 0 on error, -1 if not found.
*/
-static INT get_registry_locale_info( LPCWSTR value, LPWSTR buffer, INT len )
+static INT get_registry_locale_info( LPCWSTR value, int cache_index, LPWSTR buffer, INT len )
{
DWORD size;
INT ret;
@@ -1140,54 +1151,92 @@ static INT get_registry_locale_info( LPCWSTR value, LPWSTR buffer, INT len )
KEY_VALUE_PARTIAL_INFORMATION *info;
static const int info_size = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
- if (!(hkey = create_registry_key())) return -1;
+ RtlEnterCriticalSection( &cache_section );
- RtlInitUnicodeString( &nameW, value );
- size = info_size + len * sizeof(WCHAR);
-
- if (!(info = HeapAlloc( GetProcessHeap(), 0, size )))
+ if (!cached_registry_values[cache_index])
{
+ if (!(hkey = create_registry_key()))
+ {
+ RtlLeaveCriticalSection( &cache_section );
+ return -1;
+ }
+
+ RtlInitUnicodeString( &nameW, value );
+ size = info_size + len * sizeof(WCHAR);
+
+ if (!(info = HeapAlloc( GetProcessHeap(), 0, size )))
+ {
+ NtClose( hkey );
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ RtlLeaveCriticalSection( &cache_section );
+ return 0;
+ }
+
+ status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, info, size, &size );
+
NtClose( hkey );
- SetLastError( ERROR_NOT_ENOUGH_MEMORY );
- return 0;
- }
- status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, info, size, &size );
+ if (!status)
+ {
+ INT length = (size - info_size) / sizeof(WCHAR);
+ LPWSTR cached_value;
- if (!status)
- {
- ret = (size - info_size) / sizeof(WCHAR);
- /* append terminating null if needed */
- if (!ret || ((WCHAR *)info->Data)[ret-1])
+ if (!length || ((WCHAR *)&info->Data)[length-1])
+ length++;
+
+ cached_value = HeapAlloc( GetProcessHeap(), 0, length * sizeof(WCHAR) );
+
+ if (!cached_value)
+ {
+ HeapFree( GetProcessHeap(), 0, info );
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ RtlLeaveCriticalSection( &cache_section );
+ return 0;
+ }
+
+ memcpy( cached_value, info->Data, (length-1) * sizeof(WCHAR) );
+ cached_value[length-1] = 0;
+ HeapFree( GetProcessHeap(), 0, info );
+ cached_registry_values[cache_index] = cached_value;
+ }
+ else
{
- if (ret < len || !buffer) ret++;
+ if (status == STATUS_BUFFER_OVERFLOW && !buffer)
+ {
+ ret = (size - info_size) / sizeof(WCHAR) + 1;
+ }
+ else if (status == STATUS_OBJECT_NAME_NOT_FOUND)
+ {
+ ret = -1;
+ }
else
{
- SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ SetLastError( RtlNtStatusToDosError(status) );
ret = 0;
}
- }
- if (ret && buffer)
- {
- memcpy( buffer, info->Data, (ret-1) * sizeof(WCHAR) );
- buffer[ret-1] = 0;
+ HeapFree( GetProcessHeap(), 0, info );
+ RtlLeaveCriticalSection( &cache_section );
+ return ret;
}
}
- else if (status == STATUS_BUFFER_OVERFLOW && !buffer)
- {
- ret = (size - info_size) / sizeof(WCHAR) + 1;
- }
- else if (status == STATUS_OBJECT_NAME_NOT_FOUND)
- {
- ret = -1;
- }
- else
+
+ ret = lstrlenW( cached_registry_values[cache_index] ) + 1;
+
+ if (buffer)
{
- SetLastError( RtlNtStatusToDosError(status) );
- ret = 0;
+ if (ret > len)
+ {
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ ret = 0;
+ }
+ else
+ {
+ lstrcpyW( buffer, cached_registry_values[cache_index] );
+ }
}
- NtClose( hkey );
- HeapFree( GetProcessHeap(), 0, info );
+
+ RtlLeaveCriticalSection( &cache_section );
+
return ret;
}
@@ -1314,14 +1363,15 @@ INT WINAPI GetLocaleInfoW( LCID lcid, LCTYPE lctype, LPWSTR buffer, INT len )
if (!(lcflags & LOCALE_NOUSEROVERRIDE) &&
lcid == convert_default_lcid( LOCALE_USER_DEFAULT, lctype ))
{
- const WCHAR *value = get_locale_value_name(lctype);
+ int cache_index;
+ const WCHAR *value = get_locale_value_name(lctype, &cache_index);
if (value)
{
if (lcflags & LOCALE_RETURN_NUMBER)
{
WCHAR tmp[16];
- ret = get_registry_locale_info( value, tmp, sizeof(tmp)/sizeof(WCHAR) );
+ ret = get_registry_locale_info( value, cache_index, tmp, sizeof(tmp)/sizeof(WCHAR) );
if (ret > 0)
{
WCHAR *end;
@@ -1341,7 +1391,7 @@ INT WINAPI GetLocaleInfoW( LCID lcid, LCTYPE lctype, LPWSTR buffer, INT len )
memcpy( buffer, &number, sizeof(number) );
}
}
- else ret = get_registry_locale_info( value, buffer, len );
+ else ret = get_registry_locale_info( value, cache_index, buffer, len );
if (ret != -1) return ret;
}
@@ -1512,9 +1562,10 @@ BOOL WINAPI SetLocaleInfoW( LCID lcid, LCTYPE lctype, LPCWSTR data )
UNICODE_STRING valueW;
NTSTATUS status;
HANDLE hkey;
+ int cache_index;
lctype &= 0xffff;
- value = get_locale_value_name( lctype );
+ value = get_locale_value_name( lctype, &cache_index );
if (!data || !value)
{
@@ -1539,6 +1590,11 @@ BOOL WINAPI SetLocaleInfoW( LCID lcid, LCTYPE lctype, LPCWSTR data )
RtlInitUnicodeString( &valueW, value );
status = NtSetValueKey( hkey, &valueW, 0, REG_SZ, data, (strlenW(data)+1)*sizeof(WCHAR) );
+ RtlEnterCriticalSection( &cache_section );
+ HeapFree( GetProcessHeap(), 0, cached_registry_values[cache_index] );
+ cached_registry_values[cache_index] = NULL;
+ RtlLeaveCriticalSection( &cache_section );
+
if (lctype == LOCALE_SSHORTDATE || lctype == LOCALE_SLONGDATE)
{
/* Set I-value from S value */
@@ -1568,12 +1624,17 @@ BOOL WINAPI SetLocaleInfoW( LCID lcid, LCTYPE lctype, LPCWSTR data )
else
lctype = LOCALE_ILDATE;
- value = get_locale_value_name( lctype );
+ value = get_locale_value_name( lctype, &cache_index );
WriteProfileStringW( intlW, value, szBuff );
RtlInitUnicodeString( &valueW, value );
status = NtSetValueKey( hkey, &valueW, 0, REG_SZ, szBuff, sizeof(szBuff) );
+
+ RtlEnterCriticalSection( &cache_section );
+ HeapFree( GetProcessHeap(), 0, cached_registry_values[cache_index] );
+ cached_registry_values[cache_index] = NULL;
+ RtlLeaveCriticalSection( &cache_section );
}
NtClose( hkey );
--
1.8.3.2
More information about the wine-patches
mailing list