3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: dll/win32/kernel32/file/lang.c
6 * PURPOSE: National Laguage Support related funcs
7 * PROGRAMMER: Thomas Weidenmueller
24 #include "lcformat_private.h"
26 /* FIXME: these are included in winnls.h, however including this file causes alot of
27 conflicting type errors. */
29 #define LOCALE_RETURN_NUMBER 0x20000000
30 #define LOCALE_USE_CP_ACP 0x40000000
31 #define LOCALE_LOCALEINFOFLAGSMASK (LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP|\
32 LOCALE_RETURN_NUMBER|LOCALE_RETURN_GENITIVE_NAMES)
33 #define CALINFO_MAX_YEAR 2029
35 //static LCID SystemLocale = MAKELCID(LANG_ENGLISH, SORT_DEFAULT);
37 //static RTL_CRITICAL_SECTION LocalesListLock;
39 extern int wine_fold_string(int flags
, const WCHAR
*src
, int srclen
, WCHAR
*dst
, int dstlen
);
40 extern int wine_get_sortkey(int flags
, const WCHAR
*src
, int srclen
, char *dst
, int dstlen
);
41 extern int wine_compare_string(int flags
, const WCHAR
*str1
, int len1
, const WCHAR
*str2
, int len2
);
47 UILANGUAGE_ENUMPROCA procA
;
48 UILANGUAGE_ENUMPROCW procW
;
52 } ENUM_UILANG_CALLBACK
;
54 static const WCHAR szLocaleKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NLS\\Locale";
55 static const WCHAR szLangGroupsKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NLS\\Language Groups";
57 /***********************************************************************
58 * is_genitive_name_supported
60 * Determine could LCTYPE basically support genitive name form or not.
62 static BOOL
is_genitive_name_supported( LCTYPE lctype
)
64 switch(lctype
& 0xffff)
66 case LOCALE_SMONTHNAME1
:
67 case LOCALE_SMONTHNAME2
:
68 case LOCALE_SMONTHNAME3
:
69 case LOCALE_SMONTHNAME4
:
70 case LOCALE_SMONTHNAME5
:
71 case LOCALE_SMONTHNAME6
:
72 case LOCALE_SMONTHNAME7
:
73 case LOCALE_SMONTHNAME8
:
74 case LOCALE_SMONTHNAME9
:
75 case LOCALE_SMONTHNAME10
:
76 case LOCALE_SMONTHNAME11
:
77 case LOCALE_SMONTHNAME12
:
78 case LOCALE_SMONTHNAME13
:
85 /***********************************************************************
88 * Create the Control Panel\\International registry key.
90 static inline HANDLE
create_registry_key(void)
92 static const WCHAR intlW
[] = {'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
93 'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
94 OBJECT_ATTRIBUTES attr
;
98 if (RtlOpenCurrentUser( KEY_ALL_ACCESS
, &hkey
) != STATUS_SUCCESS
) return 0;
100 attr
.Length
= sizeof(attr
);
101 attr
.RootDirectory
= hkey
;
102 attr
.ObjectName
= &nameW
;
104 attr
.SecurityDescriptor
= NULL
;
105 attr
.SecurityQualityOfService
= NULL
;
106 RtlInitUnicodeString( &nameW
, intlW
);
108 if (NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
) hkey
= 0;
109 NtClose( attr
.RootDirectory
);
113 /******************************************************************************
115 * RIPPED FROM WINE's dlls\kernel\locale.c rev 1.42
117 * ConvertDefaultLocale (KERNEL32.@)
119 * Convert a default locale identifier into a real identifier.
122 * lcid [I] LCID identifier of the locale to convert
125 * lcid unchanged, if not a default locale or its sublanguage is
126 * not SUBLANG_NEUTRAL.
127 * GetSystemDefaultLCID(), if lcid == LOCALE_SYSTEM_DEFAULT.
128 * GetUserDefaultLCID(), if lcid == LOCALE_USER_DEFAULT or LOCALE_NEUTRAL.
129 * Otherwise, lcid with sublanguage changed to SUBLANG_DEFAULT.
132 ConvertDefaultLocale(LCID lcid
)
138 case LOCALE_SYSTEM_DEFAULT
:
139 lcid
= GetSystemDefaultLCID();
142 case LOCALE_USER_DEFAULT
:
144 lcid
= GetUserDefaultLCID();
148 /* Replace SUBLANG_NEUTRAL with SUBLANG_DEFAULT */
149 langid
= LANGIDFROMLCID(lcid
);
150 if (SUBLANGID(langid
) == SUBLANG_NEUTRAL
)
152 langid
= MAKELANGID(PRIMARYLANGID(langid
), SUBLANG_DEFAULT
);
153 lcid
= MAKELCID(langid
, SORTIDFROMLCID(lcid
));
161 static BOOL
NLS_RegEnumValue(HANDLE hKey
, UINT ulIndex
,
162 LPWSTR szValueName
, ULONG valueNameSize
,
163 LPWSTR szValueData
, ULONG valueDataSize
)
166 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
169 if (NtEnumerateValueKey( hKey
, ulIndex
, KeyValueFullInformation
,
170 buffer
, sizeof(buffer
), &dwLen
) != STATUS_SUCCESS
||
171 info
->NameLength
> valueNameSize
||
172 info
->DataLength
> valueDataSize
)
177 DPRINT("info->Name %s info->DataLength %d\n", info
->Name
, info
->DataLength
);
179 memcpy( szValueName
, info
->Name
, info
->NameLength
);
180 szValueName
[info
->NameLength
/ sizeof(WCHAR
)] = '\0';
181 memcpy( szValueData
, buffer
+ info
->DataOffset
, info
->DataLength
);
182 szValueData
[info
->DataLength
/ sizeof(WCHAR
)] = '\0';
184 DPRINT("returning %s %s\n", szValueName
, szValueData
);
189 static HANDLE
NLS_RegOpenKey(HANDLE hRootKey
, LPCWSTR szKeyName
)
191 UNICODE_STRING keyName
;
192 OBJECT_ATTRIBUTES attr
;
195 RtlInitUnicodeString( &keyName
, szKeyName
);
196 InitializeObjectAttributes(&attr
, &keyName
, OBJ_CASE_INSENSITIVE
, hRootKey
, NULL
);
198 if (NtOpenKey( &hkey
, KEY_ALL_ACCESS
, &attr
) != STATUS_SUCCESS
)
200 SetLastError( ERROR_BADDB
);
207 static BOOL
NLS_RegEnumSubKey(HANDLE hKey
, UINT ulIndex
, LPWSTR szKeyName
,
211 KEY_BASIC_INFORMATION
*info
= (KEY_BASIC_INFORMATION
*)buffer
;
214 if (NtEnumerateKey( hKey
, ulIndex
, KeyBasicInformation
, buffer
,
215 sizeof(buffer
), &dwLen
) != STATUS_SUCCESS
||
216 info
->NameLength
> keyNameSize
)
221 DPRINT("info->Name %s info->NameLength %d\n", info
->Name
, info
->NameLength
);
223 memcpy( szKeyName
, info
->Name
, info
->NameLength
);
224 szKeyName
[info
->NameLength
/ sizeof(WCHAR
)] = '\0';
226 DPRINT("returning %s\n", szKeyName
);
230 static BOOL
NLS_RegGetDword(HANDLE hKey
, LPCWSTR szValueName
, DWORD
*lpVal
)
233 const KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
234 DWORD dwSize
= sizeof(buffer
);
235 UNICODE_STRING valueName
;
237 RtlInitUnicodeString( &valueName
, szValueName
);
239 DPRINT("%p, %s\n", hKey
, szValueName
);
240 if (NtQueryValueKey( hKey
, &valueName
, KeyValuePartialInformation
,
241 buffer
, dwSize
, &dwSize
) == STATUS_SUCCESS
&&
242 info
->DataLength
== sizeof(DWORD
))
244 memcpy(lpVal
, info
->Data
, sizeof(DWORD
));
251 static BOOL
NLS_GetLanguageGroupName(LGRPID lgrpid
, LPWSTR szName
, ULONG nameSize
)
254 LPCWSTR szResourceName
= MAKEINTRESOURCEW(((lgrpid
+ 0x2000) >> 4) + 1);
258 /* FIXME: Is it correct to use the system default langid? */
259 langId
= GetSystemDefaultLangID();
261 if (SUBLANGID(langId
) == SUBLANG_NEUTRAL
)
262 langId
= MAKELANGID( PRIMARYLANGID(langId
), SUBLANG_DEFAULT
);
264 hResource
= FindResourceExW( hCurrentModule
, (LPWSTR
)RT_STRING
, szResourceName
, langId
);
268 HGLOBAL hResDir
= LoadResource( hCurrentModule
, hResource
);
272 ULONG iResourceIndex
= lgrpid
& 0xf;
273 LPCWSTR lpResEntry
= LockResource( hResDir
);
276 for (i
= 0; i
< iResourceIndex
; i
++)
277 lpResEntry
+= *lpResEntry
+ 1;
279 if (*lpResEntry
< nameSize
)
281 memcpy( szName
, lpResEntry
+ 1, *lpResEntry
* sizeof(WCHAR
) );
282 szName
[*lpResEntry
] = '\0';
287 FreeResource( hResource
);
289 else DPRINT1("FindResourceExW() failed\n");
295 /* Callback function ptrs for EnumLanguageGrouplocalesA/W */
298 LANGGROUPLOCALE_ENUMPROCA procA
;
299 LANGGROUPLOCALE_ENUMPROCW procW
;
303 } ENUMLANGUAGEGROUPLOCALE_CALLBACKS
;
305 /* Internal implementation of EnumLanguageGrouplocalesA/W */
306 static BOOL
NLS_EnumLanguageGroupLocales(ENUMLANGUAGEGROUPLOCALE_CALLBACKS
*lpProcs
)
308 static const WCHAR szAlternateSortsKeyName
[] = {
309 'A','l','t','e','r','n','a','t','e',' ','S','o','r','t','s','\0'
311 WCHAR szNumber
[10], szValue
[4];
313 BOOL bContinue
= TRUE
, bAlternate
= FALSE
;
315 ULONG ulIndex
= 1; /* Ignore default entry of 1st key */
317 if (!lpProcs
|| !lpProcs
->lgrpid
|| lpProcs
->lgrpid
> LGRPID_ARMENIAN
)
319 SetLastError(ERROR_INVALID_PARAMETER
);
323 if (lpProcs
->dwFlags
)
325 SetLastError(ERROR_INVALID_FLAGS
);
329 hKey
= NLS_RegOpenKey( 0, szLocaleKeyName
);
333 DPRINT1("NLS_RegOpenKey() failed\n");
339 if (NLS_RegEnumValue( hKey
, ulIndex
, szNumber
, sizeof(szNumber
),
340 szValue
, sizeof(szValue
) ))
342 lgrpid
= wcstoul( szValue
, NULL
, 16 );
344 DPRINT("lcid %s, grpid %d (%smatched)\n", szNumber
,
345 lgrpid
, lgrpid
== lpProcs
->lgrpid
? "" : "not ");
347 if (lgrpid
== lpProcs
->lgrpid
)
351 lcid
= wcstoul( szNumber
, NULL
, 16 );
353 /* FIXME: native returns extra text for a few (17/150) locales, e.g:
354 * '00000437 ;Georgian'
355 * At present we only pass the LCID string.
359 bContinue
= lpProcs
->procW( lgrpid
, lcid
, szNumber
, lpProcs
->lParam
);
362 char szNumberA
[sizeof(szNumber
)/sizeof(WCHAR
)];
364 WideCharToMultiByte(CP_ACP
, 0, szNumber
, -1, szNumberA
, sizeof(szNumberA
), 0, 0);
366 bContinue
= lpProcs
->procA( lgrpid
, lcid
, szNumberA
, lpProcs
->lParam
);
374 /* Finished enumerating this key */
377 /* Enumerate alternate sorts also */
378 hKey
= NLS_RegOpenKey( hKey
, szAlternateSortsKeyName
);
383 bContinue
= FALSE
; /* Finished both keys */
402 EnumLanguageGroupLocalesA(
403 LANGGROUPLOCALE_ENUMPROCA lpLangGroupLocaleEnumProc
,
404 LGRPID LanguageGroup
,
408 ENUMLANGUAGEGROUPLOCALE_CALLBACKS callbacks
;
410 DPRINT("(%p,0x%08X,0x%08X,0x%08lX)\n", lpLangGroupLocaleEnumProc
, LanguageGroup
, dwFlags
, lParam
);
412 callbacks
.procA
= lpLangGroupLocaleEnumProc
;
413 callbacks
.procW
= NULL
;
414 callbacks
.dwFlags
= dwFlags
;
415 callbacks
.lgrpid
= LanguageGroup
;
416 callbacks
.lParam
= lParam
;
418 return NLS_EnumLanguageGroupLocales( lpLangGroupLocaleEnumProc
? &callbacks
: NULL
);
427 EnumLanguageGroupLocalesW(
428 LANGGROUPLOCALE_ENUMPROCW lpLangGroupLocaleEnumProc
,
429 LGRPID LanguageGroup
,
433 ENUMLANGUAGEGROUPLOCALE_CALLBACKS callbacks
;
435 DPRINT("(%p,0x%08X,0x%08X,0x%08lX)\n", lpLangGroupLocaleEnumProc
, LanguageGroup
, dwFlags
, lParam
);
437 callbacks
.procA
= NULL
;
438 callbacks
.procW
= lpLangGroupLocaleEnumProc
;
439 callbacks
.dwFlags
= dwFlags
;
440 callbacks
.lgrpid
= LanguageGroup
;
441 callbacks
.lParam
= lParam
;
443 return NLS_EnumLanguageGroupLocales( lpLangGroupLocaleEnumProc
? &callbacks
: NULL
);
447 /* Callback function ptrs for EnumSystemCodePagesA/W */
450 CODEPAGE_ENUMPROCA procA
;
451 CODEPAGE_ENUMPROCW procW
;
453 } ENUMSYSTEMCODEPAGES_CALLBACKS
;
455 /* Internal implementation of EnumSystemCodePagesA/W */
456 static BOOL
NLS_EnumSystemCodePages(ENUMSYSTEMCODEPAGES_CALLBACKS
*lpProcs
)
458 WCHAR szNumber
[5 + 1], szValue
[MAX_PATH
];
460 BOOL bContinue
= TRUE
;
465 SetLastError(ERROR_INVALID_PARAMETER
);
469 switch (lpProcs
->dwFlags
)
475 SetLastError(ERROR_INVALID_FLAGS
);
479 hKey
= NLS_RegOpenKey(0, L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage");
482 DPRINT1("NLS_RegOpenKey() failed\n");
488 if (NLS_RegEnumValue(hKey
, ulIndex
, szNumber
, sizeof(szNumber
),
489 szValue
, sizeof(szValue
)))
491 if ((lpProcs
->dwFlags
== CP_SUPPORTED
)||
492 ((lpProcs
->dwFlags
== CP_INSTALLED
)&&(wcslen(szValue
) > 2)))
496 bContinue
= lpProcs
->procW(szNumber
);
500 char szNumberA
[sizeof(szNumber
)/sizeof(WCHAR
)];
502 WideCharToMultiByte(CP_ACP
, 0, szNumber
, -1, szNumberA
, sizeof(szNumberA
), 0, 0);
503 bContinue
= lpProcs
->procA(szNumberA
);
509 } else bContinue
= FALSE
;
526 EnumSystemCodePagesW (
527 CODEPAGE_ENUMPROCW lpCodePageEnumProc
,
531 ENUMSYSTEMCODEPAGES_CALLBACKS procs
;
533 DPRINT("(%p,0x%08X,0x%08lX)\n", lpCodePageEnumProc
, dwFlags
);
536 procs
.procW
= lpCodePageEnumProc
;
537 procs
.dwFlags
= dwFlags
;
539 return NLS_EnumSystemCodePages(lpCodePageEnumProc
? &procs
: NULL
);
548 EnumSystemCodePagesA (
549 CODEPAGE_ENUMPROCA lpCodePageEnumProc
,
553 ENUMSYSTEMCODEPAGES_CALLBACKS procs
;
555 DPRINT("(%p,0x%08X,0x%08lX)\n", lpCodePageEnumProc
, dwFlags
);
557 procs
.procA
= lpCodePageEnumProc
;
559 procs
.dwFlags
= dwFlags
;
561 return NLS_EnumSystemCodePages(lpCodePageEnumProc
? &procs
: NULL
);
572 GEOID ParentGeoId
, // reserved
573 GEO_ENUMPROC lpGeoEnumProc
)
575 WCHAR szNumber
[5 + 1];
579 DPRINT("(0x%08X,0x%08X,%p)\n", GeoClass
, ParentGeoId
, lpGeoEnumProc
);
581 if(!lpGeoEnumProc
|| GeoClass
!= GEOCLASS_NATION
)
583 SetLastError(ERROR_INVALID_PARAMETER
);
587 hKey
= NLS_RegOpenKey(0, L
"\\REGISTRY\\Machine\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Country List");
590 DPRINT1("NLS_RegOpenKey() failed\n");
594 while (NLS_RegEnumSubKey(hKey
, ulIndex
, szNumber
, sizeof(szNumber
)))
596 BOOL bContinue
= TRUE
;
598 HANDLE hSubKey
= NLS_RegOpenKey(hKey
, szNumber
);
602 if (NLS_RegGetDword(hSubKey
, L
"CountryCode", &dwGeoId
))
604 if (!lpGeoEnumProc(dwGeoId
))
624 /* Callback function ptrs for EnumSystemLanguageGroupsA/W */
627 LANGUAGEGROUP_ENUMPROCA procA
;
628 LANGUAGEGROUP_ENUMPROCW procW
;
631 } ENUMLANGUAGEGROUP_CALLBACKS
;
634 /* Internal implementation of EnumSystemLanguageGroupsA/W */
635 static BOOL
NLS_EnumSystemLanguageGroups(ENUMLANGUAGEGROUP_CALLBACKS
*lpProcs
)
637 WCHAR szNumber
[10], szValue
[4];
639 BOOL bContinue
= TRUE
;
644 SetLastError(ERROR_INVALID_PARAMETER
);
648 switch (lpProcs
->dwFlags
)
651 /* Default to LGRPID_INSTALLED */
652 lpProcs
->dwFlags
= LGRPID_INSTALLED
;
653 /* Fall through... */
654 case LGRPID_INSTALLED
:
655 case LGRPID_SUPPORTED
:
658 SetLastError(ERROR_INVALID_FLAGS
);
662 hKey
= NLS_RegOpenKey( 0, szLangGroupsKeyName
);
666 DPRINT1("NLS_RegOpenKey() failed, KeyName='%S'\n", szLangGroupsKeyName
);
672 if (NLS_RegEnumValue( hKey
, ulIndex
, szNumber
, sizeof(szNumber
),
673 szValue
, sizeof(szValue
) ))
675 BOOL bInstalled
= szValue
[0] == '1' ? TRUE
: FALSE
;
676 LGRPID lgrpid
= wcstoul( szNumber
, NULL
, 16 );
678 DPRINT("grpid %s (%sinstalled)\n", szNumber
,
679 bInstalled
? "" : "not ");
681 if (lpProcs
->dwFlags
== LGRPID_SUPPORTED
|| bInstalled
)
685 if (!NLS_GetLanguageGroupName( lgrpid
, szGrpName
, sizeof(szGrpName
) / sizeof(WCHAR
) ))
689 bContinue
= lpProcs
->procW( lgrpid
, szNumber
, szGrpName
, lpProcs
->dwFlags
,
693 char szNumberA
[sizeof(szNumber
)/sizeof(WCHAR
)];
696 /* FIXME: MSDN doesn't say which code page the W->A translation uses,
697 * or whether the language names are ever localised. Assume CP_ACP.
700 WideCharToMultiByte(CP_ACP
, 0, szNumber
, -1, szNumberA
, sizeof(szNumberA
), 0, 0);
701 WideCharToMultiByte(CP_ACP
, 0, szGrpName
, -1, szGrpNameA
, sizeof(szGrpNameA
), 0, 0);
703 bContinue
= lpProcs
->procA( lgrpid
, szNumberA
, szGrpNameA
, lpProcs
->dwFlags
,
729 EnumSystemLanguageGroupsA(
730 LANGUAGEGROUP_ENUMPROCA pLangGroupEnumProc
,
734 ENUMLANGUAGEGROUP_CALLBACKS procs
;
736 DPRINT("(%p,0x%08X,0x%08lX)\n", pLangGroupEnumProc
, dwFlags
, lParam
);
738 procs
.procA
= pLangGroupEnumProc
;
740 procs
.dwFlags
= dwFlags
;
741 procs
.lParam
= lParam
;
743 return NLS_EnumSystemLanguageGroups( pLangGroupEnumProc
? &procs
: NULL
);
752 EnumSystemLanguageGroupsW(
753 LANGUAGEGROUP_ENUMPROCW pLangGroupEnumProc
,
757 ENUMLANGUAGEGROUP_CALLBACKS procs
;
759 DPRINT("(%p,0x%08X,0x%08lX)\n", pLangGroupEnumProc
, dwFlags
, lParam
);
762 procs
.procW
= pLangGroupEnumProc
;
763 procs
.dwFlags
= dwFlags
;
764 procs
.lParam
= lParam
;
766 return NLS_EnumSystemLanguageGroups( pLangGroupEnumProc
? &procs
: NULL
);
770 /* Callback function ptrs for EnumSystemLocalesA/W */
773 LOCALE_ENUMPROCA procA
;
774 LOCALE_ENUMPROCW procW
;
776 } ENUMSYSTEMLOCALES_CALLBACKS
;
779 /* Internal implementation of EnumSystemLocalesA/W */
780 static BOOL
NLS_EnumSystemLocales(ENUMSYSTEMLOCALES_CALLBACKS
*lpProcs
)
782 WCHAR szNumber
[10], szValue
[4];
784 BOOL bContinue
= TRUE
;
789 SetLastError(ERROR_INVALID_PARAMETER
);
793 /* Passing 0 flags behaves like LCID_SUPPORTED */
794 if (lpProcs
->dwFlags
== 0)
796 lpProcs
->dwFlags
= LCID_SUPPORTED
;
799 switch (lpProcs
->dwFlags
)
801 case LCID_ALTERNATE_SORTS
:
806 SetLastError(ERROR_INVALID_FLAGS
);
810 hKey
= NLS_RegOpenKey(0, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\Locale");
814 DPRINT1("NLS_RegOpenKey() failed\n");
820 if (NLS_RegEnumValue( hKey
, ulIndex
, szNumber
, sizeof(szNumber
),
821 szValue
, sizeof(szValue
)))
823 if ((lpProcs
->dwFlags
== LCID_SUPPORTED
)||
824 ((lpProcs
->dwFlags
== LCID_INSTALLED
)&&(wcslen(szValue
) > 0)))
828 bContinue
= lpProcs
->procW(szNumber
);
832 char szNumberA
[sizeof(szNumber
)/sizeof(WCHAR
)];
834 WideCharToMultiByte(CP_ACP
, 0, szNumber
, -1, szNumberA
, sizeof(szNumberA
), 0, 0);
835 bContinue
= lpProcs
->procA(szNumberA
);
860 LOCALE_ENUMPROCA lpLocaleEnumProc
,
864 ENUMSYSTEMLOCALES_CALLBACKS procs
;
866 DPRINT("(%p,0x%08X)\n", lpLocaleEnumProc
, dwFlags
);
868 procs
.procA
= lpLocaleEnumProc
;
870 procs
.dwFlags
= dwFlags
;
872 return NLS_EnumSystemLocales(lpLocaleEnumProc
? &procs
: NULL
);
882 LOCALE_ENUMPROCW lpLocaleEnumProc
,
886 ENUMSYSTEMLOCALES_CALLBACKS procs
;
888 DPRINT("(%p,0x%08X)\n", lpLocaleEnumProc
, dwFlags
);
891 procs
.procW
= lpLocaleEnumProc
;
892 procs
.dwFlags
= dwFlags
;
894 return NLS_EnumSystemLocales(lpLocaleEnumProc
? &procs
: NULL
);
898 static BOOL CALLBACK
enum_uilang_proc_a( HMODULE hModule
, LPCSTR type
,
899 LPCSTR name
, WORD LangID
, LONG_PTR lParam
)
901 ENUM_UILANG_CALLBACK
*enum_uilang
= (ENUM_UILANG_CALLBACK
*)lParam
;
904 sprintf(buf
, "%08x", (UINT
)LangID
);
905 return enum_uilang
->u
.procA( buf
, enum_uilang
->param
);
915 UILANGUAGE_ENUMPROCA lpUILanguageEnumProc
,
919 ENUM_UILANG_CALLBACK enum_uilang
;
921 DPRINT("%p, %x, %lx\n", lpUILanguageEnumProc
, dwFlags
, lParam
);
923 if(!lpUILanguageEnumProc
) {
924 SetLastError(ERROR_INVALID_PARAMETER
);
928 SetLastError(ERROR_INVALID_FLAGS
);
932 enum_uilang
.u
.procA
= lpUILanguageEnumProc
;
933 enum_uilang
.flags
= dwFlags
;
934 enum_uilang
.param
= lParam
;
936 EnumResourceLanguagesA( hCurrentModule
, (LPCSTR
)RT_STRING
,
937 (LPCSTR
)LOCALE_ILANGUAGE
, enum_uilang_proc_a
,
938 (LONG_PTR
)&enum_uilang
);
942 static BOOL CALLBACK
enum_uilang_proc_w( HMODULE hModule
, LPCWSTR type
,
943 LPCWSTR name
, WORD LangID
, LONG_PTR lParam
)
945 static const WCHAR formatW
[] = {'%','0','8','x',0};
946 ENUM_UILANG_CALLBACK
*enum_uilang
= (ENUM_UILANG_CALLBACK
*)lParam
;
949 swprintf( buf
, formatW
, (UINT
)LangID
);
950 return enum_uilang
->u
.procW( buf
, enum_uilang
->param
);
959 UILANGUAGE_ENUMPROCW lpUILanguageEnumProc
,
963 ENUM_UILANG_CALLBACK enum_uilang
;
965 DPRINT("%p, %x, %lx\n", lpUILanguageEnumProc
, dwFlags
, lParam
);
968 if(!lpUILanguageEnumProc
) {
969 SetLastError(ERROR_INVALID_PARAMETER
);
973 SetLastError(ERROR_INVALID_FLAGS
);
977 enum_uilang
.u
.procW
= lpUILanguageEnumProc
;
978 enum_uilang
.flags
= dwFlags
;
979 enum_uilang
.param
= lParam
;
981 EnumResourceLanguagesW( hCurrentModule
, (LPCWSTR
)RT_STRING
,
982 (LPCWSTR
)LOCALE_ILANGUAGE
, enum_uilang_proc_w
,
983 (LONG_PTR
)&enum_uilang
);
1002 LPWSTR lpCalDataW
= NULL
;
1004 if (NLS_IsUnicodeOnlyLcid(lcid
))
1006 SetLastError(ERROR_INVALID_PARAMETER
);
1011 !(lpCalDataW
= HeapAlloc(GetProcessHeap(), 0, cchData
*sizeof(WCHAR
))))
1014 ret
= GetCalendarInfoW(lcid
, Calendar
, CalType
, lpCalDataW
, cchData
, lpValue
);
1015 if(ret
&& lpCalDataW
&& lpCalData
)
1016 WideCharToMultiByte(CP_ACP
, 0, lpCalDataW
, cchData
, lpCalData
, cchData
, NULL
, NULL
);
1017 HeapFree(GetProcessHeap(), 0, lpCalDataW
);
1036 if (CalType
& CAL_NOUSEROVERRIDE
)
1037 DPRINT("FIXME: flag CAL_NOUSEROVERRIDE used, not fully implemented\n");
1038 if (CalType
& CAL_USE_CP_ACP
)
1039 DPRINT("FIXME: flag CAL_USE_CP_ACP used, not fully implemented\n");
1041 if (CalType
& CAL_RETURN_NUMBER
) {
1042 if (lpCalData
!= NULL
)
1043 DPRINT("WARNING: lpCalData not NULL (%p) when it should!\n", lpCalData
);
1045 DPRINT("WARNING: cchData not 0 (%d) when it should!\n", cchData
);
1047 if (lpValue
!= NULL
)
1048 DPRINT("WARNING: lpValue not NULL (%p) when it should!\n", lpValue
);
1051 /* FIXME: No verification is made yet wrt Locale
1052 * for the CALTYPES not requiring GetLocaleInfoA */
1053 switch (CalType
& ~(CAL_NOUSEROVERRIDE
|CAL_RETURN_NUMBER
|CAL_USE_CP_ACP
)) {
1054 case CAL_ICALINTVALUE
:
1055 DPRINT("FIXME: Unimplemented caltype %d\n", CalType
& 0xffff);
1058 DPRINT("FIXME: Unimplemented caltype %d\n", CalType
& 0xffff);
1060 case CAL_IYEAROFFSETRANGE
:
1061 DPRINT("FIXME: Unimplemented caltype %d\n", CalType
& 0xffff);
1063 case CAL_SERASTRING
:
1064 DPRINT("FIXME: Unimplemented caltype %d\n", CalType
& 0xffff);
1066 case CAL_SSHORTDATE
:
1067 return GetLocaleInfoW(Locale
, LOCALE_SSHORTDATE
, lpCalData
, cchData
);
1069 return GetLocaleInfoW(Locale
, LOCALE_SLONGDATE
, lpCalData
, cchData
);
1071 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME1
, lpCalData
, cchData
);
1073 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME2
, lpCalData
, cchData
);
1075 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME3
, lpCalData
, cchData
);
1077 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME4
, lpCalData
, cchData
);
1079 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME5
, lpCalData
, cchData
);
1081 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME6
, lpCalData
, cchData
);
1083 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME7
, lpCalData
, cchData
);
1084 case CAL_SABBREVDAYNAME1
:
1085 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME1
, lpCalData
, cchData
);
1086 case CAL_SABBREVDAYNAME2
:
1087 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME2
, lpCalData
, cchData
);
1088 case CAL_SABBREVDAYNAME3
:
1089 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME3
, lpCalData
, cchData
);
1090 case CAL_SABBREVDAYNAME4
:
1091 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME4
, lpCalData
, cchData
);
1092 case CAL_SABBREVDAYNAME5
:
1093 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME5
, lpCalData
, cchData
);
1094 case CAL_SABBREVDAYNAME6
:
1095 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME6
, lpCalData
, cchData
);
1096 case CAL_SABBREVDAYNAME7
:
1097 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME7
, lpCalData
, cchData
);
1098 case CAL_SMONTHNAME1
:
1099 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME1
, lpCalData
, cchData
);
1100 case CAL_SMONTHNAME2
:
1101 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME2
, lpCalData
, cchData
);
1102 case CAL_SMONTHNAME3
:
1103 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME3
, lpCalData
, cchData
);
1104 case CAL_SMONTHNAME4
:
1105 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME4
, lpCalData
, cchData
);
1106 case CAL_SMONTHNAME5
:
1107 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME5
, lpCalData
, cchData
);
1108 case CAL_SMONTHNAME6
:
1109 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME6
, lpCalData
, cchData
);
1110 case CAL_SMONTHNAME7
:
1111 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME7
, lpCalData
, cchData
);
1112 case CAL_SMONTHNAME8
:
1113 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME8
, lpCalData
, cchData
);
1114 case CAL_SMONTHNAME9
:
1115 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME9
, lpCalData
, cchData
);
1116 case CAL_SMONTHNAME10
:
1117 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME10
, lpCalData
, cchData
);
1118 case CAL_SMONTHNAME11
:
1119 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME11
, lpCalData
, cchData
);
1120 case CAL_SMONTHNAME12
:
1121 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME12
, lpCalData
, cchData
);
1122 case CAL_SMONTHNAME13
:
1123 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME13
, lpCalData
, cchData
);
1124 case CAL_SABBREVMONTHNAME1
:
1125 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME1
, lpCalData
, cchData
);
1126 case CAL_SABBREVMONTHNAME2
:
1127 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME2
, lpCalData
, cchData
);
1128 case CAL_SABBREVMONTHNAME3
:
1129 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME3
, lpCalData
, cchData
);
1130 case CAL_SABBREVMONTHNAME4
:
1131 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME4
, lpCalData
, cchData
);
1132 case CAL_SABBREVMONTHNAME5
:
1133 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME5
, lpCalData
, cchData
);
1134 case CAL_SABBREVMONTHNAME6
:
1135 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME6
, lpCalData
, cchData
);
1136 case CAL_SABBREVMONTHNAME7
:
1137 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME7
, lpCalData
, cchData
);
1138 case CAL_SABBREVMONTHNAME8
:
1139 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME8
, lpCalData
, cchData
);
1140 case CAL_SABBREVMONTHNAME9
:
1141 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME9
, lpCalData
, cchData
);
1142 case CAL_SABBREVMONTHNAME10
:
1143 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME10
, lpCalData
, cchData
);
1144 case CAL_SABBREVMONTHNAME11
:
1145 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME11
, lpCalData
, cchData
);
1146 case CAL_SABBREVMONTHNAME12
:
1147 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME12
, lpCalData
, cchData
);
1148 case CAL_SABBREVMONTHNAME13
:
1149 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME13
, lpCalData
, cchData
);
1150 case CAL_SYEARMONTH
:
1151 return GetLocaleInfoW(Locale
, LOCALE_SYEARMONTH
, lpCalData
, cchData
);
1152 case CAL_ITWODIGITYEARMAX
:
1153 if (lpValue
) *lpValue
= CALINFO_MAX_YEAR
;
1155 default: DPRINT("Unknown caltype %d\n",CalType
& 0xffff);
1167 GetCPInfo(UINT CodePage
,
1168 LPCPINFO CodePageInfo
)
1170 PCODEPAGE_ENTRY CodePageEntry
;
1174 SetLastError(ERROR_INVALID_PARAMETER
);
1178 CodePageEntry
= IntGetCodePageEntry(CodePage
);
1179 if (CodePageEntry
== NULL
)
1185 CodePageInfo
->DefaultChar
[0] = 0x3f;
1186 CodePageInfo
->DefaultChar
[1] = 0;
1187 CodePageInfo
->LeadByte
[0] = CodePageInfo
->LeadByte
[1] = 0;
1188 CodePageInfo
->MaxCharSize
= (CodePage
== CP_UTF7
) ? 5 : 4;
1192 SetLastError( ERROR_INVALID_PARAMETER
);
1196 if (CodePageEntry
->CodePageTable
.DefaultChar
& 0xff00)
1198 CodePageInfo
->DefaultChar
[0] = (CodePageEntry
->CodePageTable
.DefaultChar
& 0xff00) >> 8;
1199 CodePageInfo
->DefaultChar
[1] = CodePageEntry
->CodePageTable
.DefaultChar
& 0x00ff;
1203 CodePageInfo
->DefaultChar
[0] = CodePageEntry
->CodePageTable
.DefaultChar
& 0xff;
1204 CodePageInfo
->DefaultChar
[1] = 0;
1207 if ((CodePageInfo
->MaxCharSize
= CodePageEntry
->CodePageTable
.MaximumCharacterSize
) == 2)
1208 memcpy(CodePageInfo
->LeadByte
, CodePageEntry
->CodePageTable
.LeadByte
, sizeof(CodePageInfo
->LeadByte
));
1210 CodePageInfo
->LeadByte
[0] = CodePageInfo
->LeadByte
[1] = 0;
1216 GetLocalisedText(DWORD dwResId
, WCHAR
*lpszDest
)
1224 dwId
= dwResId
* 100;
1228 lcid
= GetUserDefaultLCID();
1229 lcid
= ConvertDefaultLocale(lcid
);
1231 langId
= LANGIDFROMLCID(lcid
);
1233 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
1234 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
);
1236 hrsrc
= FindResourceExW(hCurrentModule
,
1238 MAKEINTRESOURCEW((dwId
>> 4) + 1),
1242 HGLOBAL hmem
= LoadResource(hCurrentModule
, hrsrc
);
1249 p
= LockResource(hmem
);
1250 for (i
= 0; i
< (dwId
& 0x0f); i
++) p
+= *p
+ 1;
1252 memcpy(lpszDest
, p
+ 1, *p
* sizeof(WCHAR
));
1253 lpszDest
[*p
] = '\0';
1259 DPRINT1("Could not get codepage name. dwResId = %ld\n", dwResId
);
1268 GetCPInfoExW(UINT CodePage
,
1270 LPCPINFOEXW lpCPInfoEx
)
1272 if (!GetCPInfo(CodePage
, (LPCPINFO
) lpCPInfoEx
))
1279 lpCPInfoEx
->CodePage
= CP_UTF7
;
1280 lpCPInfoEx
->UnicodeDefaultChar
= 0x3f;
1281 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
);
1287 lpCPInfoEx
->CodePage
= CP_UTF8
;
1288 lpCPInfoEx
->UnicodeDefaultChar
= 0x3f;
1289 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
);
1294 PCODEPAGE_ENTRY CodePageEntry
;
1296 CodePageEntry
= IntGetCodePageEntry(CodePage
);
1297 if (CodePageEntry
== NULL
)
1299 DPRINT1("Could not get CodePage Entry! CodePageEntry = 0\n");
1300 SetLastError(ERROR_INVALID_PARAMETER
);
1304 lpCPInfoEx
->CodePage
= CodePageEntry
->CodePageTable
.CodePage
;
1305 lpCPInfoEx
->UnicodeDefaultChar
= CodePageEntry
->CodePageTable
.UniDefaultChar
;
1306 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
);
1318 GetCPInfoExA(UINT CodePage
,
1320 LPCPINFOEXA lpCPInfoEx
)
1324 if (!GetCPInfoExW(CodePage
, dwFlags
, &CPInfo
))
1327 /* the layout is the same except for CodePageName */
1328 memcpy(lpCPInfoEx
, &CPInfo
, sizeof(CPINFOEXA
));
1330 WideCharToMultiByte(CP_ACP
,
1332 CPInfo
.CodePageName
,
1334 lpCPInfoEx
->CodePageName
,
1335 sizeof(lpCPInfoEx
->CodePageName
),
1342 NLS_GetGeoFriendlyName(GEOID Location
, LPWSTR szFriendlyName
, int cchData
)
1345 WCHAR szPath
[MAX_PATH
];
1346 UNICODE_STRING ValueName
;
1347 KEY_VALUE_PARTIAL_INFORMATION
*info
;
1348 static const int info_size
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1353 swprintf(szPath
, L
"\\REGISTRY\\Machine\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Country List\\%d", Location
);
1355 hKey
= NLS_RegOpenKey(0, szPath
);
1358 DPRINT1("NLS_RegOpenKey() failed\n");
1362 dwSize
= info_size
+ cchData
* sizeof(WCHAR
);
1364 if (!(info
= HeapAlloc(GetProcessHeap(), 0, dwSize
)))
1367 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1371 RtlInitUnicodeString(&ValueName
, L
"Name");
1373 Status
= NtQueryValueKey(hKey
, &ValueName
, KeyValuePartialInformation
,
1374 (LPBYTE
)info
, dwSize
, &dwSize
);
1378 Ret
= (dwSize
- info_size
) / sizeof(WCHAR
);
1380 if (!Ret
|| ((WCHAR
*)info
->Data
)[Ret
-1])
1382 if (Ret
< cchData
|| !szFriendlyName
) Ret
++;
1385 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1390 if (Ret
&& szFriendlyName
)
1392 memcpy(szFriendlyName
, info
->Data
, (Ret
-1) * sizeof(WCHAR
));
1393 szFriendlyName
[Ret
-1] = 0;
1396 else if (Status
== STATUS_BUFFER_OVERFLOW
&& !szFriendlyName
)
1398 Ret
= (dwSize
- info_size
) / sizeof(WCHAR
) + 1;
1400 else if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1406 SetLastError(RtlNtStatusToDosError(Status
));
1411 HeapFree(GetProcessHeap(), 0, info
);
1428 DPRINT("%d %d %p %d %d\n", Location
, GeoType
, lpGeoData
, cchData
, LangId
);
1430 if ((GeoType
== GEO_TIMEZONES
)||(GeoType
== GEO_OFFICIALLANGUAGES
))
1432 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1437 case GEO_FRIENDLYNAME
:
1439 return NLS_GetGeoFriendlyName(Location
, lpGeoData
, cchData
);
1448 case GEO_OFFICIALNAME
:
1449 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1469 DPRINT("%d %d %p %d %d\n", Location
, GeoType
, lpGeoData
, cchData
, LangId
);
1471 if ((GeoType
== GEO_TIMEZONES
)||(GeoType
== GEO_OFFICIALLANGUAGES
))
1473 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1478 case GEO_FRIENDLYNAME
:
1480 WCHAR szBuffer
[MAX_PATH
];
1481 char szBufferA
[sizeof(szBuffer
)/sizeof(WCHAR
)];
1484 Ret
= NLS_GetGeoFriendlyName(Location
, szBuffer
, cchData
);
1486 WideCharToMultiByte(CP_ACP
, 0, szBuffer
, -1, szBufferA
, sizeof(szBufferA
), 0, 0);
1487 strcpy(lpGeoData
, szBufferA
);
1498 case GEO_OFFICIALNAME
:
1499 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1506 const WCHAR
*RosGetLocaleValueName( DWORD lctype
)
1508 switch (lctype
& ~LOCALE_LOCALEINFOFLAGSMASK
)
1510 /* These values are used by SetLocaleInfo and GetLocaleInfo, and
1511 * the values are stored in the registry, confirmed under Windows.
1513 case LOCALE_ICALENDARTYPE
: return L
"iCalendarType";
1514 case LOCALE_ICURRDIGITS
: return L
"iCurrDigits";
1515 case LOCALE_ICURRENCY
: return L
"iCurrency";
1516 case LOCALE_IDIGITS
: return L
"iDigits";
1517 case LOCALE_IFIRSTDAYOFWEEK
: return L
"iFirstDayOfWeek";
1518 case LOCALE_IFIRSTWEEKOFYEAR
: return L
"iFirstWeekOfYear";
1519 case LOCALE_ILZERO
: return L
"iLZero";
1520 case LOCALE_IMEASURE
: return L
"iMeasure";
1521 case LOCALE_INEGCURR
: return L
"iNegCurr";
1522 case LOCALE_INEGNUMBER
: return L
"iNegNumber";
1523 case LOCALE_IPAPERSIZE
: return L
"iPaperSize";
1524 case LOCALE_ITIME
: return L
"iTime";
1525 case LOCALE_S1159
: return L
"s1159";
1526 case LOCALE_S2359
: return L
"s2359";
1527 case LOCALE_SCURRENCY
: return L
"sCurrency";
1528 case LOCALE_SDATE
: return L
"sDate";
1529 case LOCALE_SDECIMAL
: return L
"sDecimal";
1530 case LOCALE_SGROUPING
: return L
"sGrouping";
1531 case LOCALE_SLIST
: return L
"sList";
1532 case LOCALE_SLONGDATE
: return L
"sLongDate";
1533 case LOCALE_SMONDECIMALSEP
: return L
"sMonDecimalSep";
1534 case LOCALE_SMONGROUPING
: return L
"sMonGrouping";
1535 case LOCALE_SMONTHOUSANDSEP
: return L
"sMonThousandSep";
1536 case LOCALE_SNEGATIVESIGN
: return L
"sNegativeSign";
1537 case LOCALE_SPOSITIVESIGN
: return L
"sPositiveSign";
1538 case LOCALE_SSHORTDATE
: return L
"sShortDate";
1539 case LOCALE_STHOUSAND
: return L
"sThousand";
1540 case LOCALE_STIME
: return L
"sTime";
1541 case LOCALE_STIMEFORMAT
: return L
"sTimeFormat";
1542 case LOCALE_SYEARMONTH
: return L
"sYearMonth";
1544 /* The following are not listed under MSDN as supported,
1545 * but seem to be used and also stored in the registry.
1547 case LOCALE_ICOUNTRY
: return L
"iCountry";
1548 case LOCALE_IDATE
: return L
"iDate";
1549 case LOCALE_ILDATE
: return L
"iLDate";
1550 case LOCALE_ITLZERO
: return L
"iTLZero";
1551 case LOCALE_SCOUNTRY
: return L
"sCountry";
1552 case LOCALE_SLANGUAGE
: return L
"sLanguage";
1554 /* The following are used in XP and later */
1555 case LOCALE_IDIGITSUBSTITUTION
: return L
"NumShape";
1556 case LOCALE_SNATIVEDIGITS
: return L
"sNativeDigits";
1557 case LOCALE_ITIMEMARKPOSN
: return L
"iTimePrefix";
1562 HKEY
RosCreateRegistryKey(void)
1564 OBJECT_ATTRIBUTES objAttr
;
1565 UNICODE_STRING nameW
;
1568 if (RtlOpenCurrentUser( KEY_ALL_ACCESS
, &hKey
) != STATUS_SUCCESS
) return 0;
1570 objAttr
.Length
= sizeof(objAttr
);
1571 objAttr
.RootDirectory
= hKey
;
1572 objAttr
.ObjectName
= &nameW
;
1573 objAttr
.Attributes
= 0;
1574 objAttr
.SecurityDescriptor
= NULL
;
1575 objAttr
.SecurityQualityOfService
= NULL
;
1576 RtlInitUnicodeString( &nameW
, L
"Control Panel\\International");
1578 if (NtCreateKey( &hKey
, KEY_ALL_ACCESS
, &objAttr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
) hKey
= 0;
1579 NtClose( objAttr
.RootDirectory
);
1583 INT
RosGetRegistryLocaleInfo( LPCWSTR lpValue
, LPWSTR lpBuffer
, INT nLen
)
1589 UNICODE_STRING usNameW
;
1590 KEY_VALUE_PARTIAL_INFORMATION
*kvpiInfo
;
1591 const int nInfoSize
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1593 if (!(hKey
= RosCreateRegistryKey())) return -1;
1595 RtlInitUnicodeString( &usNameW
, lpValue
);
1596 dwSize
= nInfoSize
+ nLen
* sizeof(WCHAR
);
1598 if (!(kvpiInfo
= HeapAlloc( GetProcessHeap(), 0, dwSize
)))
1601 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1605 ntStatus
= NtQueryValueKey( hKey
, &usNameW
, KeyValuePartialInformation
, kvpiInfo
, dwSize
, &dwSize
);
1609 nRet
= (dwSize
- nInfoSize
) / sizeof(WCHAR
);
1611 if (!nRet
|| ((WCHAR
*)kvpiInfo
->Data
)[nRet
- 1])
1613 if (nRet
< nLen
|| !lpBuffer
) nRet
++;
1616 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1620 if (nRet
&& lpBuffer
)
1622 memcpy( lpBuffer
, kvpiInfo
->Data
, (nRet
- 1) * sizeof(WCHAR
) );
1623 lpBuffer
[nRet
- 1] = 0;
1626 else if (ntStatus
== STATUS_BUFFER_OVERFLOW
&& !lpBuffer
)
1628 nRet
= (dwSize
- nInfoSize
) / sizeof(WCHAR
) + 1;
1630 else if (ntStatus
== STATUS_OBJECT_NAME_NOT_FOUND
)
1636 SetLastError( RtlNtStatusToDosError(ntStatus
) );
1640 HeapFree( GetProcessHeap(), 0, kvpiInfo
);
1647 LPCWSTR lpLocaleName
,
1677 if (cchData
< 0 || (cchData
&& !lpLCData
))
1679 SetLastError( ERROR_INVALID_PARAMETER
);
1682 if (LCType
& LOCALE_RETURN_GENITIVE_NAMES
&&
1683 !is_genitive_name_supported( LCType
))
1685 SetLastError( ERROR_INVALID_FLAGS
);
1689 if (!cchData
) lpLCData
= NULL
;
1691 if (Locale
== LOCALE_NEUTRAL
|| Locale
== LOCALE_SYSTEM_DEFAULT
) Locale
= GetSystemDefaultLCID();
1692 else if (Locale
== LOCALE_USER_DEFAULT
) Locale
= GetUserDefaultLCID();
1694 uiFlags
= LCType
& LOCALE_LOCALEINFOFLAGSMASK
;
1695 LCType
&= ~LOCALE_LOCALEINFOFLAGSMASK
;
1697 if (!(uiFlags
& LOCALE_NOUSEROVERRIDE
) && Locale
== GetUserDefaultLCID())
1699 const WCHAR
*value
= RosGetLocaleValueName(LCType
);
1701 if (value
&& ((nRet
= RosGetRegistryLocaleInfo( value
, lpLCData
, cchData
)) != -1)) return nRet
;
1704 liLangID
= LANGIDFROMLCID( Locale
);
1706 if (SUBLANGID(liLangID
) == SUBLANG_NEUTRAL
)
1707 liLangID
= MAKELANGID(PRIMARYLANGID(liLangID
), SUBLANG_DEFAULT
);
1709 hModule
= GetModuleHandleW( L
"kernel32.dll" );
1710 if (!(hRsrc
= FindResourceExW( hModule
, (LPWSTR
)RT_STRING
, (LPCWSTR
)((LCType
>> 4) + 1), liLangID
)))
1712 SetLastError( ERROR_INVALID_FLAGS
);
1715 if (!(hMem
= LoadResource( hModule
, hRsrc
)))
1718 ch
= LockResource( hMem
);
1719 for (i
= 0; i
< (LCType
& 0x0f); i
++) ch
+= *ch
+ 1;
1721 if (uiFlags
& LOCALE_RETURN_NUMBER
) nRet
= sizeof(UINT
) / sizeof(WCHAR
);
1722 else if (is_genitive_name_supported( LCType
) && *ch
)
1724 /* genitive form's stored after a null separator from a nominative */
1725 for (i
= 1; i
<= *ch
; i
++) if (!ch
[i
]) break;
1727 if (i
<= *ch
&& (uiFlags
& LOCALE_RETURN_GENITIVE_NAMES
))
1735 nRet
= (LCType
== LOCALE_FONTSIGNATURE
) ? *ch
: *ch
+ 1;
1737 if (!lpLCData
) return nRet
;
1741 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1745 if (uiFlags
& LOCALE_RETURN_NUMBER
)
1748 WCHAR
*chEnd
, *chTmp
= HeapAlloc( GetProcessHeap(), 0, (*ch
+ 1) * sizeof(WCHAR
) );
1753 memcpy( chTmp
, ch
+ 1, *ch
* sizeof(WCHAR
) );
1755 uiNum
= wcstol( chTmp
, &chEnd
, 10 );
1758 memcpy( lpLCData
, &uiNum
, sizeof(uiNum
) );
1761 SetLastError( ERROR_INVALID_FLAGS
);
1764 HeapFree( GetProcessHeap(), 0, chTmp
);
1768 memcpy( lpLCData
, ch
+ 1, *ch
* sizeof(WCHAR
) );
1769 if (LCType
!= LOCALE_FONTSIGNATURE
) lpLCData
[nRet
-1] = 0;
1776 /***********************************************************************
1779 * Retrieve the ANSI codepage for a given locale.
1781 __inline
static UINT
get_lcid_codepage( LCID lcid
)
1784 if (!GetLocaleInfoW( lcid
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
, (WCHAR
*)&ret
,
1785 sizeof(ret
)/sizeof(WCHAR
) )) ret
= 0;
1790 /*************************************************************************
1791 * FoldStringA (KERNEL32.@)
1793 * Map characters in a string.
1796 * dwFlags [I] Flags controlling chars to map (MAP_ constants from "winnls.h")
1797 * src [I] String to map
1798 * srclen [I] Length of src, or -1 if src is NUL terminated
1799 * dst [O] Destination for mapped string
1800 * dstlen [I] Length of dst, or 0 to find the required length for the mapped string
1803 * Success: The length of the string written to dst, including the terminating NUL. If
1804 * dstlen is 0, the value returned is the same, but nothing is written to dst,
1805 * and dst may be NULL.
1806 * Failure: 0. Use GetLastError() to determine the cause.
1808 INT WINAPI
FoldStringA(DWORD dwFlags
, LPCSTR src
, INT srclen
,
1809 LPSTR dst
, INT dstlen
)
1811 INT ret
= 0, srclenW
= 0;
1812 WCHAR
*srcW
= NULL
, *dstW
= NULL
;
1814 if (!src
|| !srclen
|| dstlen
< 0 || (dstlen
&& !dst
) || src
== dst
)
1816 SetLastError(ERROR_INVALID_PARAMETER
);
1820 srclenW
= MultiByteToWideChar(CP_ACP
, dwFlags
& MAP_COMPOSITE
? MB_COMPOSITE
: 0,
1821 src
, srclen
, NULL
, 0);
1822 srcW
= HeapAlloc(GetProcessHeap(), 0, srclenW
* sizeof(WCHAR
));
1826 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1827 goto FoldStringA_exit
;
1830 MultiByteToWideChar(CP_ACP
, dwFlags
& MAP_COMPOSITE
? MB_COMPOSITE
: 0,
1831 src
, srclen
, srcW
, srclenW
);
1833 dwFlags
= (dwFlags
& ~MAP_PRECOMPOSED
) | MAP_FOLDCZONE
;
1835 ret
= FoldStringW(dwFlags
, srcW
, srclenW
, NULL
, 0);
1838 dstW
= HeapAlloc(GetProcessHeap(), 0, ret
* sizeof(WCHAR
));
1842 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1843 goto FoldStringA_exit
;
1846 ret
= FoldStringW(dwFlags
, srcW
, srclenW
, dstW
, ret
);
1847 if (!WideCharToMultiByte(CP_ACP
, 0, dstW
, ret
, dst
, dstlen
, NULL
, NULL
))
1850 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1854 HeapFree(GetProcessHeap(), 0, dstW
);
1857 HeapFree(GetProcessHeap(), 0, srcW
);
1861 /*************************************************************************
1862 * FoldStringW (KERNEL32.@)
1866 INT WINAPI
FoldStringW(DWORD dwFlags
, LPCWSTR src
, INT srclen
,
1867 LPWSTR dst
, INT dstlen
)
1871 switch (dwFlags
& (MAP_COMPOSITE
|MAP_PRECOMPOSED
|MAP_EXPAND_LIGATURES
))
1876 /* Fall through for dwFlags == 0 */
1877 case MAP_PRECOMPOSED
|MAP_COMPOSITE
:
1878 case MAP_PRECOMPOSED
|MAP_EXPAND_LIGATURES
:
1879 case MAP_COMPOSITE
|MAP_EXPAND_LIGATURES
:
1880 SetLastError(ERROR_INVALID_FLAGS
);
1884 if (!src
|| !srclen
|| dstlen
< 0 || (dstlen
&& !dst
) || src
== dst
)
1886 SetLastError(ERROR_INVALID_PARAMETER
);
1890 ret
= wine_fold_string(dwFlags
, src
, srclen
, dst
, dstlen
);
1892 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1898 * @implemented (Synced to Wine-22112008)
1911 WCHAR
*buf1W
= NtCurrentTeb()->StaticUnicodeBuffer
;
1912 WCHAR
*buf2W
= buf1W
+ 130;
1913 LPWSTR str1W
, str2W
;
1914 INT len1W
, len2W
, ret
;
1915 UINT locale_cp
= CP_ACP
;
1917 if (!lpString1
|| !lpString2
)
1919 SetLastError(ERROR_INVALID_PARAMETER
);
1922 if (cchCount1
< 0) cchCount1
= strlen(lpString1
);
1923 if (cchCount2
< 0) cchCount2
= strlen(lpString2
);
1925 if (!(dwCmpFlags
& LOCALE_USE_CP_ACP
)) locale_cp
= get_lcid_codepage(Locale
);
1927 len1W
= MultiByteToWideChar(locale_cp
, 0, lpString1
, cchCount1
, buf1W
, 130);
1932 len1W
= MultiByteToWideChar(locale_cp
, 0, lpString1
, cchCount1
, NULL
, 0);
1933 str1W
= HeapAlloc(GetProcessHeap(), 0, len1W
* sizeof(WCHAR
));
1936 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1939 MultiByteToWideChar(locale_cp
, 0, lpString1
, cchCount1
, str1W
, len1W
);
1941 len2W
= MultiByteToWideChar(locale_cp
, 0, lpString2
, cchCount2
, buf2W
, 130);
1946 len2W
= MultiByteToWideChar(locale_cp
, 0, lpString2
, cchCount2
, NULL
, 0);
1947 str2W
= HeapAlloc(GetProcessHeap(), 0, len2W
* sizeof(WCHAR
));
1950 if (str1W
!= buf1W
) HeapFree(GetProcessHeap(), 0, str1W
);
1951 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1954 MultiByteToWideChar(locale_cp
, 0, lpString2
, cchCount2
, str2W
, len2W
);
1957 ret
= CompareStringW(Locale
, dwCmpFlags
, str1W
, len1W
, str2W
, len2W
);
1959 if (str1W
!= buf1W
) HeapFree(GetProcessHeap(), 0, str1W
);
1960 if (str2W
!= buf2W
) HeapFree(GetProcessHeap(), 0, str2W
);
1965 * @implemented (Synced to Wine-22/11/2008)
1980 if (!lpString1
|| !lpString2
)
1982 SetLastError(ERROR_INVALID_PARAMETER
);
1986 if (dwCmpFlags
& ~(NORM_IGNORECASE
| NORM_IGNORENONSPACE
|
1987 NORM_IGNORESYMBOLS
| SORT_STRINGSORT
| NORM_IGNOREKANATYPE
|
1988 NORM_IGNOREWIDTH
| LOCALE_USE_CP_ACP
| 0x10000000))
1990 SetLastError(ERROR_INVALID_FLAGS
);
1994 /* this style is related to diacritics in Arabic, Japanese, and Hebrew */
1995 if (dwCmpFlags
& 0x10000000)
1996 DPRINT1("Ignoring unknown style 0x10000000\n");
1998 if (cchCount1
< 0) cchCount1
= wcslen(lpString1
);
1999 if (cchCount2
< 0) cchCount2
= wcslen(lpString2
);
2001 Result
= wine_compare_string(dwCmpFlags
, lpString1
, cchCount1
, lpString2
, cchCount2
);
2003 if (Result
) /* need to translate result */
2004 return (Result
< 0) ? CSTR_LESS_THAN
: CSTR_GREATER_THAN
;
2015 * Get information about an aspect of a locale.
2018 * lcid [I] LCID of the locale
2019 * lctype [I] LCTYPE_ flags from "winnls.h"
2020 * buffer [O] Destination for the information
2021 * len [I] Length of buffer in characters
2024 * Success: The size of the data requested. If buffer is non-NULL, it is filled
2025 * with the information.
2026 * Failure: 0. Use GetLastError() to determine the cause.
2029 * - LOCALE_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT
2030 * - The string returned is NUL terminated, except for LOCALE_FONTSIGNATURE,
2031 * which is a bit string.
2033 INT WINAPI
GetLocaleInfoA( LCID lcid
, LCTYPE lctype
, LPSTR buffer
, INT len
)
2038 if (len
< 0 || (len
&& !buffer
))
2040 SetLastError( ERROR_INVALID_PARAMETER
);
2043 if (lctype
& LOCALE_RETURN_GENITIVE_NAMES
)
2045 SetLastError( ERROR_INVALID_FLAGS
);
2049 if (!len
) buffer
= NULL
;
2051 if (!(lenW
= GetLocaleInfoW( lcid
, lctype
, NULL
, 0 ))) return 0;
2053 if (!(bufferW
= HeapAlloc( GetProcessHeap(), 0, lenW
* sizeof(WCHAR
) )))
2055 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
2058 if ((ret
= GetLocaleInfoW( lcid
, lctype
, bufferW
, lenW
)))
2060 if ((lctype
& LOCALE_RETURN_NUMBER
) ||
2061 ((lctype
& ~LOCALE_LOCALEINFOFLAGSMASK
) == LOCALE_FONTSIGNATURE
))
2063 /* it's not an ASCII string, just bytes */
2064 ret
*= sizeof(WCHAR
);
2067 if (ret
<= len
) memcpy( buffer
, bufferW
, ret
);
2070 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
2077 UINT codepage
= CP_ACP
;
2078 if (!(lctype
& LOCALE_USE_CP_ACP
)) codepage
= get_lcid_codepage( lcid
);
2079 ret
= WideCharToMultiByte( codepage
, 0, bufferW
, ret
, buffer
, len
, NULL
, NULL
);
2082 HeapFree( GetProcessHeap(), 0, bufferW
);
2091 GetSystemDefaultLangID(VOID
)
2093 return LANGIDFROMLCID(GetSystemDefaultLCID());
2101 GetSystemDefaultLCID(VOID
)
2105 NtQueryDefaultLocale(FALSE
, &lcid
);
2115 GetSystemDefaultUILanguage(VOID
)
2120 Status
= NtQueryInstallUILanguage(&LanguageId
);
2121 if (!NT_SUCCESS(Status
))
2123 SetLastErrorByStatus(Status
);
2135 GetThreadLocale(VOID
)
2137 return NtCurrentTeb()->CurrentLocale
;
2145 GetUserDefaultLangID(VOID
)
2147 return LANGIDFROMLCID(GetUserDefaultLCID());
2155 GetUserDefaultLCID(VOID
)
2160 Status
= NtQueryDefaultLocale(TRUE
, &lcid
);
2161 if (!NT_SUCCESS(Status
))
2163 SetLastErrorByStatus(Status
);
2175 GetUserDefaultUILanguage(VOID
)
2180 Status
= NtQueryDefaultUILanguage(&LangId
);
2181 if (!NT_SUCCESS(Status
))
2183 SetLastErrorByStatus(Status
);
2199 GEOID ret
= GEOID_NOT_AVAILABLE
;
2200 static const WCHAR geoW
[] = {'G','e','o',0};
2201 static const WCHAR nationW
[] = {'N','a','t','i','o','n',0};
2202 WCHAR bufferW
[40], *end
;
2204 HANDLE hkey
, hSubkey
= 0;
2205 UNICODE_STRING keyW
;
2206 const KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)bufferW
;
2207 RtlInitUnicodeString( &keyW
, nationW
);
2208 count
= sizeof(bufferW
);
2210 if(!(hkey
= create_registry_key())) return ret
;
2213 case GEOCLASS_NATION
:
2214 if ((hSubkey
= NLS_RegOpenKey(hkey
, geoW
)))
2216 if((NtQueryValueKey(hSubkey
, &keyW
, KeyValuePartialInformation
,
2217 (LPBYTE
)bufferW
, count
, &count
) == STATUS_SUCCESS
) && info
->DataLength
)
2218 ret
= wcstol((LPCWSTR
)info
->Data
, &end
, 10);
2221 case GEOCLASS_REGION
:
2222 DPRINT("GEOCLASS_REGION not handled yet\n");
2227 if (hSubkey
) NtClose(hSubkey
);
2232 /******************************************************************************
2233 * IsValidLanguageGroup
2235 * Determine if a language group is supported and/or installed.
2238 * LanguageGroup [I] Language Group Id (LGRPID_ values from "winnls.h")
2239 * dwFlags [I] LGRPID_SUPPORTED=Supported, LGRPID_INSTALLED=Installed
2242 * TRUE, if lgrpid is supported and/or installed, according to dwFlags.
2249 IsValidLanguageGroup(
2250 LGRPID LanguageGroup
,
2253 static const WCHAR szFormat
[] = { '%','x','\0' };
2254 WCHAR szValueName
[16], szValue
[2];
2255 BOOL bSupported
= FALSE
, bInstalled
= FALSE
;
2261 case LGRPID_INSTALLED
:
2262 case LGRPID_SUPPORTED
:
2264 hKey
= NLS_RegOpenKey( 0, szLangGroupsKeyName
);
2268 swprintf( szValueName
, szFormat
, LanguageGroup
);
2270 if (NLS_RegGetDword( hKey
, szValueName
, (LPDWORD
)szValue
))
2274 if (szValue
[0] == '1')
2283 DPRINT("Invalid flags: %lx\n", dwFlags
);
2287 if ((dwFlags
== LGRPID_SUPPORTED
&& bSupported
) ||
2288 (dwFlags
== LGRPID_INSTALLED
&& bInstalled
))
2295 /******************************************************************************
2298 * Determine if a locale is valid.
2301 * Locale [I] LCID of the locale to check
2302 * dwFlags [I] LCID_SUPPORTED = Valid
2303 * LCID_INSTALLED = Valid and installed on the system
2306 * TRUE, if Locale is valid,
2312 IsValidLocale(LCID Locale
,
2315 OBJECT_ATTRIBUTES ObjectAttributes
;
2316 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo
;
2317 WCHAR ValueNameBuffer
[9];
2318 UNICODE_STRING KeyName
;
2319 UNICODE_STRING ValueName
;
2325 BOOL Installed
= FALSE
;
2327 DPRINT("IsValidLocale() called\n");
2329 if ((dwFlags
& ~(LCID_SUPPORTED
| LCID_INSTALLED
)) ||
2330 (dwFlags
== (LCID_SUPPORTED
| LCID_INSTALLED
)))
2332 DPRINT("Invalid flags: %lx\n", dwFlags
);
2336 if (Locale
& 0xFFFF0000)
2338 RtlInitUnicodeString(&KeyName
,
2339 L
"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Nls\\Locale\\Alternate Sorts");
2343 RtlInitUnicodeString(&KeyName
,
2344 L
"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Nls\\Locale");
2347 InitializeObjectAttributes(&ObjectAttributes
,
2349 OBJ_CASE_INSENSITIVE
,
2353 Status
= NtOpenKey(&KeyHandle
,
2356 if (!NT_SUCCESS(Status
))
2358 DPRINT("NtOpenKey() failed (Status %lx)\n", Status
);
2359 SetLastError(ERROR_BADDB
);
2363 swprintf(ValueNameBuffer
, L
"%08lx", (ULONG
)Locale
);
2364 RtlInitUnicodeString(&ValueName
, ValueNameBuffer
);
2366 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4 * sizeof(WCHAR
);
2367 KeyInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
2370 if (KeyInfo
== NULL
)
2372 DPRINT("RtlAllocateHeap() failed (Status %lx)\n", Status
);
2377 Status
= NtQueryValueKey(KeyHandle
,
2379 KeyValuePartialInformation
,
2385 if (!NT_SUCCESS(Status
))
2387 DPRINT("NtQueryValueKey() failed (Status %lx)\n", Status
);
2388 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo
);
2392 if (dwFlags
& LCID_SUPPORTED
)
2394 DPRINT("Locale is supported\n");
2395 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo
);
2399 ValueData
= (PWSTR
)&KeyInfo
->Data
[0];
2400 if ((KeyInfo
->Type
== REG_SZ
) &&
2401 (KeyInfo
->DataLength
== 2 * sizeof(WCHAR
)))
2403 /* Find out if there is support for the language group
2404 * installed, to which this language belongs */
2405 KeyHandle
= NLS_RegOpenKey(0, szLangGroupsKeyName
);
2409 if (NLS_RegGetDword(KeyHandle
, ValueData
, (LPDWORD
) Value
) &&
2413 DPRINT("Locale is supported and installed\n");
2420 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo
);
2422 DPRINT("IsValidLocale() called\n");
2441 WCHAR
*bufW
= NtCurrentTeb()->StaticUnicodeBuffer
;
2443 INT ret
= 0, srclenW
, dstlenW
;
2444 UINT locale_cp
= CP_ACP
;
2446 if (!lpSrcStr
|| !cchSrc
|| cchDest
< 0)
2448 SetLastError(ERROR_INVALID_PARAMETER
);
2452 if (!(dwMapFlags
& LOCALE_USE_CP_ACP
)) locale_cp
= get_lcid_codepage(Locale
);
2454 srclenW
= MultiByteToWideChar(locale_cp
, 0, lpSrcStr
, cchSrc
, bufW
, 260);
2459 srclenW
= MultiByteToWideChar(locale_cp
, 0, lpSrcStr
, cchSrc
, NULL
, 0);
2460 srcW
= HeapAlloc(GetProcessHeap(), 0, srclenW
* sizeof(WCHAR
));
2463 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2466 MultiByteToWideChar(locale_cp
, 0, lpSrcStr
, cchSrc
, srcW
, srclenW
);
2469 if (dwMapFlags
& LCMAP_SORTKEY
)
2471 if (lpSrcStr
== lpDestStr
)
2473 SetLastError(ERROR_INVALID_FLAGS
);
2474 goto map_string_exit
;
2476 ret
= wine_get_sortkey(dwMapFlags
, srcW
, srclenW
, lpDestStr
, cchDest
);
2478 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2481 goto map_string_exit
;
2484 if (dwMapFlags
& SORT_STRINGSORT
)
2486 SetLastError(ERROR_INVALID_FLAGS
);
2487 goto map_string_exit
;
2490 dstlenW
= LCMapStringW(Locale
, dwMapFlags
, srcW
, srclenW
, NULL
, 0);
2492 goto map_string_exit
;
2494 dstW
= HeapAlloc(GetProcessHeap(), 0, dstlenW
* sizeof(WCHAR
));
2497 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2498 goto map_string_exit
;
2501 LCMapStringW(Locale
, dwMapFlags
, srcW
, srclenW
, dstW
, dstlenW
);
2502 ret
= WideCharToMultiByte(locale_cp
, 0, dstW
, dstlenW
, lpDestStr
, cchDest
, NULL
, NULL
);
2503 HeapFree(GetProcessHeap(), 0, dstW
);
2506 if (srcW
!= bufW
) HeapFree(GetProcessHeap(), 0, srcW
);
2527 if (!lpSrcStr
|| !cchSrc
|| cchDest
< 0)
2529 SetLastError(ERROR_INVALID_PARAMETER
);
2533 /* mutually exclusive flags */
2534 if ((dwMapFlags
& (LCMAP_LOWERCASE
| LCMAP_UPPERCASE
)) == (LCMAP_LOWERCASE
| LCMAP_UPPERCASE
) ||
2535 (dwMapFlags
& (LCMAP_HIRAGANA
| LCMAP_KATAKANA
)) == (LCMAP_HIRAGANA
| LCMAP_KATAKANA
) ||
2536 (dwMapFlags
& (LCMAP_HALFWIDTH
| LCMAP_FULLWIDTH
)) == (LCMAP_HALFWIDTH
| LCMAP_FULLWIDTH
) ||
2537 (dwMapFlags
& (LCMAP_TRADITIONAL_CHINESE
| LCMAP_SIMPLIFIED_CHINESE
)) == (LCMAP_TRADITIONAL_CHINESE
| LCMAP_SIMPLIFIED_CHINESE
))
2539 SetLastError(ERROR_INVALID_FLAGS
);
2543 if (!cchDest
) lpDestStr
= NULL
;
2545 Locale
= ConvertDefaultLocale(Locale
);
2547 if (dwMapFlags
& LCMAP_SORTKEY
)
2550 if (lpSrcStr
== lpDestStr
)
2552 SetLastError(ERROR_INVALID_FLAGS
);
2556 if (cchSrc
< 0) cchSrc
= wcslen(lpSrcStr
);
2558 ret
= wine_get_sortkey(dwMapFlags
, lpSrcStr
, cchSrc
, (char *)lpDestStr
, cchDest
);
2560 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2564 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
2565 if (dwMapFlags
& SORT_STRINGSORT
)
2567 SetLastError(ERROR_INVALID_FLAGS
);
2571 if (cchSrc
< 0) cchSrc
= wcslen(lpSrcStr
) + 1;
2573 if (!lpDestStr
) /* return required string length */
2577 for (len
= 0; cchSrc
; lpSrcStr
++, cchSrc
--)
2579 WCHAR wch
= *lpSrcStr
;
2580 /* tests show that win2k just ignores NORM_IGNORENONSPACE,
2581 * and skips white space and punctuation characters for
2582 * NORM_IGNORESYMBOLS.
2584 if ((dwMapFlags
& NORM_IGNORESYMBOLS
) && (iswctype(wch
, _SPACE
| _PUNCT
)))
2591 if (dwMapFlags
& LCMAP_UPPERCASE
)
2593 for (dst_ptr
= lpDestStr
; cchSrc
&& cchDest
; lpSrcStr
++, cchSrc
--)
2595 WCHAR wch
= *lpSrcStr
;
2596 if ((dwMapFlags
& NORM_IGNORESYMBOLS
) && (iswctype(wch
, _SPACE
| _PUNCT
)))
2598 *dst_ptr
++ = towupper(wch
);
2602 else if (dwMapFlags
& LCMAP_LOWERCASE
)
2604 for (dst_ptr
= lpDestStr
; cchSrc
&& cchDest
; lpSrcStr
++, cchSrc
--)
2606 WCHAR wch
= *lpSrcStr
;
2607 if ((dwMapFlags
& NORM_IGNORESYMBOLS
) && (iswctype(wch
, _SPACE
| _PUNCT
)))
2609 *dst_ptr
++ = towlower(wch
);
2615 if (lpSrcStr
== lpDestStr
)
2617 SetLastError(ERROR_INVALID_FLAGS
);
2620 for (dst_ptr
= lpDestStr
; cchSrc
&& cchDest
; lpSrcStr
++, cchSrc
--)
2622 WCHAR wch
= *lpSrcStr
;
2623 if ((dwMapFlags
& NORM_IGNORESYMBOLS
) && (iswctype(wch
, _SPACE
| _PUNCT
)))
2632 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2636 return dst_ptr
- lpDestStr
;
2651 if (!Locale
|| !lpCalData
)
2653 SetLastError(ERROR_INVALID_PARAMETER
);
2659 case CAL_NOUSEROVERRIDE
:
2660 case CAL_RETURN_NUMBER
:
2661 case CAL_USE_CP_ACP
:
2664 SetLastError(ERROR_INVALID_FLAGS
);
2668 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2683 if (!Locale
|| !lpCalData
)
2685 SetLastError(ERROR_INVALID_PARAMETER
);
2691 case CAL_NOUSEROVERRIDE
:
2692 case CAL_RETURN_NUMBER
:
2693 case CAL_USE_CP_ACP
:
2696 SetLastError(ERROR_INVALID_FLAGS
);
2700 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2705 /**********************************************************************
2707 * RIPPED FROM WINE's dlls\kernel\locale.c ver 0.9.29
2709 * SetLocaleInfoA (KERNEL32.@)
2711 * Set the current locale info.
2714 * Locale [I] LCID of the locale
2715 * LCType [I] LCTYPE_ flags from "winnls.h"
2716 * lpLCData [I] Information to set
2719 * Success: TRUE. The information given will be returned by GetLocaleInfoA()
2720 * whenever it is called without LOCALE_NOUSEROVERRIDE.
2721 * Failure: FALSE. Use GetLastError() to determine the cause.
2731 UINT codepage
= CP_ACP
;
2736 if (!(LCType
& LOCALE_USE_CP_ACP
)) codepage
= get_lcid_codepage( Locale
);
2740 SetLastError( ERROR_INVALID_PARAMETER
);
2743 len
= MultiByteToWideChar( codepage
, 0, lpLCData
, -1, NULL
, 0 );
2744 if (!(strW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
2746 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
2749 MultiByteToWideChar( codepage
, 0, lpLCData
, -1, strW
, len
);
2750 ret
= SetLocaleInfoW( Locale
, LCType
, strW
);
2751 HeapFree( GetProcessHeap(), 0, strW
);
2756 /**********************************************************************
2758 * RIPPED FROM WINE's dlls\kernel\locale.c ver 0.9.29
2760 * SetLocaleInfoW (KERNEL32.@)
2762 * See SetLocaleInfoA.
2774 UNICODE_STRING valueW
;
2779 value
= RosGetLocaleValueName( LCType
);
2781 if (!lpLCData
|| !value
)
2783 SetLastError( ERROR_INVALID_PARAMETER
);
2787 if (LCType
== LOCALE_IDATE
|| LCType
== LOCALE_ILDATE
)
2789 SetLastError( ERROR_INVALID_FLAGS
);
2793 if (!(hkey
= RosCreateRegistryKey())) return FALSE
;
2794 RtlInitUnicodeString( &valueW
, value
);
2795 status
= NtSetValueKey( hkey
, &valueW
, 0, REG_SZ
, (PVOID
)lpLCData
, (lstrlenW(lpLCData
)+1)*sizeof(WCHAR
) );
2797 if (LCType
== LOCALE_SSHORTDATE
|| LCType
== LOCALE_SLONGDATE
)
2799 /* Set I-value from S value */
2800 WCHAR
*lpD
, *lpM
, *lpY
;
2803 lpD
= wcschr(lpLCData
, 'd');
2804 lpM
= wcschr(lpLCData
, 'M');
2805 lpY
= wcschr(lpLCData
, 'y');
2809 szBuff
[0] = '1'; /* D-M-Y */
2814 szBuff
[0] = '2'; /* Y-M-D */
2816 szBuff
[0] = '0'; /* M-D-Y */
2821 if (LCType
== LOCALE_SSHORTDATE
)
2822 LCType
= LOCALE_IDATE
;
2824 LCType
= LOCALE_ILDATE
;
2826 value
= RosGetLocaleValueName( LCType
);
2828 RtlInitUnicodeString( &valueW
, value
);
2829 status
= NtSetValueKey( hkey
, &valueW
, 0, REG_SZ
, szBuff
, sizeof(szBuff
) );
2834 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
2839 /**********************************************************************
2841 * RIPPED FROM WINE's dlls\kernel\locale.c rev 1.42
2843 * SetThreadLocale (KERNEL32.@)
2845 * Set the current threads locale.
2848 * lcid [I] LCID of the locale to set
2851 * Success: TRUE. The threads locale is set to lcid.
2852 * Failure: FALSE. Use GetLastError() to determine the cause.
2855 BOOL WINAPI
SetThreadLocale( LCID lcid
)
2857 DPRINT("SetThreadLocale(0x%04lX)\n", lcid
);
2859 lcid
= ConvertDefaultLocale(lcid
);
2861 if (lcid
!= GetThreadLocale())
2863 if (!IsValidLocale(lcid
, LCID_SUPPORTED
))
2865 SetLastError(ERROR_INVALID_PARAMETER
);
2869 NtCurrentTeb()->CurrentLocale
= lcid
;
2870 /* FIXME: NtCurrentTeb()->code_page = get_lcid_codepage( lcid );
2871 * Wine save the acp for easy/fast access, but ROS has no such Teb member.
2872 * Maybe add this member to ros as well?
2876 Lag test app for å se om locale etc, endres i en app. etter at prosessen er
2877 startet, eller om bare nye prosesser blir berørt.
2888 SetUserDefaultLCID(LCID lcid
)
2892 Status
= NtSetDefaultLocale(TRUE
, lcid
);
2893 if (!NT_SUCCESS(Status
))
2895 SetLastErrorByStatus(Status
);
2906 SetUserDefaultUILanguage(LANGID LangId
)
2910 Status
= NtSetDefaultUILanguage(LangId
);
2911 if (!NT_SUCCESS(Status
))
2913 SetLastErrorByStatus(Status
);
2928 static const WCHAR geoW
[] = {'G','e','o',0};
2929 static const WCHAR nationW
[] = {'N','a','t','i','o','n',0};
2930 static const WCHAR formatW
[] = {'%','i',0};
2931 UNICODE_STRING nameW
,keyW
;
2933 OBJECT_ATTRIBUTES attr
;
2936 if(!(hkey
= create_registry_key())) return FALSE
;
2938 attr
.Length
= sizeof(attr
);
2939 attr
.RootDirectory
= hkey
;
2940 attr
.ObjectName
= &nameW
;
2941 attr
.Attributes
= 0;
2942 attr
.SecurityDescriptor
= NULL
;
2943 attr
.SecurityQualityOfService
= NULL
;
2944 RtlInitUnicodeString( &nameW
, geoW
);
2945 RtlInitUnicodeString( &keyW
, nationW
);
2947 if (NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
)
2950 NtClose(attr
.RootDirectory
);
2954 swprintf(bufferW
, formatW
, GeoId
);
2955 NtSetValueKey(hkey
, &keyW
, 0, REG_SZ
, bufferW
, (wcslen(bufferW
) + 1) * sizeof(WCHAR
));
2956 NtClose(attr
.RootDirectory
);
2973 return GetLocaleInfoA( MAKELCID(wLang
, SORT_DEFAULT
), LOCALE_SENGLANGUAGE
, szLang
, nSize
);
2988 return GetLocaleInfoW( MAKELCID(wLang
, SORT_DEFAULT
), LOCALE_SENGLANGUAGE
, szLang
, nSize
);
2991 /***********************************************************************
2992 * LCIDToLocaleName (KERNEL32.@) Wine 13.02.2009
2994 INT WINAPI
LCIDToLocaleName( LCID lcid
, LPWSTR name
, INT count
, DWORD flags
)
2996 if (flags
) DPRINT1( "unsupported flags %x\n", flags
);
2998 return GetLocaleInfoW( lcid
, LOCALE_SNAME
| LOCALE_NOUSEROVERRIDE
, name
, count
);