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