mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-06 23:11:33 +00:00
kernel32: Move Get/SetLocaleInfoW() to kernelbase.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
830de63139
commit
6bcda47419
|
@ -704,7 +704,7 @@
|
|||
@ stub GetLinguistLangSize
|
||||
@ stdcall -import GetLocalTime(ptr)
|
||||
@ stdcall -import GetLocaleInfoA(long long ptr long)
|
||||
@ stdcall GetLocaleInfoW(long long ptr long)
|
||||
@ stdcall -import GetLocaleInfoW(long long ptr long)
|
||||
@ stdcall -import GetLocaleInfoEx(wstr long ptr long)
|
||||
@ stdcall GetLogicalDriveStringsA(long ptr)
|
||||
@ stdcall GetLogicalDriveStringsW(long ptr)
|
||||
|
@ -1421,7 +1421,7 @@
|
|||
# @ stub SetLocalPrimaryComputerNameW
|
||||
@ stdcall -import SetLocalTime(ptr)
|
||||
@ stdcall SetLocaleInfoA(long long str)
|
||||
@ stdcall SetLocaleInfoW(long long wstr)
|
||||
@ stdcall -import SetLocaleInfoW(long long wstr)
|
||||
@ stdcall SetMailslotInfo(long long)
|
||||
@ stub SetMessageWaitingIndicator
|
||||
# @ stub SetNamedPipeAttribute
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winuser.h" /* for RT_STRINGW */
|
||||
#include "winternl.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "winnls.h"
|
||||
|
@ -48,9 +47,6 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(nls);
|
||||
|
||||
#define LOCALE_LOCALEINFOFLAGSMASK (LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP|\
|
||||
LOCALE_RETURN_NUMBER|LOCALE_RETURN_GENITIVE_NAMES)
|
||||
|
||||
extern BOOL WINAPI Internal_EnumCalendarInfo( CALINFO_ENUMPROCW proc, LCID lcid, CALID id,
|
||||
CALTYPE type, BOOL unicode, BOOL ex,
|
||||
BOOL exex, LPARAM lparam );
|
||||
|
@ -66,107 +62,6 @@ extern BOOL WINAPI Internal_EnumTimeFormats( TIMEFMT_ENUMPROCW proc, LCID lcid,
|
|||
extern BOOL WINAPI Internal_EnumUILanguages( UILANGUAGE_ENUMPROCW proc, DWORD flags,
|
||||
LONG_PTR param, BOOL unicode );
|
||||
|
||||
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};
|
||||
static const WCHAR iCurrDigitsW[] = {'i','C','u','r','r','D','i','g','i','t','s',0};
|
||||
static const WCHAR iCurrencyW[] = {'i','C','u','r','r','e','n','c','y',0};
|
||||
static const WCHAR iDateW[] = {'i','D','a','t','e',0};
|
||||
static const WCHAR iDigitsW[] = {'i','D','i','g','i','t','s',0};
|
||||
static const WCHAR iFirstDayOfWeekW[] = {'i','F','i','r','s','t','D','a','y','O','f','W','e','e','k',0};
|
||||
static const WCHAR iFirstWeekOfYearW[] = {'i','F','i','r','s','t','W','e','e','k','O','f','Y','e','a','r',0};
|
||||
static const WCHAR iLDateW[] = {'i','L','D','a','t','e',0};
|
||||
static const WCHAR iLZeroW[] = {'i','L','Z','e','r','o',0};
|
||||
static const WCHAR iMeasureW[] = {'i','M','e','a','s','u','r','e',0};
|
||||
static const WCHAR iNegCurrW[] = {'i','N','e','g','C','u','r','r',0};
|
||||
static const WCHAR iNegNumberW[] = {'i','N','e','g','N','u','m','b','e','r',0};
|
||||
static const WCHAR iPaperSizeW[] = {'i','P','a','p','e','r','S','i','z','e',0};
|
||||
static const WCHAR iTLZeroW[] = {'i','T','L','Z','e','r','o',0};
|
||||
static const WCHAR iTimePrefixW[] = {'i','T','i','m','e','P','r','e','f','i','x',0};
|
||||
static const WCHAR iTimeW[] = {'i','T','i','m','e',0};
|
||||
static const WCHAR s1159W[] = {'s','1','1','5','9',0};
|
||||
static const WCHAR s2359W[] = {'s','2','3','5','9',0};
|
||||
static const WCHAR sCountryW[] = {'s','C','o','u','n','t','r','y',0};
|
||||
static const WCHAR sCurrencyW[] = {'s','C','u','r','r','e','n','c','y',0};
|
||||
static const WCHAR sDateW[] = {'s','D','a','t','e',0};
|
||||
static const WCHAR sDecimalW[] = {'s','D','e','c','i','m','a','l',0};
|
||||
static const WCHAR sGroupingW[] = {'s','G','r','o','u','p','i','n','g',0};
|
||||
static const WCHAR sLanguageW[] = {'s','L','a','n','g','u','a','g','e',0};
|
||||
static const WCHAR sListW[] = {'s','L','i','s','t',0};
|
||||
static const WCHAR sLongDateW[] = {'s','L','o','n','g','D','a','t','e',0};
|
||||
static const WCHAR sMonDecimalSepW[] = {'s','M','o','n','D','e','c','i','m','a','l','S','e','p',0};
|
||||
static const WCHAR sMonGroupingW[] = {'s','M','o','n','G','r','o','u','p','i','n','g',0};
|
||||
static const WCHAR sMonThousandSepW[] = {'s','M','o','n','T','h','o','u','s','a','n','d','S','e','p',0};
|
||||
static const WCHAR sNativeDigitsW[] = {'s','N','a','t','i','v','e','D','i','g','i','t','s',0};
|
||||
static const WCHAR sNegativeSignW[] = {'s','N','e','g','a','t','i','v','e','S','i','g','n',0};
|
||||
static const WCHAR sPositiveSignW[] = {'s','P','o','s','i','t','i','v','e','S','i','g','n',0};
|
||||
static const WCHAR sShortDateW[] = {'s','S','h','o','r','t','D','a','t','e',0};
|
||||
static const WCHAR sThousandW[] = {'s','T','h','o','u','s','a','n','d',0};
|
||||
static const WCHAR sTimeFormatW[] = {'s','T','i','m','e','F','o','r','m','a','t',0};
|
||||
static const WCHAR sTimeW[] = {'s','T','i','m','e',0};
|
||||
static const WCHAR sYearMonthW[] = {'s','Y','e','a','r','M','o','n','t','h',0};
|
||||
static const WCHAR NumShapeW[] = {'N','u','m','s','h','a','p','e',0};
|
||||
|
||||
static struct registry_value
|
||||
{
|
||||
DWORD lctype;
|
||||
const WCHAR *name;
|
||||
WCHAR *cached_value;
|
||||
} registry_values[] =
|
||||
{
|
||||
{ LOCALE_ICALENDARTYPE, iCalendarTypeW },
|
||||
{ LOCALE_ICURRDIGITS, iCurrDigitsW },
|
||||
{ LOCALE_ICURRENCY, iCurrencyW },
|
||||
{ LOCALE_IDIGITS, iDigitsW },
|
||||
{ LOCALE_IFIRSTDAYOFWEEK, iFirstDayOfWeekW },
|
||||
{ LOCALE_IFIRSTWEEKOFYEAR, iFirstWeekOfYearW },
|
||||
{ LOCALE_ILZERO, iLZeroW },
|
||||
{ LOCALE_IMEASURE, iMeasureW },
|
||||
{ LOCALE_INEGCURR, iNegCurrW },
|
||||
{ LOCALE_INEGNUMBER, iNegNumberW },
|
||||
{ LOCALE_IPAPERSIZE, iPaperSizeW },
|
||||
{ LOCALE_ITIME, iTimeW },
|
||||
{ LOCALE_S1159, s1159W },
|
||||
{ LOCALE_S2359, s2359W },
|
||||
{ LOCALE_SCURRENCY, sCurrencyW },
|
||||
{ LOCALE_SDATE, sDateW },
|
||||
{ LOCALE_SDECIMAL, sDecimalW },
|
||||
{ LOCALE_SGROUPING, sGroupingW },
|
||||
{ LOCALE_SLIST, sListW },
|
||||
{ LOCALE_SLONGDATE, sLongDateW },
|
||||
{ LOCALE_SMONDECIMALSEP, sMonDecimalSepW },
|
||||
{ LOCALE_SMONGROUPING, sMonGroupingW },
|
||||
{ LOCALE_SMONTHOUSANDSEP, sMonThousandSepW },
|
||||
{ LOCALE_SNEGATIVESIGN, sNegativeSignW },
|
||||
{ LOCALE_SPOSITIVESIGN, sPositiveSignW },
|
||||
{ LOCALE_SSHORTDATE, sShortDateW },
|
||||
{ LOCALE_STHOUSAND, sThousandW },
|
||||
{ LOCALE_STIME, sTimeW },
|
||||
{ LOCALE_STIMEFORMAT, sTimeFormatW },
|
||||
{ LOCALE_SYEARMONTH, sYearMonthW },
|
||||
/* The following are not listed under MSDN as supported,
|
||||
* but seem to be used and also stored in the registry.
|
||||
*/
|
||||
{ LOCALE_ICOUNTRY, iCountryW },
|
||||
{ LOCALE_IDATE, iDateW },
|
||||
{ LOCALE_ILDATE, iLDateW },
|
||||
{ LOCALE_ITLZERO, iTLZeroW },
|
||||
{ LOCALE_SCOUNTRY, sCountryW },
|
||||
{ LOCALE_SABBREVLANGNAME, sLanguageW },
|
||||
/* The following are used in XP and later */
|
||||
{ LOCALE_IDIGITSUBSTITUTION, NumShapeW },
|
||||
{ LOCALE_SNATIVEDIGITS, sNativeDigitsW },
|
||||
{ LOCALE_ITIMEMARKPOSN, iTimePrefixW }
|
||||
};
|
||||
|
||||
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 };
|
||||
|
||||
extern const unsigned short wctype_table[] DECLSPEC_HIDDEN;
|
||||
extern const unsigned short nameprep_char_type[] DECLSPEC_HIDDEN;
|
||||
extern const WCHAR nameprep_mapping[] DECLSPEC_HIDDEN;
|
||||
|
@ -190,34 +85,6 @@ static inline UINT get_lcid_codepage( LCID lcid )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* is_genitive_name_supported
|
||||
*
|
||||
* Determine could LCTYPE basically support genitive name form or not.
|
||||
*/
|
||||
static BOOL is_genitive_name_supported( LCTYPE lctype )
|
||||
{
|
||||
switch(lctype & 0xffff)
|
||||
{
|
||||
case LOCALE_SMONTHNAME1:
|
||||
case LOCALE_SMONTHNAME2:
|
||||
case LOCALE_SMONTHNAME3:
|
||||
case LOCALE_SMONTHNAME4:
|
||||
case LOCALE_SMONTHNAME5:
|
||||
case LOCALE_SMONTHNAME6:
|
||||
case LOCALE_SMONTHNAME7:
|
||||
case LOCALE_SMONTHNAME8:
|
||||
case LOCALE_SMONTHNAME9:
|
||||
case LOCALE_SMONTHNAME10:
|
||||
case LOCALE_SMONTHNAME11:
|
||||
case LOCALE_SMONTHNAME12:
|
||||
case LOCALE_SMONTHNAME13:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* create_registry_key
|
||||
*
|
||||
|
@ -385,283 +252,6 @@ BOOL WINAPI GetUserPreferredUILanguages( DWORD flags, ULONG *count, WCHAR *buffe
|
|||
return get_dummy_preferred_ui_language( flags, count, buffer, size );
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* get_locale_registry_value
|
||||
*
|
||||
* Gets the registry value name and cache for a given lctype.
|
||||
*/
|
||||
static struct registry_value *get_locale_registry_value( DWORD lctype )
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE( registry_values ); i++)
|
||||
if (registry_values[i].lctype == lctype)
|
||||
return ®istry_values[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* get_registry_locale_info
|
||||
*
|
||||
* Retrieve user-modified locale info from the registry.
|
||||
* Return length, 0 on error, -1 if not found.
|
||||
*/
|
||||
static INT get_registry_locale_info( struct registry_value *registry_value, LPWSTR buffer, INT len )
|
||||
{
|
||||
DWORD size;
|
||||
INT ret;
|
||||
HANDLE hkey;
|
||||
NTSTATUS status;
|
||||
UNICODE_STRING nameW;
|
||||
KEY_VALUE_PARTIAL_INFORMATION *info;
|
||||
static const int info_size = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
|
||||
|
||||
RtlEnterCriticalSection( &cache_section );
|
||||
|
||||
if (!registry_value->cached_value)
|
||||
{
|
||||
if (!(hkey = create_registry_key()))
|
||||
{
|
||||
RtlLeaveCriticalSection( &cache_section );
|
||||
return -1;
|
||||
}
|
||||
|
||||
RtlInitUnicodeString( &nameW, registry_value->name );
|
||||
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 );
|
||||
|
||||
/* try again with a bigger buffer when we have to return the correct size */
|
||||
if (status == STATUS_BUFFER_OVERFLOW && !buffer && size > info_size)
|
||||
{
|
||||
KEY_VALUE_PARTIAL_INFORMATION *new_info;
|
||||
if ((new_info = HeapReAlloc( GetProcessHeap(), 0, info, size )))
|
||||
{
|
||||
info = new_info;
|
||||
status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, info, size, &size );
|
||||
}
|
||||
}
|
||||
|
||||
NtClose( hkey );
|
||||
|
||||
if (!status)
|
||||
{
|
||||
INT length = (size - info_size) / sizeof(WCHAR);
|
||||
LPWSTR cached_value;
|
||||
|
||||
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 );
|
||||
registry_value->cached_value = cached_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (status == STATUS_BUFFER_OVERFLOW && !buffer)
|
||||
{
|
||||
ret = (size - info_size) / sizeof(WCHAR);
|
||||
}
|
||||
else if (status == STATUS_OBJECT_NAME_NOT_FOUND)
|
||||
{
|
||||
ret = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetLastError( RtlNtStatusToDosError(status) );
|
||||
ret = 0;
|
||||
}
|
||||
HeapFree( GetProcessHeap(), 0, info );
|
||||
RtlLeaveCriticalSection( &cache_section );
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = lstrlenW( registry_value->cached_value ) + 1;
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
if (ret > len)
|
||||
{
|
||||
SetLastError( ERROR_INSUFFICIENT_BUFFER );
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lstrcpyW( buffer, registry_value->cached_value );
|
||||
}
|
||||
}
|
||||
|
||||
RtlLeaveCriticalSection( &cache_section );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int get_value_base_by_lctype( LCTYPE lctype )
|
||||
{
|
||||
return lctype == LOCALE_ILANGUAGE || lctype == LOCALE_IDEFAULTLANGUAGE ? 16 : 10;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* GetLocaleInfoW (KERNEL32.@)
|
||||
*
|
||||
* See GetLocaleInfoA.
|
||||
*/
|
||||
INT WINAPI GetLocaleInfoW( LCID lcid, LCTYPE lctype, LPWSTR buffer, INT len )
|
||||
{
|
||||
HRSRC hrsrc;
|
||||
HGLOBAL hmem;
|
||||
INT ret;
|
||||
UINT lcflags;
|
||||
const WCHAR *p;
|
||||
unsigned int i;
|
||||
|
||||
if (len < 0 || (len && !buffer))
|
||||
{
|
||||
SetLastError( ERROR_INVALID_PARAMETER );
|
||||
return 0;
|
||||
}
|
||||
if (lctype & LOCALE_RETURN_GENITIVE_NAMES &&
|
||||
!is_genitive_name_supported( lctype ))
|
||||
{
|
||||
SetLastError( ERROR_INVALID_FLAGS );
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!len) buffer = NULL;
|
||||
|
||||
lcid = ConvertDefaultLocale( lcid );
|
||||
lcflags = lctype & LOCALE_LOCALEINFOFLAGSMASK;
|
||||
lctype &= 0xffff;
|
||||
|
||||
TRACE( "(lcid=0x%x,lctype=0x%x,%p,%d)\n", lcid, lctype, buffer, len );
|
||||
|
||||
/* first check for overrides in the registry */
|
||||
|
||||
if (!(lcflags & LOCALE_NOUSEROVERRIDE) && lcid == ConvertDefaultLocale( LOCALE_USER_DEFAULT ))
|
||||
{
|
||||
struct registry_value *value = get_locale_registry_value(lctype);
|
||||
|
||||
if (value)
|
||||
{
|
||||
if (lcflags & LOCALE_RETURN_NUMBER)
|
||||
{
|
||||
WCHAR tmp[16];
|
||||
ret = get_registry_locale_info( value, tmp, ARRAY_SIZE( tmp ));
|
||||
if (ret > 0)
|
||||
{
|
||||
WCHAR *end;
|
||||
UINT number = strtolW( tmp, &end, get_value_base_by_lctype( lctype ) );
|
||||
if (*end) /* invalid number */
|
||||
{
|
||||
SetLastError( ERROR_INVALID_FLAGS );
|
||||
return 0;
|
||||
}
|
||||
ret = sizeof(UINT)/sizeof(WCHAR);
|
||||
if (!buffer) return ret;
|
||||
if (ret > len)
|
||||
{
|
||||
SetLastError( ERROR_INSUFFICIENT_BUFFER );
|
||||
return 0;
|
||||
}
|
||||
memcpy( buffer, &number, sizeof(number) );
|
||||
}
|
||||
}
|
||||
else ret = get_registry_locale_info( value, buffer, len );
|
||||
|
||||
if (ret != -1) return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* now load it from kernel resources */
|
||||
|
||||
if (!(hrsrc = FindResourceExW( kernel32_handle, (LPWSTR)RT_STRING,
|
||||
ULongToPtr((lctype >> 4) + 1), lcid )))
|
||||
{
|
||||
SetLastError( ERROR_INVALID_FLAGS ); /* no such lctype */
|
||||
return 0;
|
||||
}
|
||||
if (!(hmem = LoadResource( kernel32_handle, hrsrc )))
|
||||
return 0;
|
||||
|
||||
p = LockResource( hmem );
|
||||
for (i = 0; i < (lctype & 0x0f); i++) p += *p + 1;
|
||||
|
||||
if (lcflags & LOCALE_RETURN_NUMBER) ret = sizeof(UINT)/sizeof(WCHAR);
|
||||
else if (is_genitive_name_supported( lctype ) && *p)
|
||||
{
|
||||
/* genitive form's stored after a null separator from a nominative */
|
||||
for (i = 1; i <= *p; i++) if (!p[i]) break;
|
||||
|
||||
if (i <= *p && (lcflags & LOCALE_RETURN_GENITIVE_NAMES))
|
||||
{
|
||||
ret = *p - i + 1;
|
||||
p += i;
|
||||
}
|
||||
else ret = i;
|
||||
}
|
||||
else
|
||||
ret = (lctype == LOCALE_FONTSIGNATURE) ? *p : *p + 1;
|
||||
|
||||
if (!buffer) return ret;
|
||||
|
||||
if (ret > len)
|
||||
{
|
||||
SetLastError( ERROR_INSUFFICIENT_BUFFER );
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lcflags & LOCALE_RETURN_NUMBER)
|
||||
{
|
||||
UINT number;
|
||||
WCHAR *end, *tmp = HeapAlloc( GetProcessHeap(), 0, (*p + 1) * sizeof(WCHAR) );
|
||||
if (!tmp) return 0;
|
||||
memcpy( tmp, p + 1, *p * sizeof(WCHAR) );
|
||||
tmp[*p] = 0;
|
||||
number = strtolW( tmp, &end, get_value_base_by_lctype( lctype ) );
|
||||
if (!*end)
|
||||
memcpy( buffer, &number, sizeof(number) );
|
||||
else /* invalid number */
|
||||
{
|
||||
SetLastError( ERROR_INVALID_FLAGS );
|
||||
ret = 0;
|
||||
}
|
||||
HeapFree( GetProcessHeap(), 0, tmp );
|
||||
|
||||
TRACE( "(lcid=0x%x,lctype=0x%x,%p,%d) returning number %d\n",
|
||||
lcid, lctype, buffer, len, number );
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy( buffer, p + 1, ret * sizeof(WCHAR) );
|
||||
if (lctype != LOCALE_FONTSIGNATURE) buffer[ret-1] = 0;
|
||||
|
||||
TRACE( "(lcid=0x%x,lctype=0x%x,%p,%d) returning %d %s\n",
|
||||
lcid, lctype, buffer, len, ret, debugstr_w(buffer) );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* SetLocaleInfoA [KERNEL32.@]
|
||||
*
|
||||
|
@ -713,97 +303,6 @@ BOOL WINAPI SetLocaleInfoA(LCID lcid, LCTYPE lctype, LPCSTR data)
|
|||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* SetLocaleInfoW (KERNEL32.@)
|
||||
*
|
||||
* See SetLocaleInfoA.
|
||||
*/
|
||||
BOOL WINAPI SetLocaleInfoW( LCID lcid, LCTYPE lctype, LPCWSTR data )
|
||||
{
|
||||
struct registry_value *value;
|
||||
static const WCHAR intlW[] = {'i','n','t','l',0 };
|
||||
UNICODE_STRING valueW;
|
||||
NTSTATUS status;
|
||||
HANDLE hkey;
|
||||
|
||||
lctype &= 0xffff;
|
||||
value = get_locale_registry_value( lctype );
|
||||
|
||||
if (!data || !value)
|
||||
{
|
||||
SetLastError( ERROR_INVALID_PARAMETER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (lctype == LOCALE_IDATE || lctype == LOCALE_ILDATE)
|
||||
{
|
||||
SetLastError( ERROR_INVALID_FLAGS );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TRACE("setting %x (%s) to %s\n", lctype, debugstr_w(value->name), debugstr_w(data) );
|
||||
|
||||
/* FIXME: should check that data to set is sane */
|
||||
|
||||
/* FIXME: profile functions should map to registry */
|
||||
WriteProfileStringW( intlW, value->name, data );
|
||||
|
||||
if (!(hkey = create_registry_key())) return FALSE;
|
||||
RtlInitUnicodeString( &valueW, value->name );
|
||||
status = NtSetValueKey( hkey, &valueW, 0, REG_SZ, data, (strlenW(data)+1)*sizeof(WCHAR) );
|
||||
|
||||
RtlEnterCriticalSection( &cache_section );
|
||||
HeapFree( GetProcessHeap(), 0, value->cached_value );
|
||||
value->cached_value = NULL;
|
||||
RtlLeaveCriticalSection( &cache_section );
|
||||
|
||||
if (lctype == LOCALE_SSHORTDATE || lctype == LOCALE_SLONGDATE)
|
||||
{
|
||||
/* Set I-value from S value */
|
||||
WCHAR *lpD, *lpM, *lpY;
|
||||
WCHAR szBuff[2];
|
||||
|
||||
lpD = strrchrW(data, 'd');
|
||||
lpM = strrchrW(data, 'M');
|
||||
lpY = strrchrW(data, 'y');
|
||||
|
||||
if (lpD <= lpM)
|
||||
{
|
||||
szBuff[0] = '1'; /* D-M-Y */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lpY <= lpM)
|
||||
szBuff[0] = '2'; /* Y-M-D */
|
||||
else
|
||||
szBuff[0] = '0'; /* M-D-Y */
|
||||
}
|
||||
|
||||
szBuff[1] = '\0';
|
||||
|
||||
if (lctype == LOCALE_SSHORTDATE)
|
||||
lctype = LOCALE_IDATE;
|
||||
else
|
||||
lctype = LOCALE_ILDATE;
|
||||
|
||||
value = get_locale_registry_value( lctype );
|
||||
|
||||
WriteProfileStringW( intlW, value->name, szBuff );
|
||||
|
||||
RtlInitUnicodeString( &valueW, value->name );
|
||||
status = NtSetValueKey( hkey, &valueW, 0, REG_SZ, szBuff, sizeof(szBuff) );
|
||||
|
||||
RtlEnterCriticalSection( &cache_section );
|
||||
HeapFree( GetProcessHeap(), 0, value->cached_value );
|
||||
value->cached_value = NULL;
|
||||
RtlLeaveCriticalSection( &cache_section );
|
||||
}
|
||||
|
||||
NtClose( hkey );
|
||||
return set_ntstatus( status );
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* SetCPGlobal (KERNEL32.@)
|
||||
*
|
||||
|
|
|
@ -544,7 +544,7 @@
|
|||
@ stdcall GetLocaleInfoA(long long ptr long)
|
||||
@ stdcall GetLocaleInfoEx(wstr long ptr long)
|
||||
@ stub GetLocaleInfoHelper
|
||||
@ stdcall GetLocaleInfoW(long long ptr long) kernel32.GetLocaleInfoW
|
||||
@ stdcall GetLocaleInfoW(long long ptr long)
|
||||
@ stdcall GetLogicalDriveStringsW(long ptr) kernel32.GetLogicalDriveStringsW
|
||||
@ stdcall GetLogicalDrives() kernel32.GetLogicalDrives
|
||||
@ stdcall GetLogicalProcessorInformation(ptr ptr)
|
||||
|
@ -1447,7 +1447,7 @@
|
|||
@ stub SetLastConsoleEventActive
|
||||
@ stdcall SetLastError(long) ntdll.RtlSetLastWin32Error
|
||||
@ stdcall SetLocalTime(ptr)
|
||||
@ stdcall SetLocaleInfoW(long long wstr) kernel32.SetLocaleInfoW
|
||||
@ stdcall SetLocaleInfoW(long long wstr)
|
||||
@ stdcall SetNamedPipeHandleState(long ptr ptr ptr)
|
||||
@ stdcall SetPriorityClass(long long)
|
||||
@ stdcall SetPrivateObjectSecurity(long ptr ptr ptr long)
|
||||
|
|
|
@ -98,6 +98,8 @@ static const struct registry_value
|
|||
{ LOCALE_ITIMEMARKPOSN, L"iTimePrefix" },
|
||||
};
|
||||
|
||||
static WCHAR *registry_cache[ARRAY_SIZE(registry_values)];
|
||||
|
||||
static const struct { UINT cp; const WCHAR *name; } codepage_names[] =
|
||||
{
|
||||
{ 37, L"IBM EBCDIC US Canada" },
|
||||
|
@ -338,6 +340,92 @@ static UINT get_lcid_codepage( LCID lcid, ULONG flags )
|
|||
}
|
||||
|
||||
|
||||
static BOOL is_genitive_name_supported( LCTYPE lctype )
|
||||
{
|
||||
switch (LOWORD(lctype))
|
||||
{
|
||||
case LOCALE_SMONTHNAME1:
|
||||
case LOCALE_SMONTHNAME2:
|
||||
case LOCALE_SMONTHNAME3:
|
||||
case LOCALE_SMONTHNAME4:
|
||||
case LOCALE_SMONTHNAME5:
|
||||
case LOCALE_SMONTHNAME6:
|
||||
case LOCALE_SMONTHNAME7:
|
||||
case LOCALE_SMONTHNAME8:
|
||||
case LOCALE_SMONTHNAME9:
|
||||
case LOCALE_SMONTHNAME10:
|
||||
case LOCALE_SMONTHNAME11:
|
||||
case LOCALE_SMONTHNAME12:
|
||||
case LOCALE_SMONTHNAME13:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int get_value_base_by_lctype( LCTYPE lctype )
|
||||
{
|
||||
return lctype == LOCALE_ILANGUAGE || lctype == LOCALE_IDEFAULTLANGUAGE ? 16 : 10;
|
||||
}
|
||||
|
||||
|
||||
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 INT get_registry_locale_info( const struct registry_value *registry_value, LPWSTR buffer, INT len )
|
||||
{
|
||||
DWORD size, index = registry_value - registry_values;
|
||||
INT ret;
|
||||
|
||||
RtlEnterCriticalSection( &locale_section );
|
||||
|
||||
if (!registry_cache[index])
|
||||
{
|
||||
size = len * sizeof(WCHAR);
|
||||
ret = RegQueryValueExW( intl_key, registry_value->name, NULL, NULL, (BYTE *)buffer, &size );
|
||||
if (!ret)
|
||||
{
|
||||
if (buffer && (registry_cache[index] = HeapAlloc( GetProcessHeap(), 0, size + sizeof(WCHAR) )))
|
||||
{
|
||||
memcpy( registry_cache[index], buffer, size );
|
||||
registry_cache[index][size / sizeof(WCHAR)] = 0;
|
||||
}
|
||||
RtlLeaveCriticalSection( &locale_section );
|
||||
return size / sizeof(WCHAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
RtlLeaveCriticalSection( &locale_section );
|
||||
if (ret == ERROR_FILE_NOT_FOUND) return -1;
|
||||
if (ret == ERROR_MORE_DATA) SetLastError( ERROR_INSUFFICIENT_BUFFER );
|
||||
else SetLastError( ret );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ret = lstrlenW( registry_cache[index] ) + 1;
|
||||
if (buffer)
|
||||
{
|
||||
if (ret > len)
|
||||
{
|
||||
SetLastError( ERROR_INSUFFICIENT_BUFFER );
|
||||
ret = 0;
|
||||
}
|
||||
else lstrcpyW( buffer, registry_cache[index] );
|
||||
}
|
||||
RtlLeaveCriticalSection( &locale_section );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static const CPTABLEINFO *get_codepage_table( UINT codepage )
|
||||
{
|
||||
unsigned int i;
|
||||
|
@ -2438,6 +2526,142 @@ INT WINAPI DECLSPEC_HOTPATCH GetLocaleInfoA( LCID lcid, LCTYPE lctype, char *buf
|
|||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* GetLocaleInfoW (kernelbase.@)
|
||||
*/
|
||||
INT WINAPI DECLSPEC_HOTPATCH GetLocaleInfoW( LCID lcid, LCTYPE lctype, WCHAR *buffer, INT len )
|
||||
{
|
||||
HRSRC hrsrc;
|
||||
HGLOBAL hmem;
|
||||
INT ret;
|
||||
UINT lcflags = lctype;
|
||||
const WCHAR *p;
|
||||
unsigned int i;
|
||||
|
||||
if (len < 0 || (len && !buffer))
|
||||
{
|
||||
SetLastError( ERROR_INVALID_PARAMETER );
|
||||
return 0;
|
||||
}
|
||||
if (lctype & LOCALE_RETURN_GENITIVE_NAMES && !is_genitive_name_supported( lctype ))
|
||||
{
|
||||
SetLastError( ERROR_INVALID_FLAGS );
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!len) buffer = NULL;
|
||||
|
||||
lcid = ConvertDefaultLocale( lcid );
|
||||
lctype = LOWORD(lctype);
|
||||
|
||||
TRACE( "(lcid=0x%x,lctype=0x%x,%p,%d)\n", lcid, lctype, buffer, len );
|
||||
|
||||
/* first check for overrides in the registry */
|
||||
|
||||
if (!(lcflags & LOCALE_NOUSEROVERRIDE) && lcid == ConvertDefaultLocale( LOCALE_USER_DEFAULT ))
|
||||
{
|
||||
const struct registry_value *value = get_locale_registry_value( lctype );
|
||||
|
||||
if (value)
|
||||
{
|
||||
if (lcflags & LOCALE_RETURN_NUMBER)
|
||||
{
|
||||
WCHAR tmp[16];
|
||||
ret = get_registry_locale_info( value, tmp, ARRAY_SIZE( tmp ));
|
||||
if (ret > 0)
|
||||
{
|
||||
WCHAR *end;
|
||||
UINT number = wcstol( tmp, &end, get_value_base_by_lctype( lctype ) );
|
||||
if (*end) /* invalid number */
|
||||
{
|
||||
SetLastError( ERROR_INVALID_FLAGS );
|
||||
return 0;
|
||||
}
|
||||
ret = sizeof(UINT) / sizeof(WCHAR);
|
||||
if (!len) return ret;
|
||||
if (ret > len)
|
||||
{
|
||||
SetLastError( ERROR_INSUFFICIENT_BUFFER );
|
||||
return 0;
|
||||
}
|
||||
memcpy( buffer, &number, sizeof(number) );
|
||||
}
|
||||
}
|
||||
else ret = get_registry_locale_info( value, buffer, len );
|
||||
|
||||
if (ret != -1) return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* now load it from kernel resources */
|
||||
|
||||
if (!(hrsrc = FindResourceExW( kernel32_handle, (LPWSTR)RT_STRING,
|
||||
ULongToPtr((lctype >> 4) + 1), lcid )))
|
||||
{
|
||||
SetLastError( ERROR_INVALID_FLAGS ); /* no such lctype */
|
||||
return 0;
|
||||
}
|
||||
if (!(hmem = LoadResource( kernel32_handle, hrsrc ))) return 0;
|
||||
|
||||
p = LockResource( hmem );
|
||||
for (i = 0; i < (lctype & 0x0f); i++) p += *p + 1;
|
||||
|
||||
if (lcflags & LOCALE_RETURN_NUMBER) ret = sizeof(UINT) / sizeof(WCHAR);
|
||||
else if (is_genitive_name_supported( lctype ) && *p)
|
||||
{
|
||||
/* genitive form is stored after a null separator from a nominative */
|
||||
for (i = 1; i <= *p; i++) if (!p[i]) break;
|
||||
|
||||
if (i <= *p && (lcflags & LOCALE_RETURN_GENITIVE_NAMES))
|
||||
{
|
||||
ret = *p - i + 1;
|
||||
p += i;
|
||||
}
|
||||
else ret = i;
|
||||
}
|
||||
else
|
||||
ret = (lctype == LOCALE_FONTSIGNATURE) ? *p : *p + 1;
|
||||
|
||||
if (!len) return ret;
|
||||
|
||||
if (ret > len)
|
||||
{
|
||||
SetLastError( ERROR_INSUFFICIENT_BUFFER );
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lcflags & LOCALE_RETURN_NUMBER)
|
||||
{
|
||||
UINT number;
|
||||
WCHAR *end, *tmp = HeapAlloc( GetProcessHeap(), 0, (*p + 1) * sizeof(WCHAR) );
|
||||
if (!tmp) return 0;
|
||||
memcpy( tmp, p + 1, *p * sizeof(WCHAR) );
|
||||
tmp[*p] = 0;
|
||||
number = wcstol( tmp, &end, get_value_base_by_lctype( lctype ) );
|
||||
if (!*end)
|
||||
memcpy( buffer, &number, sizeof(number) );
|
||||
else /* invalid number */
|
||||
{
|
||||
SetLastError( ERROR_INVALID_FLAGS );
|
||||
ret = 0;
|
||||
}
|
||||
HeapFree( GetProcessHeap(), 0, tmp );
|
||||
|
||||
TRACE( "(lcid=0x%x,lctype=0x%x,%p,%d) returning number %d\n",
|
||||
lcid, lctype, buffer, len, number );
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy( buffer, p + 1, ret * sizeof(WCHAR) );
|
||||
if (lctype != LOCALE_FONTSIGNATURE) buffer[ret-1] = 0;
|
||||
|
||||
TRACE( "(lcid=0x%x,lctype=0x%x,%p,%d) returning %d %s\n",
|
||||
lcid, lctype, buffer, len, ret, debugstr_w(buffer) );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* GetLocaleInfoEx (kernelbase.@)
|
||||
*/
|
||||
|
@ -2749,6 +2973,71 @@ INT WINAPI DECLSPEC_HOTPATCH ResolveLocaleName( LPCWSTR name, LPWSTR buffer, INT
|
|||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* SetLocaleInfoW (kernelbase.@)
|
||||
*/
|
||||
BOOL WINAPI DECLSPEC_HOTPATCH SetLocaleInfoW( LCID lcid, LCTYPE lctype, const WCHAR *data )
|
||||
{
|
||||
const struct registry_value *value;
|
||||
DWORD index;
|
||||
LSTATUS status;
|
||||
|
||||
lctype = LOWORD(lctype);
|
||||
value = get_locale_registry_value( lctype );
|
||||
|
||||
if (!data || !value)
|
||||
{
|
||||
SetLastError( ERROR_INVALID_PARAMETER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (lctype == LOCALE_IDATE || lctype == LOCALE_ILDATE)
|
||||
{
|
||||
SetLastError( ERROR_INVALID_FLAGS );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TRACE( "setting %x (%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 );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* SetCalendarInfoW (kernelbase.@)
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue