kernelbase: Implement GetNLSVersion/GetNLSVersionEx().

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2020-03-20 12:54:36 +01:00
parent 3795484e81
commit 86522976c9
5 changed files with 198 additions and 4 deletions

View File

@ -724,6 +724,8 @@
@ stdcall -import GetModuleHandleExA(long ptr ptr)
@ stdcall -import GetModuleHandleExW(long ptr ptr)
@ stdcall -import GetModuleHandleW(wstr)
@ stdcall -import GetNLSVersion(long long ptr)
@ stdcall -import GetNLSVersionEx(long wstr ptr)
# @ stub GetNamedPipeAttribute
# @ stub GetNamedPipeClientComputerNameA
# @ stub GetNamedPipeClientComputerNameW
@ -738,8 +740,6 @@
@ stdcall -arch=x86_64 GetNextUmsListItem(ptr)
@ stub GetNextVDMCommand
@ stub GetNlsSectionName
# @ stub GetNLSVersion
# @ stub GetNLSVersionEx
# @ stub GetNumaAvailableMemory
@ stdcall GetNumaAvailableMemoryNode(long ptr)
@ stdcall GetNumaAvailableMemoryNodeEx(long ptr)

View File

@ -85,6 +85,8 @@ static LANGID (WINAPI *pSetThreadUILanguage)(LANGID);
static LANGID (WINAPI *pGetThreadUILanguage)(VOID);
static INT (WINAPI *pNormalizeString)(NORM_FORM, LPCWSTR, INT, LPWSTR, INT);
static INT (WINAPI *pFindStringOrdinal)(DWORD, LPCWSTR lpStringSource, INT, LPCWSTR, INT, BOOL);
static BOOL (WINAPI *pGetNLSVersion)(NLS_FUNCTION,LCID,NLSVERSIONINFO*);
static BOOL (WINAPI *pGetNLSVersionEx)(NLS_FUNCTION,LPCWSTR,NLSVERSIONINFOEX*);
static NTSTATUS (WINAPI *pRtlNormalizeString)(ULONG, LPCWSTR, INT, LPWSTR, INT*);
static NTSTATUS (WINAPI *pRtlIsNormalizedString)(ULONG, LPCWSTR, INT, BOOLEAN*);
static NTSTATUS (WINAPI *pNtGetNlsSectionPtr)(ULONG,ULONG,void*,void**,SIZE_T*);
@ -125,6 +127,8 @@ static void InitFunctionPointers(void)
X(GetThreadUILanguage);
X(NormalizeString);
X(FindStringOrdinal);
X(GetNLSVersion);
X(GetNLSVersionEx);
mod = GetModuleHandleA("ntdll");
X(RtlUpcaseUnicodeChar);
@ -6633,6 +6637,134 @@ static void test_SpecialCasing(void)
}
}
static void test_NLSVersion(void)
{
static const GUID guid_null = { 0 };
static const GUID guid_def = { 0x000000001, 0x57ee, 0x1e5c, {0x00,0xb4,0xd0,0x00,0x0b,0xb1,0xe1,0x1e}};
static const GUID guid_fr = { 0x000000003, 0x57ee, 0x1e5c, {0x00,0xb4,0xd0,0x00,0x0b,0xb1,0xe1,0x1e}};
static const GUID guid_ja = { 0x000000046, 0x57ee, 0x1e5c, {0x00,0xb4,0xd0,0x00,0x0b,0xb1,0xe1,0x1e}};
BOOL ret;
NLSVERSIONINFOEX info;
if (!pGetNLSVersion)
{
win_skip( "GetNLSVersion not available\n" );
return;
}
SetLastError( 0xdeadbeef );
memset( &info, 0xcc, sizeof(info) );
info.dwNLSVersionInfoSize = sizeof(info);
ret = pGetNLSVersion( COMPARE_STRING, MAKELANGID( LANG_FRENCH, SUBLANG_FRENCH_CANADIAN ),
(NLSVERSIONINFO *)&info );
ok( ret, "GetNLSVersion failed err %u\n", GetLastError() );
ok( info.dwEffectiveId == MAKELANGID( LANG_FRENCH, SUBLANG_FRENCH_CANADIAN ),
"wrong id %x\n", info.dwEffectiveId );
ok( IsEqualIID( &info.guidCustomVersion, &guid_fr ) ||
broken( IsEqualIID( &info.guidCustomVersion, &guid_null )), /* <= win7 */
"wrong guid %s\n", debugstr_guid(&info.guidCustomVersion) );
SetLastError( 0xdeadbeef );
info.dwNLSVersionInfoSize = 8;
ret = pGetNLSVersion( COMPARE_STRING, LOCALE_USER_DEFAULT, (NLSVERSIONINFO *)&info );
ok( !ret, "GetNLSVersion succeeded\n" );
ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %u\n", GetLastError() );
SetLastError( 0xdeadbeef );
info.dwNLSVersionInfoSize = sizeof(info);
ret = pGetNLSVersion( 2, LOCALE_USER_DEFAULT, (NLSVERSIONINFO *)&info );
ok( !ret, "GetNLSVersion succeeded\n" );
ok( GetLastError() == ERROR_INVALID_FLAGS, "wrong error %u\n", GetLastError() );
SetLastError( 0xdeadbeef );
info.dwNLSVersionInfoSize = sizeof(info);
ret = pGetNLSVersion( COMPARE_STRING, 0xdeadbeef, (NLSVERSIONINFO *)&info );
ok( !ret, "GetNLSVersion succeeded\n" );
ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
if (pGetNLSVersionEx)
{
SetLastError( 0xdeadbeef );
memset( &info, 0xcc, sizeof(info) );
info.dwNLSVersionInfoSize = sizeof(info);
ret = pGetNLSVersionEx( COMPARE_STRING, L"ja-JP", &info );
ok( ret, "GetNLSVersionEx failed err %u\n", GetLastError() );
ok( info.dwEffectiveId == MAKELANGID( LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN ),
"wrong id %x\n", info.dwEffectiveId );
ok( IsEqualIID( &info.guidCustomVersion, &guid_ja ) ||
broken( IsEqualIID( &info.guidCustomVersion, &guid_null )), /* <= win7 */
"wrong guid %s\n", debugstr_guid(&info.guidCustomVersion) );
trace( "version %08x %08x %08x %s\n", info.dwNLSVersion, info.dwDefinedVersion, info.dwEffectiveId,
debugstr_guid(&info.guidCustomVersion) );
SetLastError( 0xdeadbeef );
memset( &info, 0xcc, sizeof(info) );
info.dwNLSVersionInfoSize = sizeof(info);
ret = pGetNLSVersionEx( COMPARE_STRING, L"fr", &info );
ok( !ret == !pIsValidLocaleName(L"fr"), "GetNLSVersionEx doesn't match IsValidLocaleName\n" );
if (ret)
{
ok( info.dwEffectiveId == MAKELANGID( LANG_FRENCH, SUBLANG_DEFAULT ),
"wrong id %x\n", info.dwEffectiveId );
ok( IsEqualIID( &info.guidCustomVersion, &guid_fr ) ||
broken( IsEqualIID( &info.guidCustomVersion, &guid_null )), /* <= win7 */
"wrong guid %s\n", debugstr_guid(&info.guidCustomVersion) );
}
SetLastError( 0xdeadbeef );
info.dwNLSVersionInfoSize = sizeof(info) - 1;
ret = pGetNLSVersionEx( COMPARE_STRING, L"en-US", &info );
ok( !ret, "GetNLSVersionEx succeeded\n" );
ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %u\n", GetLastError() );
SetLastError( 0xdeadbeef );
memset( &info, 0xcc, sizeof(info) );
info.dwNLSVersionInfoSize = offsetof( NLSVERSIONINFO, dwEffectiveId );
ret = pGetNLSVersionEx( COMPARE_STRING, L"en-US", &info );
ok( ret, "GetNLSVersionEx failed err %u\n", GetLastError() );
ok( info.dwEffectiveId == 0xcccccccc, "wrong id %x\n", info.dwEffectiveId );
SetLastError( 0xdeadbeef );
info.dwNLSVersionInfoSize = sizeof(info);
ret = pGetNLSVersionEx( 2, L"en-US", &info );
ok( !ret, "GetNLSVersionEx succeeded\n" );
ok( GetLastError() == ERROR_INVALID_FLAGS, "wrong error %u\n", GetLastError() );
SetLastError( 0xdeadbeef );
info.dwNLSVersionInfoSize = sizeof(info);
ret = pGetNLSVersionEx( COMPARE_STRING, L"foobar", &info );
ok( !ret, "GetNLSVersionEx succeeded\n" );
ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
SetLastError( 0xdeadbeef );
memset( &info, 0xcc, sizeof(info) );
info.dwNLSVersionInfoSize = sizeof(info);
ret = pGetNLSVersionEx( COMPARE_STRING, L"zz-XX", &info );
if (!ret) ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
ok( !ret == !pIsValidLocaleName(L"zz-XX"), "GetNLSVersionEx doesn't match IsValidLocaleName\n" );
if (ret)
{
ok( info.dwEffectiveId == LOCALE_CUSTOM_UNSPECIFIED, "wrong id %x\n", info.dwEffectiveId );
ok( IsEqualIID( &info.guidCustomVersion, &guid_def ),
"wrong guid %s\n", debugstr_guid(&info.guidCustomVersion) );
}
SetLastError( 0xdeadbeef );
memset( &info, 0xcc, sizeof(info) );
info.dwNLSVersionInfoSize = sizeof(info);
ret = pGetNLSVersionEx( COMPARE_STRING, LOCALE_NAME_INVARIANT, &info );
ok( ret, "GetNLSVersionEx failed err %u\n", GetLastError() );
if (ret)
{
ok( info.dwEffectiveId == LOCALE_INVARIANT, "wrong id %x\n", info.dwEffectiveId );
ok( IsEqualIID( &info.guidCustomVersion, &guid_def ) ||
broken( IsEqualIID( &info.guidCustomVersion, &guid_null )), /* <= win7 */
"wrong guid %s\n", debugstr_guid(&info.guidCustomVersion) );
}
else ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
}
else win_skip( "GetNLSVersionEx not available\n" );
}
START_TEST(locale)
{
InitFunctionPointers();
@ -6682,6 +6814,7 @@ START_TEST(locale)
test_SetThreadUILanguage();
test_NormalizeString();
test_SpecialCasing();
test_NLSVersion();
/* this requires collation table patch to make it MS compatible */
if (0) test_sorting();
}

View File

@ -565,8 +565,8 @@
@ stdcall GetModuleHandleExW(long ptr ptr)
@ stdcall GetModuleHandleW(wstr)
# @ stub GetModuleInformation
@ stub GetNLSVersion
@ stub GetNLSVersionEx
@ stdcall GetNLSVersion(long long ptr)
@ stdcall GetNLSVersionEx(long wstr ptr)
@ stub GetNamedLocaleHashNode
@ stub GetNamedPipeAttribute
@ stub GetNamedPipeClientComputerNameW

View File

@ -4260,6 +4260,60 @@ INT WINAPI DECLSPEC_HOTPATCH GetLocaleInfoEx( const WCHAR *locale, LCTYPE info,
}
/******************************************************************************
* GetNLSVersion (kernelbase.@)
*/
BOOL WINAPI DECLSPEC_HOTPATCH GetNLSVersion( NLS_FUNCTION func, LCID lcid, NLSVERSIONINFO *info )
{
WCHAR locale[LOCALE_NAME_MAX_LENGTH];
if (info->dwNLSVersionInfoSize < offsetof( NLSVERSIONINFO, dwEffectiveId ))
{
SetLastError( ERROR_INSUFFICIENT_BUFFER );
return FALSE;
}
if (!LCIDToLocaleName( lcid, locale, LOCALE_NAME_MAX_LENGTH, LOCALE_ALLOW_NEUTRAL_NAMES ))
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
return GetNLSVersionEx( func, locale, (NLSVERSIONINFOEX *)info );
}
/******************************************************************************
* GetNLSVersionEx (kernelbase.@)
*/
BOOL WINAPI DECLSPEC_HOTPATCH GetNLSVersionEx( NLS_FUNCTION func, const WCHAR *locale,
NLSVERSIONINFOEX *info )
{
LCID lcid = 0;
if (func != COMPARE_STRING)
{
SetLastError( ERROR_INVALID_FLAGS );
return FALSE;
}
if (info->dwNLSVersionInfoSize < sizeof(*info) &&
(info->dwNLSVersionInfoSize != offsetof( NLSVERSIONINFO, dwEffectiveId )))
{
SetLastError( ERROR_INSUFFICIENT_BUFFER );
return FALSE;
}
if (!(lcid = LocaleNameToLCID( locale, 0 ))) return FALSE;
info->dwNLSVersion = info->dwDefinedVersion = sort.version;
if (info->dwNLSVersionInfoSize >= sizeof(*info))
{
const struct sortguid *sortid = get_language_sort( locale );
info->dwEffectiveId = lcid;
info->guidCustomVersion = sortid ? sortid->id : default_sort_guid;
}
return TRUE;
}
/******************************************************************************
* GetOEMCP (kernelbase.@)
*/

View File

@ -735,6 +735,8 @@ typedef struct _nlsversioninfo {
DWORD dwNLSVersionInfoSize;
DWORD dwNLSVersion;
DWORD dwDefinedVersion;
DWORD dwEffectiveId;
GUID guidCustomVersion;
} NLSVERSIONINFO, *LPNLSVERSIONINFO;
typedef struct _nlsversioninfoex {
@ -745,6 +747,9 @@ typedef struct _nlsversioninfoex {
GUID guidCustomVersion;
} NLSVERSIONINFOEX, *LPNLSVERSIONINFOEX;
enum SYSNLS_FUNCTION { COMPARE_STRING = 1 };
typedef DWORD NLS_FUNCTION;
/* Define a bunch of callback types */
typedef BOOL (CALLBACK *CALINFO_ENUMPROCEXEX)(LPWSTR,CALID,LPWSTR,LPARAM);
@ -913,6 +918,8 @@ WINBASEAPI INT WINAPI GetLocaleInfoA(LCID,LCTYPE,LPSTR,INT);
WINBASEAPI INT WINAPI GetLocaleInfoW(LCID,LCTYPE,LPWSTR,INT);
#define GetLocaleInfo WINELIB_NAME_AW(GetLocaleInfo)
WINBASEAPI INT WINAPI GetLocaleInfoEx(LPCWSTR,LCTYPE,LPWSTR,INT);
WINBASEAPI BOOL WINAPI GetNLSVersion(NLS_FUNCTION,LCID,NLSVERSIONINFO*);
WINBASEAPI BOOL WINAPI GetNLSVersionEx(NLS_FUNCTION,LPCWSTR,NLSVERSIONINFOEX*);
WINBASEAPI INT WINAPI GetNumberFormatA(LCID,DWORD,LPCSTR,const NUMBERFMTA*,LPSTR,INT);
WINBASEAPI INT WINAPI GetNumberFormatW(LCID,DWORD,LPCWSTR,const NUMBERFMTW*,LPWSTR,INT);
#define GetNumberFormat WINELIB_NAME_AW(GetNumberFormat)