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
25 #include "lcformat_private.h"
27 #define LOCALE_LOCALEINFOFLAGSMASK (LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP|\
28 LOCALE_RETURN_NUMBER|LOCALE_RETURN_GENITIVE_NAMES)
29 #define CALINFO_MAX_YEAR 2029
31 //static LCID SystemLocale = MAKELCID(LANG_ENGLISH, SORT_DEFAULT);
33 //static RTL_CRITICAL_SECTION LocalesListLock;
35 extern int wine_fold_string(int flags
, const WCHAR
*src
, int srclen
, WCHAR
*dst
, int dstlen
);
36 extern int wine_get_sortkey(int flags
, const WCHAR
*src
, int srclen
, char *dst
, int dstlen
);
37 extern int wine_compare_string(int flags
, const WCHAR
*str1
, int len1
, const WCHAR
*str2
, int len2
);
43 UILANGUAGE_ENUMPROCA procA
;
44 UILANGUAGE_ENUMPROCW procW
;
48 } ENUM_UILANG_CALLBACK
;
50 static const WCHAR szLocaleKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NLS\\Locale";
51 static const WCHAR szLangGroupsKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NLS\\Language Groups";
53 /***********************************************************************
54 * is_genitive_name_supported
56 * Determine could LCTYPE basically support genitive name form or not.
58 static BOOL
is_genitive_name_supported( LCTYPE lctype
)
60 switch(lctype
& 0xffff)
62 case LOCALE_SMONTHNAME1
:
63 case LOCALE_SMONTHNAME2
:
64 case LOCALE_SMONTHNAME3
:
65 case LOCALE_SMONTHNAME4
:
66 case LOCALE_SMONTHNAME5
:
67 case LOCALE_SMONTHNAME6
:
68 case LOCALE_SMONTHNAME7
:
69 case LOCALE_SMONTHNAME8
:
70 case LOCALE_SMONTHNAME9
:
71 case LOCALE_SMONTHNAME10
:
72 case LOCALE_SMONTHNAME11
:
73 case LOCALE_SMONTHNAME12
:
74 case LOCALE_SMONTHNAME13
:
81 /***********************************************************************
84 * Create the Control Panel\\International registry key.
86 static inline HANDLE
create_registry_key(void)
88 static const WCHAR intlW
[] = {'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
89 'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
90 OBJECT_ATTRIBUTES attr
;
94 if (RtlOpenCurrentUser( KEY_ALL_ACCESS
, &hkey
) != STATUS_SUCCESS
) return 0;
96 attr
.Length
= sizeof(attr
);
97 attr
.RootDirectory
= hkey
;
98 attr
.ObjectName
= &nameW
;
100 attr
.SecurityDescriptor
= NULL
;
101 attr
.SecurityQualityOfService
= NULL
;
102 RtlInitUnicodeString( &nameW
, intlW
);
104 if (NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
) hkey
= 0;
105 NtClose( attr
.RootDirectory
);
109 /******************************************************************************
111 * RIPPED FROM WINE's dlls\kernel\locale.c rev 1.42
113 * ConvertDefaultLocale (KERNEL32.@)
115 * Convert a default locale identifier into a real identifier.
118 * lcid [I] LCID identifier of the locale to convert
121 * lcid unchanged, if not a default locale or its sublanguage is
122 * not SUBLANG_NEUTRAL.
123 * GetSystemDefaultLCID(), if lcid == LOCALE_SYSTEM_DEFAULT.
124 * GetUserDefaultLCID(), if lcid == LOCALE_USER_DEFAULT or LOCALE_NEUTRAL.
125 * Otherwise, lcid with sublanguage changed to SUBLANG_DEFAULT.
128 ConvertDefaultLocale(LCID lcid
)
134 case LOCALE_SYSTEM_DEFAULT
:
135 lcid
= GetSystemDefaultLCID();
138 case LOCALE_USER_DEFAULT
:
140 lcid
= GetUserDefaultLCID();
144 /* Replace SUBLANG_NEUTRAL with SUBLANG_DEFAULT */
145 langid
= LANGIDFROMLCID(lcid
);
146 if (SUBLANGID(langid
) == SUBLANG_NEUTRAL
)
148 langid
= MAKELANGID(PRIMARYLANGID(langid
), SUBLANG_DEFAULT
);
149 lcid
= MAKELCID(langid
, SORTIDFROMLCID(lcid
));
157 static BOOL
NLS_RegEnumValue(HANDLE hKey
, UINT ulIndex
,
158 LPWSTR szValueName
, ULONG valueNameSize
,
159 LPWSTR szValueData
, ULONG valueDataSize
)
162 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
165 if (NtEnumerateValueKey( hKey
, ulIndex
, KeyValueFullInformation
,
166 buffer
, sizeof(buffer
), &dwLen
) != STATUS_SUCCESS
||
167 info
->NameLength
> valueNameSize
||
168 info
->DataLength
> valueDataSize
)
173 DPRINT("info->Name %s info->DataLength %d\n", info
->Name
, info
->DataLength
);
175 memcpy( szValueName
, info
->Name
, info
->NameLength
);
176 szValueName
[info
->NameLength
/ sizeof(WCHAR
)] = '\0';
177 memcpy( szValueData
, buffer
+ info
->DataOffset
, info
->DataLength
);
178 szValueData
[info
->DataLength
/ sizeof(WCHAR
)] = '\0';
180 DPRINT("returning %s %s\n", szValueName
, szValueData
);
185 static HANDLE
NLS_RegOpenKey(HANDLE hRootKey
, LPCWSTR szKeyName
)
187 UNICODE_STRING keyName
;
188 OBJECT_ATTRIBUTES attr
;
191 RtlInitUnicodeString( &keyName
, szKeyName
);
192 InitializeObjectAttributes(&attr
, &keyName
, OBJ_CASE_INSENSITIVE
, hRootKey
, NULL
);
194 if (NtOpenKey( &hkey
, KEY_ALL_ACCESS
, &attr
) != STATUS_SUCCESS
)
196 SetLastError( ERROR_BADDB
);
203 static BOOL
NLS_RegEnumSubKey(HANDLE hKey
, UINT ulIndex
, LPWSTR szKeyName
,
207 KEY_BASIC_INFORMATION
*info
= (KEY_BASIC_INFORMATION
*)buffer
;
210 if (NtEnumerateKey( hKey
, ulIndex
, KeyBasicInformation
, buffer
,
211 sizeof(buffer
), &dwLen
) != STATUS_SUCCESS
||
212 info
->NameLength
> keyNameSize
)
217 DPRINT("info->Name %s info->NameLength %d\n", info
->Name
, info
->NameLength
);
219 memcpy( szKeyName
, info
->Name
, info
->NameLength
);
220 szKeyName
[info
->NameLength
/ sizeof(WCHAR
)] = '\0';
222 DPRINT("returning %s\n", szKeyName
);
226 static BOOL
NLS_RegGetDword(HANDLE hKey
, LPCWSTR szValueName
, DWORD
*lpVal
)
229 const KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
230 DWORD dwSize
= sizeof(buffer
);
231 UNICODE_STRING valueName
;
233 RtlInitUnicodeString( &valueName
, szValueName
);
235 DPRINT("%p, %s\n", hKey
, szValueName
);
236 if (NtQueryValueKey( hKey
, &valueName
, KeyValuePartialInformation
,
237 buffer
, dwSize
, &dwSize
) == STATUS_SUCCESS
&&
238 info
->DataLength
== sizeof(DWORD
))
240 memcpy(lpVal
, info
->Data
, sizeof(DWORD
));
247 static BOOL
NLS_GetLanguageGroupName(LGRPID lgrpid
, LPWSTR szName
, ULONG nameSize
)
250 LPCWSTR szResourceName
= MAKEINTRESOURCEW(((lgrpid
+ 0x2000) >> 4) + 1);
254 /* FIXME: Is it correct to use the system default langid? */
255 langId
= GetSystemDefaultLangID();
257 if (SUBLANGID(langId
) == SUBLANG_NEUTRAL
)
258 langId
= MAKELANGID( PRIMARYLANGID(langId
), SUBLANG_DEFAULT
);
260 hResource
= FindResourceExW( hCurrentModule
, (LPWSTR
)RT_STRING
, szResourceName
, langId
);
264 HGLOBAL hResDir
= LoadResource( hCurrentModule
, hResource
);
268 ULONG iResourceIndex
= lgrpid
& 0xf;
269 LPCWSTR lpResEntry
= LockResource( hResDir
);
272 for (i
= 0; i
< iResourceIndex
; i
++)
273 lpResEntry
+= *lpResEntry
+ 1;
275 if (*lpResEntry
< nameSize
)
277 memcpy( szName
, lpResEntry
+ 1, *lpResEntry
* sizeof(WCHAR
) );
278 szName
[*lpResEntry
] = '\0';
283 FreeResource( hResource
);
285 else DPRINT1("FindResourceExW() failed\n");
291 /* Callback function ptrs for EnumLanguageGrouplocalesA/W */
294 LANGGROUPLOCALE_ENUMPROCA procA
;
295 LANGGROUPLOCALE_ENUMPROCW procW
;
299 } ENUMLANGUAGEGROUPLOCALE_CALLBACKS
;
301 /* Internal implementation of EnumLanguageGrouplocalesA/W */
302 static BOOL
NLS_EnumLanguageGroupLocales(ENUMLANGUAGEGROUPLOCALE_CALLBACKS
*lpProcs
)
304 static const WCHAR szAlternateSortsKeyName
[] = {
305 'A','l','t','e','r','n','a','t','e',' ','S','o','r','t','s','\0'
307 WCHAR szNumber
[10], szValue
[4];
309 BOOL bContinue
= TRUE
, bAlternate
= FALSE
;
311 ULONG ulIndex
= 1; /* Ignore default entry of 1st key */
313 if (!lpProcs
|| !lpProcs
->lgrpid
|| lpProcs
->lgrpid
> LGRPID_ARMENIAN
)
315 SetLastError(ERROR_INVALID_PARAMETER
);
319 if (lpProcs
->dwFlags
)
321 SetLastError(ERROR_INVALID_FLAGS
);
325 hKey
= NLS_RegOpenKey( 0, szLocaleKeyName
);
329 DPRINT1("NLS_RegOpenKey() failed\n");
335 if (NLS_RegEnumValue( hKey
, ulIndex
, szNumber
, sizeof(szNumber
),
336 szValue
, sizeof(szValue
) ))
338 lgrpid
= wcstoul( szValue
, NULL
, 16 );
340 DPRINT("lcid %s, grpid %d (%smatched)\n", szNumber
,
341 lgrpid
, lgrpid
== lpProcs
->lgrpid
? "" : "not ");
343 if (lgrpid
== lpProcs
->lgrpid
)
347 lcid
= wcstoul( szNumber
, NULL
, 16 );
349 /* FIXME: native returns extra text for a few (17/150) locales, e.g:
350 * '00000437 ;Georgian'
351 * At present we only pass the LCID string.
355 bContinue
= lpProcs
->procW( lgrpid
, lcid
, szNumber
, lpProcs
->lParam
);
358 char szNumberA
[sizeof(szNumber
)/sizeof(WCHAR
)];
360 WideCharToMultiByte(CP_ACP
, 0, szNumber
, -1, szNumberA
, sizeof(szNumberA
), 0, 0);
362 bContinue
= lpProcs
->procA( lgrpid
, lcid
, szNumberA
, lpProcs
->lParam
);
370 /* Finished enumerating this key */
373 /* Enumerate alternate sorts also */
374 hKey
= NLS_RegOpenKey( hKey
, szAlternateSortsKeyName
);
379 bContinue
= FALSE
; /* Finished both keys */
398 EnumLanguageGroupLocalesA(
399 LANGGROUPLOCALE_ENUMPROCA lpLangGroupLocaleEnumProc
,
400 LGRPID LanguageGroup
,
404 ENUMLANGUAGEGROUPLOCALE_CALLBACKS callbacks
;
406 DPRINT("(%p,0x%08X,0x%08X,0x%08lX)\n", lpLangGroupLocaleEnumProc
, LanguageGroup
, dwFlags
, lParam
);
408 callbacks
.procA
= lpLangGroupLocaleEnumProc
;
409 callbacks
.procW
= NULL
;
410 callbacks
.dwFlags
= dwFlags
;
411 callbacks
.lgrpid
= LanguageGroup
;
412 callbacks
.lParam
= lParam
;
414 return NLS_EnumLanguageGroupLocales( lpLangGroupLocaleEnumProc
? &callbacks
: NULL
);
423 EnumLanguageGroupLocalesW(
424 LANGGROUPLOCALE_ENUMPROCW lpLangGroupLocaleEnumProc
,
425 LGRPID LanguageGroup
,
429 ENUMLANGUAGEGROUPLOCALE_CALLBACKS callbacks
;
431 DPRINT("(%p,0x%08X,0x%08X,0x%08lX)\n", lpLangGroupLocaleEnumProc
, LanguageGroup
, dwFlags
, lParam
);
433 callbacks
.procA
= NULL
;
434 callbacks
.procW
= lpLangGroupLocaleEnumProc
;
435 callbacks
.dwFlags
= dwFlags
;
436 callbacks
.lgrpid
= LanguageGroup
;
437 callbacks
.lParam
= lParam
;
439 return NLS_EnumLanguageGroupLocales( lpLangGroupLocaleEnumProc
? &callbacks
: NULL
);
443 /* Callback function ptrs for EnumSystemCodePagesA/W */
446 CODEPAGE_ENUMPROCA procA
;
447 CODEPAGE_ENUMPROCW procW
;
449 } ENUMSYSTEMCODEPAGES_CALLBACKS
;
451 /* Internal implementation of EnumSystemCodePagesA/W */
452 static BOOL
NLS_EnumSystemCodePages(ENUMSYSTEMCODEPAGES_CALLBACKS
*lpProcs
)
454 WCHAR szNumber
[5 + 1], szValue
[MAX_PATH
];
456 BOOL bContinue
= TRUE
;
461 SetLastError(ERROR_INVALID_PARAMETER
);
465 switch (lpProcs
->dwFlags
)
471 SetLastError(ERROR_INVALID_FLAGS
);
475 hKey
= NLS_RegOpenKey(0, L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage");
478 DPRINT1("NLS_RegOpenKey() failed\n");
484 if (NLS_RegEnumValue(hKey
, ulIndex
, szNumber
, sizeof(szNumber
),
485 szValue
, sizeof(szValue
)))
487 if ((lpProcs
->dwFlags
== CP_SUPPORTED
)||
488 ((lpProcs
->dwFlags
== CP_INSTALLED
)&&(wcslen(szValue
) > 2)))
492 bContinue
= lpProcs
->procW(szNumber
);
496 char szNumberA
[sizeof(szNumber
)/sizeof(WCHAR
)];
498 WideCharToMultiByte(CP_ACP
, 0, szNumber
, -1, szNumberA
, sizeof(szNumberA
), 0, 0);
499 bContinue
= lpProcs
->procA(szNumberA
);
505 } else bContinue
= FALSE
;
522 EnumSystemCodePagesW (
523 CODEPAGE_ENUMPROCW lpCodePageEnumProc
,
527 ENUMSYSTEMCODEPAGES_CALLBACKS procs
;
529 DPRINT("(%p,0x%08X,0x%08lX)\n", lpCodePageEnumProc
, dwFlags
);
532 procs
.procW
= lpCodePageEnumProc
;
533 procs
.dwFlags
= dwFlags
;
535 return NLS_EnumSystemCodePages(lpCodePageEnumProc
? &procs
: NULL
);
544 EnumSystemCodePagesA (
545 CODEPAGE_ENUMPROCA lpCodePageEnumProc
,
549 ENUMSYSTEMCODEPAGES_CALLBACKS procs
;
551 DPRINT("(%p,0x%08X,0x%08lX)\n", lpCodePageEnumProc
, dwFlags
);
553 procs
.procA
= lpCodePageEnumProc
;
555 procs
.dwFlags
= dwFlags
;
557 return NLS_EnumSystemCodePages(lpCodePageEnumProc
? &procs
: NULL
);
568 GEOID ParentGeoId
, // reserved
569 GEO_ENUMPROC lpGeoEnumProc
)
571 WCHAR szNumber
[5 + 1];
575 DPRINT("(0x%08X,0x%08X,%p)\n", GeoClass
, ParentGeoId
, lpGeoEnumProc
);
577 if(!lpGeoEnumProc
|| GeoClass
!= GEOCLASS_NATION
)
579 SetLastError(ERROR_INVALID_PARAMETER
);
583 hKey
= NLS_RegOpenKey(0, L
"\\REGISTRY\\Machine\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Country List");
586 DPRINT1("NLS_RegOpenKey() failed\n");
590 while (NLS_RegEnumSubKey(hKey
, ulIndex
, szNumber
, sizeof(szNumber
)))
592 BOOL bContinue
= TRUE
;
594 HANDLE hSubKey
= NLS_RegOpenKey(hKey
, szNumber
);
598 if (NLS_RegGetDword(hSubKey
, L
"CountryCode", &dwGeoId
))
600 if (!lpGeoEnumProc(dwGeoId
))
620 /* Callback function ptrs for EnumSystemLanguageGroupsA/W */
623 LANGUAGEGROUP_ENUMPROCA procA
;
624 LANGUAGEGROUP_ENUMPROCW procW
;
627 } ENUMLANGUAGEGROUP_CALLBACKS
;
630 /* Internal implementation of EnumSystemLanguageGroupsA/W */
631 static BOOL
NLS_EnumSystemLanguageGroups(ENUMLANGUAGEGROUP_CALLBACKS
*lpProcs
)
633 WCHAR szNumber
[10], szValue
[4];
635 BOOL bContinue
= TRUE
;
640 SetLastError(ERROR_INVALID_PARAMETER
);
644 switch (lpProcs
->dwFlags
)
647 /* Default to LGRPID_INSTALLED */
648 lpProcs
->dwFlags
= LGRPID_INSTALLED
;
649 /* Fall through... */
650 case LGRPID_INSTALLED
:
651 case LGRPID_SUPPORTED
:
654 SetLastError(ERROR_INVALID_FLAGS
);
658 hKey
= NLS_RegOpenKey( 0, szLangGroupsKeyName
);
662 DPRINT1("NLS_RegOpenKey() failed, KeyName='%S'\n", szLangGroupsKeyName
);
668 if (NLS_RegEnumValue( hKey
, ulIndex
, szNumber
, sizeof(szNumber
),
669 szValue
, sizeof(szValue
) ))
671 BOOL bInstalled
= szValue
[0] == '1' ? TRUE
: FALSE
;
672 LGRPID lgrpid
= wcstoul( szNumber
, NULL
, 16 );
674 DPRINT("grpid %s (%sinstalled)\n", szNumber
,
675 bInstalled
? "" : "not ");
677 if (lpProcs
->dwFlags
== LGRPID_SUPPORTED
|| bInstalled
)
681 if (!NLS_GetLanguageGroupName( lgrpid
, szGrpName
, sizeof(szGrpName
) / sizeof(WCHAR
) ))
685 bContinue
= lpProcs
->procW( lgrpid
, szNumber
, szGrpName
, lpProcs
->dwFlags
,
689 char szNumberA
[sizeof(szNumber
)/sizeof(WCHAR
)];
692 /* FIXME: MSDN doesn't say which code page the W->A translation uses,
693 * or whether the language names are ever localised. Assume CP_ACP.
696 WideCharToMultiByte(CP_ACP
, 0, szNumber
, -1, szNumberA
, sizeof(szNumberA
), 0, 0);
697 WideCharToMultiByte(CP_ACP
, 0, szGrpName
, -1, szGrpNameA
, sizeof(szGrpNameA
), 0, 0);
699 bContinue
= lpProcs
->procA( lgrpid
, szNumberA
, szGrpNameA
, lpProcs
->dwFlags
,
725 EnumSystemLanguageGroupsA(
726 LANGUAGEGROUP_ENUMPROCA pLangGroupEnumProc
,
730 ENUMLANGUAGEGROUP_CALLBACKS procs
;
732 DPRINT("(%p,0x%08X,0x%08lX)\n", pLangGroupEnumProc
, dwFlags
, lParam
);
734 procs
.procA
= pLangGroupEnumProc
;
736 procs
.dwFlags
= dwFlags
;
737 procs
.lParam
= lParam
;
739 return NLS_EnumSystemLanguageGroups( pLangGroupEnumProc
? &procs
: NULL
);
748 EnumSystemLanguageGroupsW(
749 LANGUAGEGROUP_ENUMPROCW pLangGroupEnumProc
,
753 ENUMLANGUAGEGROUP_CALLBACKS procs
;
755 DPRINT("(%p,0x%08X,0x%08lX)\n", pLangGroupEnumProc
, dwFlags
, lParam
);
758 procs
.procW
= pLangGroupEnumProc
;
759 procs
.dwFlags
= dwFlags
;
760 procs
.lParam
= lParam
;
762 return NLS_EnumSystemLanguageGroups( pLangGroupEnumProc
? &procs
: NULL
);
766 /* Callback function ptrs for EnumSystemLocalesA/W */
769 LOCALE_ENUMPROCA procA
;
770 LOCALE_ENUMPROCW procW
;
772 } ENUMSYSTEMLOCALES_CALLBACKS
;
775 /* Internal implementation of EnumSystemLocalesA/W */
776 static BOOL
NLS_EnumSystemLocales(ENUMSYSTEMLOCALES_CALLBACKS
*lpProcs
)
778 WCHAR szNumber
[10], szValue
[4];
780 BOOL bContinue
= TRUE
;
785 SetLastError(ERROR_INVALID_PARAMETER
);
789 /* Passing 0 flags behaves like LCID_SUPPORTED */
790 if (lpProcs
->dwFlags
== 0)
792 lpProcs
->dwFlags
= LCID_SUPPORTED
;
795 switch (lpProcs
->dwFlags
)
797 case LCID_ALTERNATE_SORTS
:
802 SetLastError(ERROR_INVALID_FLAGS
);
806 hKey
= NLS_RegOpenKey(0, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\Locale");
810 DPRINT1("NLS_RegOpenKey() failed\n");
816 if (NLS_RegEnumValue( hKey
, ulIndex
, szNumber
, sizeof(szNumber
),
817 szValue
, sizeof(szValue
)))
819 if ((lpProcs
->dwFlags
== LCID_SUPPORTED
)||
820 ((lpProcs
->dwFlags
== LCID_INSTALLED
)&&(wcslen(szValue
) > 0)))
824 bContinue
= lpProcs
->procW(szNumber
);
828 char szNumberA
[sizeof(szNumber
)/sizeof(WCHAR
)];
830 WideCharToMultiByte(CP_ACP
, 0, szNumber
, -1, szNumberA
, sizeof(szNumberA
), 0, 0);
831 bContinue
= lpProcs
->procA(szNumberA
);
856 LOCALE_ENUMPROCA lpLocaleEnumProc
,
860 ENUMSYSTEMLOCALES_CALLBACKS procs
;
862 DPRINT("(%p,0x%08X)\n", lpLocaleEnumProc
, dwFlags
);
864 procs
.procA
= lpLocaleEnumProc
;
866 procs
.dwFlags
= dwFlags
;
868 return NLS_EnumSystemLocales(lpLocaleEnumProc
? &procs
: NULL
);
878 LOCALE_ENUMPROCW lpLocaleEnumProc
,
882 ENUMSYSTEMLOCALES_CALLBACKS procs
;
884 DPRINT("(%p,0x%08X)\n", lpLocaleEnumProc
, dwFlags
);
887 procs
.procW
= lpLocaleEnumProc
;
888 procs
.dwFlags
= dwFlags
;
890 return NLS_EnumSystemLocales(lpLocaleEnumProc
? &procs
: NULL
);
894 static BOOL CALLBACK
enum_uilang_proc_a( HMODULE hModule
, LPCSTR type
,
895 LPCSTR name
, WORD LangID
, LONG_PTR lParam
)
897 ENUM_UILANG_CALLBACK
*enum_uilang
= (ENUM_UILANG_CALLBACK
*)lParam
;
900 sprintf(buf
, "%08x", (UINT
)LangID
);
901 return enum_uilang
->u
.procA( buf
, enum_uilang
->param
);
911 UILANGUAGE_ENUMPROCA lpUILanguageEnumProc
,
915 ENUM_UILANG_CALLBACK enum_uilang
;
917 DPRINT("%p, %x, %lx\n", lpUILanguageEnumProc
, dwFlags
, lParam
);
919 if(!lpUILanguageEnumProc
) {
920 SetLastError(ERROR_INVALID_PARAMETER
);
924 SetLastError(ERROR_INVALID_FLAGS
);
928 enum_uilang
.u
.procA
= lpUILanguageEnumProc
;
929 enum_uilang
.flags
= dwFlags
;
930 enum_uilang
.param
= lParam
;
932 EnumResourceLanguagesA( hCurrentModule
, (LPCSTR
)RT_STRING
,
933 (LPCSTR
)LOCALE_ILANGUAGE
, enum_uilang_proc_a
,
934 (LONG_PTR
)&enum_uilang
);
938 static BOOL CALLBACK
enum_uilang_proc_w( HMODULE hModule
, LPCWSTR type
,
939 LPCWSTR name
, WORD LangID
, LONG_PTR lParam
)
941 static const WCHAR formatW
[] = {'%','0','8','x',0};
942 ENUM_UILANG_CALLBACK
*enum_uilang
= (ENUM_UILANG_CALLBACK
*)lParam
;
945 swprintf( buf
, formatW
, (UINT
)LangID
);
946 return enum_uilang
->u
.procW( buf
, enum_uilang
->param
);
955 UILANGUAGE_ENUMPROCW lpUILanguageEnumProc
,
959 ENUM_UILANG_CALLBACK enum_uilang
;
961 DPRINT("%p, %x, %lx\n", lpUILanguageEnumProc
, dwFlags
, lParam
);
964 if(!lpUILanguageEnumProc
) {
965 SetLastError(ERROR_INVALID_PARAMETER
);
969 SetLastError(ERROR_INVALID_FLAGS
);
973 enum_uilang
.u
.procW
= lpUILanguageEnumProc
;
974 enum_uilang
.flags
= dwFlags
;
975 enum_uilang
.param
= lParam
;
977 EnumResourceLanguagesW( hCurrentModule
, (LPCWSTR
)RT_STRING
,
978 (LPCWSTR
)LOCALE_ILANGUAGE
, enum_uilang_proc_w
,
979 (LONG_PTR
)&enum_uilang
);
998 LPWSTR lpCalDataW
= NULL
;
1000 if (NLS_IsUnicodeOnlyLcid(lcid
))
1002 SetLastError(ERROR_INVALID_PARAMETER
);
1007 !(lpCalDataW
= HeapAlloc(GetProcessHeap(), 0, cchData
*sizeof(WCHAR
))))
1010 ret
= GetCalendarInfoW(lcid
, Calendar
, CalType
, lpCalDataW
, cchData
, lpValue
);
1011 if(ret
&& lpCalDataW
&& lpCalData
)
1012 WideCharToMultiByte(CP_ACP
, 0, lpCalDataW
, cchData
, lpCalData
, cchData
, NULL
, NULL
);
1013 HeapFree(GetProcessHeap(), 0, lpCalDataW
);
1032 if (CalType
& CAL_NOUSEROVERRIDE
)
1033 DPRINT("FIXME: flag CAL_NOUSEROVERRIDE used, not fully implemented\n");
1034 if (CalType
& CAL_USE_CP_ACP
)
1035 DPRINT("FIXME: flag CAL_USE_CP_ACP used, not fully implemented\n");
1037 if (CalType
& CAL_RETURN_NUMBER
) {
1038 if (lpCalData
!= NULL
)
1039 DPRINT("WARNING: lpCalData not NULL (%p) when it should!\n", lpCalData
);
1041 DPRINT("WARNING: cchData not 0 (%d) when it should!\n", cchData
);
1043 if (lpValue
!= NULL
)
1044 DPRINT("WARNING: lpValue not NULL (%p) when it should!\n", lpValue
);
1047 /* FIXME: No verification is made yet wrt Locale
1048 * for the CALTYPES not requiring GetLocaleInfoA */
1049 switch (CalType
& ~(CAL_NOUSEROVERRIDE
|CAL_RETURN_NUMBER
|CAL_USE_CP_ACP
)) {
1050 case CAL_ICALINTVALUE
:
1051 DPRINT("FIXME: Unimplemented caltype %d\n", CalType
& 0xffff);
1054 DPRINT("FIXME: Unimplemented caltype %d\n", CalType
& 0xffff);
1056 case CAL_IYEAROFFSETRANGE
:
1057 DPRINT("FIXME: Unimplemented caltype %d\n", CalType
& 0xffff);
1059 case CAL_SERASTRING
:
1060 DPRINT("FIXME: Unimplemented caltype %d\n", CalType
& 0xffff);
1062 case CAL_SSHORTDATE
:
1063 return GetLocaleInfoW(Locale
, LOCALE_SSHORTDATE
, lpCalData
, cchData
);
1065 return GetLocaleInfoW(Locale
, LOCALE_SLONGDATE
, lpCalData
, cchData
);
1067 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME1
, lpCalData
, cchData
);
1069 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME2
, lpCalData
, cchData
);
1071 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME3
, lpCalData
, cchData
);
1073 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME4
, lpCalData
, cchData
);
1075 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME5
, lpCalData
, cchData
);
1077 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME6
, lpCalData
, cchData
);
1079 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME7
, lpCalData
, cchData
);
1080 case CAL_SABBREVDAYNAME1
:
1081 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME1
, lpCalData
, cchData
);
1082 case CAL_SABBREVDAYNAME2
:
1083 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME2
, lpCalData
, cchData
);
1084 case CAL_SABBREVDAYNAME3
:
1085 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME3
, lpCalData
, cchData
);
1086 case CAL_SABBREVDAYNAME4
:
1087 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME4
, lpCalData
, cchData
);
1088 case CAL_SABBREVDAYNAME5
:
1089 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME5
, lpCalData
, cchData
);
1090 case CAL_SABBREVDAYNAME6
:
1091 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME6
, lpCalData
, cchData
);
1092 case CAL_SABBREVDAYNAME7
:
1093 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME7
, lpCalData
, cchData
);
1094 case CAL_SMONTHNAME1
:
1095 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME1
, lpCalData
, cchData
);
1096 case CAL_SMONTHNAME2
:
1097 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME2
, lpCalData
, cchData
);
1098 case CAL_SMONTHNAME3
:
1099 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME3
, lpCalData
, cchData
);
1100 case CAL_SMONTHNAME4
:
1101 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME4
, lpCalData
, cchData
);
1102 case CAL_SMONTHNAME5
:
1103 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME5
, lpCalData
, cchData
);
1104 case CAL_SMONTHNAME6
:
1105 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME6
, lpCalData
, cchData
);
1106 case CAL_SMONTHNAME7
:
1107 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME7
, lpCalData
, cchData
);
1108 case CAL_SMONTHNAME8
:
1109 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME8
, lpCalData
, cchData
);
1110 case CAL_SMONTHNAME9
:
1111 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME9
, lpCalData
, cchData
);
1112 case CAL_SMONTHNAME10
:
1113 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME10
, lpCalData
, cchData
);
1114 case CAL_SMONTHNAME11
:
1115 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME11
, lpCalData
, cchData
);
1116 case CAL_SMONTHNAME12
:
1117 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME12
, lpCalData
, cchData
);
1118 case CAL_SMONTHNAME13
:
1119 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME13
, lpCalData
, cchData
);
1120 case CAL_SABBREVMONTHNAME1
:
1121 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME1
, lpCalData
, cchData
);
1122 case CAL_SABBREVMONTHNAME2
:
1123 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME2
, lpCalData
, cchData
);
1124 case CAL_SABBREVMONTHNAME3
:
1125 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME3
, lpCalData
, cchData
);
1126 case CAL_SABBREVMONTHNAME4
:
1127 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME4
, lpCalData
, cchData
);
1128 case CAL_SABBREVMONTHNAME5
:
1129 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME5
, lpCalData
, cchData
);
1130 case CAL_SABBREVMONTHNAME6
:
1131 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME6
, lpCalData
, cchData
);
1132 case CAL_SABBREVMONTHNAME7
:
1133 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME7
, lpCalData
, cchData
);
1134 case CAL_SABBREVMONTHNAME8
:
1135 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME8
, lpCalData
, cchData
);
1136 case CAL_SABBREVMONTHNAME9
:
1137 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME9
, lpCalData
, cchData
);
1138 case CAL_SABBREVMONTHNAME10
:
1139 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME10
, lpCalData
, cchData
);
1140 case CAL_SABBREVMONTHNAME11
:
1141 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME11
, lpCalData
, cchData
);
1142 case CAL_SABBREVMONTHNAME12
:
1143 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME12
, lpCalData
, cchData
);
1144 case CAL_SABBREVMONTHNAME13
:
1145 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME13
, lpCalData
, cchData
);
1146 case CAL_SYEARMONTH
:
1147 return GetLocaleInfoW(Locale
, LOCALE_SYEARMONTH
, lpCalData
, cchData
);
1148 case CAL_ITWODIGITYEARMAX
:
1149 if (lpValue
) *lpValue
= CALINFO_MAX_YEAR
;
1151 default: DPRINT("Unknown caltype %d\n",CalType
& 0xffff);
1163 GetCPInfo(UINT CodePage
,
1164 LPCPINFO CodePageInfo
)
1166 PCODEPAGE_ENTRY CodePageEntry
;
1170 SetLastError(ERROR_INVALID_PARAMETER
);
1174 CodePageEntry
= IntGetCodePageEntry(CodePage
);
1175 if (CodePageEntry
== NULL
)
1181 CodePageInfo
->DefaultChar
[0] = 0x3f;
1182 CodePageInfo
->DefaultChar
[1] = 0;
1183 CodePageInfo
->LeadByte
[0] = CodePageInfo
->LeadByte
[1] = 0;
1184 CodePageInfo
->MaxCharSize
= (CodePage
== CP_UTF7
) ? 5 : 4;
1188 SetLastError( ERROR_INVALID_PARAMETER
);
1192 if (CodePageEntry
->CodePageTable
.DefaultChar
& 0xff00)
1194 CodePageInfo
->DefaultChar
[0] = (CodePageEntry
->CodePageTable
.DefaultChar
& 0xff00) >> 8;
1195 CodePageInfo
->DefaultChar
[1] = CodePageEntry
->CodePageTable
.DefaultChar
& 0x00ff;
1199 CodePageInfo
->DefaultChar
[0] = CodePageEntry
->CodePageTable
.DefaultChar
& 0xff;
1200 CodePageInfo
->DefaultChar
[1] = 0;
1203 if ((CodePageInfo
->MaxCharSize
= CodePageEntry
->CodePageTable
.MaximumCharacterSize
) == 2)
1204 memcpy(CodePageInfo
->LeadByte
, CodePageEntry
->CodePageTable
.LeadByte
, sizeof(CodePageInfo
->LeadByte
));
1206 CodePageInfo
->LeadByte
[0] = CodePageInfo
->LeadByte
[1] = 0;
1212 GetLocalisedText(DWORD dwResId
, WCHAR
*lpszDest
)
1220 dwId
= dwResId
* 100;
1224 lcid
= GetUserDefaultLCID();
1225 lcid
= ConvertDefaultLocale(lcid
);
1227 langId
= LANGIDFROMLCID(lcid
);
1229 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
1230 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
);
1232 hrsrc
= FindResourceExW(hCurrentModule
,
1234 MAKEINTRESOURCEW((dwId
>> 4) + 1),
1238 HGLOBAL hmem
= LoadResource(hCurrentModule
, hrsrc
);
1245 p
= LockResource(hmem
);
1246 for (i
= 0; i
< (dwId
& 0x0f); i
++) p
+= *p
+ 1;
1248 memcpy(lpszDest
, p
+ 1, *p
* sizeof(WCHAR
));
1249 lpszDest
[*p
] = '\0';
1255 DPRINT1("Could not get codepage name. dwResId = %ld\n", dwResId
);
1264 GetCPInfoExW(UINT CodePage
,
1266 LPCPINFOEXW lpCPInfoEx
)
1268 if (!GetCPInfo(CodePage
, (LPCPINFO
) lpCPInfoEx
))
1275 lpCPInfoEx
->CodePage
= CP_UTF7
;
1276 lpCPInfoEx
->UnicodeDefaultChar
= 0x3f;
1277 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
);
1283 lpCPInfoEx
->CodePage
= CP_UTF8
;
1284 lpCPInfoEx
->UnicodeDefaultChar
= 0x3f;
1285 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
);
1290 PCODEPAGE_ENTRY CodePageEntry
;
1292 CodePageEntry
= IntGetCodePageEntry(CodePage
);
1293 if (CodePageEntry
== NULL
)
1295 DPRINT1("Could not get CodePage Entry! CodePageEntry = 0\n");
1296 SetLastError(ERROR_INVALID_PARAMETER
);
1300 lpCPInfoEx
->CodePage
= CodePageEntry
->CodePageTable
.CodePage
;
1301 lpCPInfoEx
->UnicodeDefaultChar
= CodePageEntry
->CodePageTable
.UniDefaultChar
;
1302 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
);
1314 GetCPInfoExA(UINT CodePage
,
1316 LPCPINFOEXA lpCPInfoEx
)
1320 if (!GetCPInfoExW(CodePage
, dwFlags
, &CPInfo
))
1323 /* the layout is the same except for CodePageName */
1324 memcpy(lpCPInfoEx
, &CPInfo
, sizeof(CPINFOEXA
));
1326 WideCharToMultiByte(CP_ACP
,
1328 CPInfo
.CodePageName
,
1330 lpCPInfoEx
->CodePageName
,
1331 sizeof(lpCPInfoEx
->CodePageName
),
1338 NLS_GetGeoFriendlyName(GEOID Location
, LPWSTR szFriendlyName
, int cchData
)
1341 WCHAR szPath
[MAX_PATH
];
1342 UNICODE_STRING ValueName
;
1343 KEY_VALUE_PARTIAL_INFORMATION
*info
;
1344 static const int info_size
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1349 swprintf(szPath
, L
"\\REGISTRY\\Machine\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Country List\\%d", Location
);
1351 hKey
= NLS_RegOpenKey(0, szPath
);
1354 DPRINT1("NLS_RegOpenKey() failed\n");
1358 dwSize
= info_size
+ cchData
* sizeof(WCHAR
);
1360 if (!(info
= HeapAlloc(GetProcessHeap(), 0, dwSize
)))
1363 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1367 RtlInitUnicodeString(&ValueName
, L
"Name");
1369 Status
= NtQueryValueKey(hKey
, &ValueName
, KeyValuePartialInformation
,
1370 (LPBYTE
)info
, dwSize
, &dwSize
);
1374 Ret
= (dwSize
- info_size
) / sizeof(WCHAR
);
1376 if (!Ret
|| ((WCHAR
*)info
->Data
)[Ret
-1])
1378 if (Ret
< cchData
|| !szFriendlyName
) Ret
++;
1381 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1386 if (Ret
&& szFriendlyName
)
1388 memcpy(szFriendlyName
, info
->Data
, (Ret
-1) * sizeof(WCHAR
));
1389 szFriendlyName
[Ret
-1] = 0;
1392 else if (Status
== STATUS_BUFFER_OVERFLOW
&& !szFriendlyName
)
1394 Ret
= (dwSize
- info_size
) / sizeof(WCHAR
) + 1;
1396 else if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1402 SetLastError(RtlNtStatusToDosError(Status
));
1407 HeapFree(GetProcessHeap(), 0, info
);
1424 DPRINT("%d %d %p %d %d\n", Location
, GeoType
, lpGeoData
, cchData
, LangId
);
1426 if ((GeoType
== GEO_TIMEZONES
)||(GeoType
== GEO_OFFICIALLANGUAGES
))
1428 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1433 case GEO_FRIENDLYNAME
:
1435 return NLS_GetGeoFriendlyName(Location
, lpGeoData
, cchData
);
1444 case GEO_OFFICIALNAME
:
1445 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1465 DPRINT("%d %d %p %d %d\n", Location
, GeoType
, lpGeoData
, cchData
, LangId
);
1467 if ((GeoType
== GEO_TIMEZONES
)||(GeoType
== GEO_OFFICIALLANGUAGES
))
1469 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1474 case GEO_FRIENDLYNAME
:
1476 WCHAR szBuffer
[MAX_PATH
];
1477 char szBufferA
[sizeof(szBuffer
)/sizeof(WCHAR
)];
1480 Ret
= NLS_GetGeoFriendlyName(Location
, szBuffer
, cchData
);
1482 WideCharToMultiByte(CP_ACP
, 0, szBuffer
, -1, szBufferA
, sizeof(szBufferA
), 0, 0);
1483 strcpy(lpGeoData
, szBufferA
);
1494 case GEO_OFFICIALNAME
:
1495 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1502 const WCHAR
*RosGetLocaleValueName( DWORD lctype
)
1504 switch (lctype
& ~LOCALE_LOCALEINFOFLAGSMASK
)
1506 /* These values are used by SetLocaleInfo and GetLocaleInfo, and
1507 * the values are stored in the registry, confirmed under Windows.
1509 case LOCALE_ICALENDARTYPE
: return L
"iCalendarType";
1510 case LOCALE_ICURRDIGITS
: return L
"iCurrDigits";
1511 case LOCALE_ICURRENCY
: return L
"iCurrency";
1512 case LOCALE_IDIGITS
: return L
"iDigits";
1513 case LOCALE_IFIRSTDAYOFWEEK
: return L
"iFirstDayOfWeek";
1514 case LOCALE_IFIRSTWEEKOFYEAR
: return L
"iFirstWeekOfYear";
1515 case LOCALE_ILZERO
: return L
"iLZero";
1516 case LOCALE_IMEASURE
: return L
"iMeasure";
1517 case LOCALE_INEGCURR
: return L
"iNegCurr";
1518 case LOCALE_INEGNUMBER
: return L
"iNegNumber";
1519 case LOCALE_IPAPERSIZE
: return L
"iPaperSize";
1520 case LOCALE_ITIME
: return L
"iTime";
1521 case LOCALE_S1159
: return L
"s1159";
1522 case LOCALE_S2359
: return L
"s2359";
1523 case LOCALE_SCURRENCY
: return L
"sCurrency";
1524 case LOCALE_SDATE
: return L
"sDate";
1525 case LOCALE_SDECIMAL
: return L
"sDecimal";
1526 case LOCALE_SGROUPING
: return L
"sGrouping";
1527 case LOCALE_SLIST
: return L
"sList";
1528 case LOCALE_SLONGDATE
: return L
"sLongDate";
1529 case LOCALE_SMONDECIMALSEP
: return L
"sMonDecimalSep";
1530 case LOCALE_SMONGROUPING
: return L
"sMonGrouping";
1531 case LOCALE_SMONTHOUSANDSEP
: return L
"sMonThousandSep";
1532 case LOCALE_SNEGATIVESIGN
: return L
"sNegativeSign";
1533 case LOCALE_SPOSITIVESIGN
: return L
"sPositiveSign";
1534 case LOCALE_SSHORTDATE
: return L
"sShortDate";
1535 case LOCALE_STHOUSAND
: return L
"sThousand";
1536 case LOCALE_STIME
: return L
"sTime";
1537 case LOCALE_STIMEFORMAT
: return L
"sTimeFormat";
1538 case LOCALE_SYEARMONTH
: return L
"sYearMonth";
1540 /* The following are not listed under MSDN as supported,
1541 * but seem to be used and also stored in the registry.
1543 case LOCALE_ICOUNTRY
: return L
"iCountry";
1544 case LOCALE_IDATE
: return L
"iDate";
1545 case LOCALE_ILDATE
: return L
"iLDate";
1546 case LOCALE_ITLZERO
: return L
"iTLZero";
1547 case LOCALE_SCOUNTRY
: return L
"sCountry";
1548 case LOCALE_SLANGUAGE
: return L
"sLanguage";
1550 /* The following are used in XP and later */
1551 case LOCALE_IDIGITSUBSTITUTION
: return L
"NumShape";
1552 case LOCALE_SNATIVEDIGITS
: return L
"sNativeDigits";
1553 case LOCALE_ITIMEMARKPOSN
: return L
"iTimePrefix";
1558 HKEY
RosCreateRegistryKey(void)
1560 OBJECT_ATTRIBUTES objAttr
;
1561 UNICODE_STRING nameW
;
1564 if (RtlOpenCurrentUser( KEY_ALL_ACCESS
, &hKey
) != STATUS_SUCCESS
) return 0;
1566 objAttr
.Length
= sizeof(objAttr
);
1567 objAttr
.RootDirectory
= hKey
;
1568 objAttr
.ObjectName
= &nameW
;
1569 objAttr
.Attributes
= 0;
1570 objAttr
.SecurityDescriptor
= NULL
;
1571 objAttr
.SecurityQualityOfService
= NULL
;
1572 RtlInitUnicodeString( &nameW
, L
"Control Panel\\International");
1574 if (NtCreateKey( &hKey
, KEY_ALL_ACCESS
, &objAttr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
) hKey
= 0;
1575 NtClose( objAttr
.RootDirectory
);
1579 INT
RosGetRegistryLocaleInfo( LPCWSTR lpValue
, LPWSTR lpBuffer
, INT nLen
)
1585 UNICODE_STRING usNameW
;
1586 KEY_VALUE_PARTIAL_INFORMATION
*kvpiInfo
;
1587 const int nInfoSize
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1589 if (!(hKey
= RosCreateRegistryKey())) return -1;
1591 RtlInitUnicodeString( &usNameW
, lpValue
);
1592 dwSize
= nInfoSize
+ nLen
* sizeof(WCHAR
);
1594 if (!(kvpiInfo
= HeapAlloc( GetProcessHeap(), 0, dwSize
)))
1597 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1601 ntStatus
= NtQueryValueKey( hKey
, &usNameW
, KeyValuePartialInformation
, kvpiInfo
, dwSize
, &dwSize
);
1605 nRet
= (dwSize
- nInfoSize
) / sizeof(WCHAR
);
1607 if (!nRet
|| ((WCHAR
*)kvpiInfo
->Data
)[nRet
- 1])
1609 if (nRet
< nLen
|| !lpBuffer
) nRet
++;
1612 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1616 if (nRet
&& lpBuffer
)
1618 memcpy( lpBuffer
, kvpiInfo
->Data
, (nRet
- 1) * sizeof(WCHAR
) );
1619 lpBuffer
[nRet
- 1] = 0;
1622 else if (ntStatus
== STATUS_BUFFER_OVERFLOW
&& !lpBuffer
)
1624 nRet
= (dwSize
- nInfoSize
) / sizeof(WCHAR
) + 1;
1626 else if (ntStatus
== STATUS_OBJECT_NAME_NOT_FOUND
)
1632 SetLastError( RtlNtStatusToDosError(ntStatus
) );
1636 HeapFree( GetProcessHeap(), 0, kvpiInfo
);
1643 LPCWSTR lpLocaleName
,
1673 if (cchData
< 0 || (cchData
&& !lpLCData
))
1675 SetLastError( ERROR_INVALID_PARAMETER
);
1678 if (LCType
& LOCALE_RETURN_GENITIVE_NAMES
&&
1679 !is_genitive_name_supported( LCType
))
1681 SetLastError( ERROR_INVALID_FLAGS
);
1685 if (!cchData
) lpLCData
= NULL
;
1687 if (Locale
== LOCALE_NEUTRAL
|| Locale
== LOCALE_SYSTEM_DEFAULT
) Locale
= GetSystemDefaultLCID();
1688 else if (Locale
== LOCALE_USER_DEFAULT
) Locale
= GetUserDefaultLCID();
1690 uiFlags
= LCType
& LOCALE_LOCALEINFOFLAGSMASK
;
1691 LCType
&= ~LOCALE_LOCALEINFOFLAGSMASK
;
1693 if (!(uiFlags
& LOCALE_NOUSEROVERRIDE
) && Locale
== GetUserDefaultLCID())
1695 const WCHAR
*value
= RosGetLocaleValueName(LCType
);
1697 if (value
&& ((nRet
= RosGetRegistryLocaleInfo( value
, lpLCData
, cchData
)) != -1)) return nRet
;
1700 liLangID
= LANGIDFROMLCID( Locale
);
1702 if (SUBLANGID(liLangID
) == SUBLANG_NEUTRAL
)
1703 liLangID
= MAKELANGID(PRIMARYLANGID(liLangID
), SUBLANG_DEFAULT
);
1705 hModule
= GetModuleHandleW( L
"kernel32.dll" );
1706 if (!(hRsrc
= FindResourceExW( hModule
, (LPWSTR
)RT_STRING
, (LPCWSTR
)((LCType
>> 4) + 1), liLangID
)))
1708 SetLastError( ERROR_INVALID_FLAGS
);
1711 if (!(hMem
= LoadResource( hModule
, hRsrc
)))
1714 ch
= LockResource( hMem
);
1715 for (i
= 0; i
< (LCType
& 0x0f); i
++) ch
+= *ch
+ 1;
1717 if (uiFlags
& LOCALE_RETURN_NUMBER
) nRet
= sizeof(UINT
) / sizeof(WCHAR
);
1718 else if (is_genitive_name_supported( LCType
) && *ch
)
1720 /* genitive form's stored after a null separator from a nominative */
1721 for (i
= 1; i
<= *ch
; i
++) if (!ch
[i
]) break;
1723 if (i
<= *ch
&& (uiFlags
& LOCALE_RETURN_GENITIVE_NAMES
))
1731 nRet
= (LCType
== LOCALE_FONTSIGNATURE
) ? *ch
: *ch
+ 1;
1733 if (!lpLCData
) return nRet
;
1737 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1741 if (uiFlags
& LOCALE_RETURN_NUMBER
)
1744 WCHAR
*chEnd
, *chTmp
= HeapAlloc( GetProcessHeap(), 0, (*ch
+ 1) * sizeof(WCHAR
) );
1749 memcpy( chTmp
, ch
+ 1, *ch
* sizeof(WCHAR
) );
1751 uiNum
= wcstol( chTmp
, &chEnd
, 10 );
1754 memcpy( lpLCData
, &uiNum
, sizeof(uiNum
) );
1757 SetLastError( ERROR_INVALID_FLAGS
);
1760 HeapFree( GetProcessHeap(), 0, chTmp
);
1764 memcpy( lpLCData
, ch
+ 1, nRet
* sizeof(WCHAR
) );
1765 if (LCType
!= LOCALE_FONTSIGNATURE
) lpLCData
[nRet
-1] = 0;
1772 /***********************************************************************
1775 * Retrieve the ANSI codepage for a given locale.
1777 __inline
static UINT
get_lcid_codepage( LCID lcid
)
1780 if (!GetLocaleInfoW( lcid
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
, (WCHAR
*)&ret
,
1781 sizeof(ret
)/sizeof(WCHAR
) )) ret
= 0;
1786 /*************************************************************************
1787 * FoldStringA (KERNEL32.@)
1789 * Map characters in a string.
1792 * dwFlags [I] Flags controlling chars to map (MAP_ constants from "winnls.h")
1793 * src [I] String to map
1794 * srclen [I] Length of src, or -1 if src is NUL terminated
1795 * dst [O] Destination for mapped string
1796 * dstlen [I] Length of dst, or 0 to find the required length for the mapped string
1799 * Success: The length of the string written to dst, including the terminating NUL. If
1800 * dstlen is 0, the value returned is the same, but nothing is written to dst,
1801 * and dst may be NULL.
1802 * Failure: 0. Use GetLastError() to determine the cause.
1804 INT WINAPI
FoldStringA(DWORD dwFlags
, LPCSTR src
, INT srclen
,
1805 LPSTR dst
, INT dstlen
)
1807 INT ret
= 0, srclenW
= 0;
1808 WCHAR
*srcW
= NULL
, *dstW
= NULL
;
1810 if (!src
|| !srclen
|| dstlen
< 0 || (dstlen
&& !dst
) || src
== dst
)
1812 SetLastError(ERROR_INVALID_PARAMETER
);
1816 srclenW
= MultiByteToWideChar(CP_ACP
, dwFlags
& MAP_COMPOSITE
? MB_COMPOSITE
: 0,
1817 src
, srclen
, NULL
, 0);
1818 srcW
= HeapAlloc(GetProcessHeap(), 0, srclenW
* sizeof(WCHAR
));
1822 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1823 goto FoldStringA_exit
;
1826 MultiByteToWideChar(CP_ACP
, dwFlags
& MAP_COMPOSITE
? MB_COMPOSITE
: 0,
1827 src
, srclen
, srcW
, srclenW
);
1829 dwFlags
= (dwFlags
& ~MAP_PRECOMPOSED
) | MAP_FOLDCZONE
;
1831 ret
= FoldStringW(dwFlags
, srcW
, srclenW
, NULL
, 0);
1834 dstW
= HeapAlloc(GetProcessHeap(), 0, ret
* sizeof(WCHAR
));
1838 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1839 goto FoldStringA_exit
;
1842 ret
= FoldStringW(dwFlags
, srcW
, srclenW
, dstW
, ret
);
1843 if (!WideCharToMultiByte(CP_ACP
, 0, dstW
, ret
, dst
, dstlen
, NULL
, NULL
))
1846 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1850 HeapFree(GetProcessHeap(), 0, dstW
);
1853 HeapFree(GetProcessHeap(), 0, srcW
);
1857 /*************************************************************************
1858 * FoldStringW (KERNEL32.@)
1862 INT WINAPI
FoldStringW(DWORD dwFlags
, LPCWSTR src
, INT srclen
,
1863 LPWSTR dst
, INT dstlen
)
1867 switch (dwFlags
& (MAP_COMPOSITE
|MAP_PRECOMPOSED
|MAP_EXPAND_LIGATURES
))
1872 /* Fall through for dwFlags == 0 */
1873 case MAP_PRECOMPOSED
|MAP_COMPOSITE
:
1874 case MAP_PRECOMPOSED
|MAP_EXPAND_LIGATURES
:
1875 case MAP_COMPOSITE
|MAP_EXPAND_LIGATURES
:
1876 SetLastError(ERROR_INVALID_FLAGS
);
1880 if (!src
|| !srclen
|| dstlen
< 0 || (dstlen
&& !dst
) || src
== dst
)
1882 SetLastError(ERROR_INVALID_PARAMETER
);
1886 ret
= wine_fold_string(dwFlags
, src
, srclen
, dst
, dstlen
);
1888 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1894 * @implemented (Synced to Wine-22112008)
1907 WCHAR
*buf1W
= NtCurrentTeb()->StaticUnicodeBuffer
;
1908 WCHAR
*buf2W
= buf1W
+ 130;
1909 LPWSTR str1W
, str2W
;
1910 INT len1W
, len2W
, ret
;
1911 UINT locale_cp
= CP_ACP
;
1913 if (!lpString1
|| !lpString2
)
1915 SetLastError(ERROR_INVALID_PARAMETER
);
1918 if (cchCount1
< 0) cchCount1
= strlen(lpString1
);
1919 if (cchCount2
< 0) cchCount2
= strlen(lpString2
);
1921 if (!(dwCmpFlags
& LOCALE_USE_CP_ACP
)) locale_cp
= get_lcid_codepage(Locale
);
1923 len1W
= MultiByteToWideChar(locale_cp
, 0, lpString1
, cchCount1
, buf1W
, 130);
1928 len1W
= MultiByteToWideChar(locale_cp
, 0, lpString1
, cchCount1
, NULL
, 0);
1929 str1W
= HeapAlloc(GetProcessHeap(), 0, len1W
* sizeof(WCHAR
));
1932 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1935 MultiByteToWideChar(locale_cp
, 0, lpString1
, cchCount1
, str1W
, len1W
);
1937 len2W
= MultiByteToWideChar(locale_cp
, 0, lpString2
, cchCount2
, buf2W
, 130);
1942 len2W
= MultiByteToWideChar(locale_cp
, 0, lpString2
, cchCount2
, NULL
, 0);
1943 str2W
= HeapAlloc(GetProcessHeap(), 0, len2W
* sizeof(WCHAR
));
1946 if (str1W
!= buf1W
) HeapFree(GetProcessHeap(), 0, str1W
);
1947 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1950 MultiByteToWideChar(locale_cp
, 0, lpString2
, cchCount2
, str2W
, len2W
);
1953 ret
= CompareStringW(Locale
, dwCmpFlags
, str1W
, len1W
, str2W
, len2W
);
1955 if (str1W
!= buf1W
) HeapFree(GetProcessHeap(), 0, str1W
);
1956 if (str2W
!= buf2W
) HeapFree(GetProcessHeap(), 0, str2W
);
1961 * @implemented (Synced to Wine-22/11/2008)
1976 if (!lpString1
|| !lpString2
)
1978 SetLastError(ERROR_INVALID_PARAMETER
);
1982 if (dwCmpFlags
& ~(NORM_IGNORECASE
| NORM_IGNORENONSPACE
|
1983 NORM_IGNORESYMBOLS
| SORT_STRINGSORT
| NORM_IGNOREKANATYPE
|
1984 NORM_IGNOREWIDTH
| LOCALE_USE_CP_ACP
| 0x10000000))
1986 SetLastError(ERROR_INVALID_FLAGS
);
1990 /* this style is related to diacritics in Arabic, Japanese, and Hebrew */
1991 if (dwCmpFlags
& 0x10000000)
1992 DPRINT1("Ignoring unknown style 0x10000000\n");
1994 if (cchCount1
< 0) cchCount1
= wcslen(lpString1
);
1995 if (cchCount2
< 0) cchCount2
= wcslen(lpString2
);
1997 Result
= wine_compare_string(dwCmpFlags
, lpString1
, cchCount1
, lpString2
, cchCount2
);
1999 if (Result
) /* need to translate result */
2000 return (Result
< 0) ? CSTR_LESS_THAN
: CSTR_GREATER_THAN
;
2011 * Get information about an aspect of a locale.
2014 * lcid [I] LCID of the locale
2015 * lctype [I] LCTYPE_ flags from "winnls.h"
2016 * buffer [O] Destination for the information
2017 * len [I] Length of buffer in characters
2020 * Success: The size of the data requested. If buffer is non-NULL, it is filled
2021 * with the information.
2022 * Failure: 0. Use GetLastError() to determine the cause.
2025 * - LOCALE_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT
2026 * - The string returned is NUL terminated, except for LOCALE_FONTSIGNATURE,
2027 * which is a bit string.
2029 INT WINAPI
GetLocaleInfoA( LCID lcid
, LCTYPE lctype
, LPSTR buffer
, INT len
)
2034 if (len
< 0 || (len
&& !buffer
))
2036 SetLastError( ERROR_INVALID_PARAMETER
);
2039 if (lctype
& LOCALE_RETURN_GENITIVE_NAMES
)
2041 SetLastError( ERROR_INVALID_FLAGS
);
2045 if (!len
) buffer
= NULL
;
2047 if (!(lenW
= GetLocaleInfoW( lcid
, lctype
, NULL
, 0 ))) return 0;
2049 if (!(bufferW
= HeapAlloc( GetProcessHeap(), 0, lenW
* sizeof(WCHAR
) )))
2051 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
2054 if ((ret
= GetLocaleInfoW( lcid
, lctype
, bufferW
, lenW
)))
2056 if ((lctype
& LOCALE_RETURN_NUMBER
) ||
2057 ((lctype
& ~LOCALE_LOCALEINFOFLAGSMASK
) == LOCALE_FONTSIGNATURE
))
2059 /* it's not an ASCII string, just bytes */
2060 ret
*= sizeof(WCHAR
);
2063 if (ret
<= len
) memcpy( buffer
, bufferW
, ret
);
2066 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
2073 UINT codepage
= CP_ACP
;
2074 if (!(lctype
& LOCALE_USE_CP_ACP
)) codepage
= get_lcid_codepage( lcid
);
2075 ret
= WideCharToMultiByte( codepage
, 0, bufferW
, ret
, buffer
, len
, NULL
, NULL
);
2078 HeapFree( GetProcessHeap(), 0, bufferW
);
2087 GetSystemDefaultLangID(VOID
)
2089 return LANGIDFROMLCID(GetSystemDefaultLCID());
2097 GetSystemDefaultLCID(VOID
)
2101 NtQueryDefaultLocale(FALSE
, &lcid
);
2111 GetSystemDefaultUILanguage(VOID
)
2116 Status
= NtQueryInstallUILanguage(&LanguageId
);
2117 if (!NT_SUCCESS(Status
))
2119 SetLastErrorByStatus(Status
);
2131 GetThreadLocale(VOID
)
2133 return NtCurrentTeb()->CurrentLocale
;
2141 GetUserDefaultLangID(VOID
)
2143 return LANGIDFROMLCID(GetUserDefaultLCID());
2151 GetUserDefaultLCID(VOID
)
2156 Status
= NtQueryDefaultLocale(TRUE
, &lcid
);
2157 if (!NT_SUCCESS(Status
))
2159 SetLastErrorByStatus(Status
);
2171 GetUserDefaultUILanguage(VOID
)
2176 Status
= NtQueryDefaultUILanguage(&LangId
);
2177 if (!NT_SUCCESS(Status
))
2179 SetLastErrorByStatus(Status
);
2195 GEOID ret
= GEOID_NOT_AVAILABLE
;
2196 static const WCHAR geoW
[] = {'G','e','o',0};
2197 static const WCHAR nationW
[] = {'N','a','t','i','o','n',0};
2198 WCHAR bufferW
[40], *end
;
2200 HANDLE hkey
, hSubkey
= 0;
2201 UNICODE_STRING keyW
;
2202 const KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)bufferW
;
2203 RtlInitUnicodeString( &keyW
, nationW
);
2204 count
= sizeof(bufferW
);
2206 if(!(hkey
= create_registry_key())) return ret
;
2209 case GEOCLASS_NATION
:
2210 if ((hSubkey
= NLS_RegOpenKey(hkey
, geoW
)))
2212 if((NtQueryValueKey(hSubkey
, &keyW
, KeyValuePartialInformation
,
2213 (LPBYTE
)bufferW
, count
, &count
) == STATUS_SUCCESS
) && info
->DataLength
)
2214 ret
= wcstol((LPCWSTR
)info
->Data
, &end
, 10);
2217 case GEOCLASS_REGION
:
2218 DPRINT("GEOCLASS_REGION not handled yet\n");
2223 if (hSubkey
) NtClose(hSubkey
);
2228 /******************************************************************************
2229 * IsValidLanguageGroup
2231 * Determine if a language group is supported and/or installed.
2234 * LanguageGroup [I] Language Group Id (LGRPID_ values from "winnls.h")
2235 * dwFlags [I] LGRPID_SUPPORTED=Supported, LGRPID_INSTALLED=Installed
2238 * TRUE, if lgrpid is supported and/or installed, according to dwFlags.
2245 IsValidLanguageGroup(
2246 LGRPID LanguageGroup
,
2249 static const WCHAR szFormat
[] = { '%','x','\0' };
2250 WCHAR szValueName
[16], szValue
[2];
2251 BOOL bSupported
= FALSE
, bInstalled
= FALSE
;
2257 case LGRPID_INSTALLED
:
2258 case LGRPID_SUPPORTED
:
2260 hKey
= NLS_RegOpenKey( 0, szLangGroupsKeyName
);
2264 swprintf( szValueName
, szFormat
, LanguageGroup
);
2266 if (NLS_RegGetDword( hKey
, szValueName
, (LPDWORD
)szValue
))
2270 if (szValue
[0] == '1')
2279 DPRINT("Invalid flags: %lx\n", dwFlags
);
2283 if ((dwFlags
== LGRPID_SUPPORTED
&& bSupported
) ||
2284 (dwFlags
== LGRPID_INSTALLED
&& bInstalled
))
2291 /******************************************************************************
2294 * Determine if a locale is valid.
2297 * Locale [I] LCID of the locale to check
2298 * dwFlags [I] LCID_SUPPORTED = Valid
2299 * LCID_INSTALLED = Valid and installed on the system
2302 * TRUE, if Locale is valid,
2308 IsValidLocale(LCID Locale
,
2311 OBJECT_ATTRIBUTES ObjectAttributes
;
2312 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo
;
2313 WCHAR ValueNameBuffer
[9];
2314 UNICODE_STRING KeyName
;
2315 UNICODE_STRING ValueName
;
2321 BOOL Installed
= FALSE
;
2323 DPRINT("IsValidLocale() called\n");
2325 if ((dwFlags
& ~(LCID_SUPPORTED
| LCID_INSTALLED
)) ||
2326 (dwFlags
== (LCID_SUPPORTED
| LCID_INSTALLED
)))
2328 DPRINT("Invalid flags: %lx\n", dwFlags
);
2332 if (Locale
& 0xFFFF0000)
2334 RtlInitUnicodeString(&KeyName
,
2335 L
"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Nls\\Locale\\Alternate Sorts");
2339 RtlInitUnicodeString(&KeyName
,
2340 L
"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Nls\\Locale");
2343 InitializeObjectAttributes(&ObjectAttributes
,
2345 OBJ_CASE_INSENSITIVE
,
2349 Status
= NtOpenKey(&KeyHandle
,
2352 if (!NT_SUCCESS(Status
))
2354 DPRINT("NtOpenKey() failed (Status %lx)\n", Status
);
2355 SetLastError(ERROR_BADDB
);
2359 swprintf(ValueNameBuffer
, L
"%08lx", (ULONG
)Locale
);
2360 RtlInitUnicodeString(&ValueName
, ValueNameBuffer
);
2362 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4 * sizeof(WCHAR
);
2363 KeyInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
2366 if (KeyInfo
== NULL
)
2368 DPRINT("RtlAllocateHeap() failed (Status %lx)\n", Status
);
2373 Status
= NtQueryValueKey(KeyHandle
,
2375 KeyValuePartialInformation
,
2381 if (!NT_SUCCESS(Status
))
2383 DPRINT("NtQueryValueKey() failed (Status %lx)\n", Status
);
2384 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo
);
2388 if (dwFlags
& LCID_SUPPORTED
)
2390 DPRINT("Locale is supported\n");
2391 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo
);
2395 ValueData
= (PWSTR
)&KeyInfo
->Data
[0];
2396 if ((KeyInfo
->Type
== REG_SZ
) &&
2397 (KeyInfo
->DataLength
== 2 * sizeof(WCHAR
)))
2399 /* Find out if there is support for the language group
2400 * installed, to which this language belongs */
2401 KeyHandle
= NLS_RegOpenKey(0, szLangGroupsKeyName
);
2405 if (NLS_RegGetDword(KeyHandle
, ValueData
, (LPDWORD
) Value
) &&
2409 DPRINT("Locale is supported and installed\n");
2416 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo
);
2418 DPRINT("IsValidLocale() called\n");
2437 WCHAR
*bufW
= NtCurrentTeb()->StaticUnicodeBuffer
;
2439 INT ret
= 0, srclenW
, dstlenW
;
2440 UINT locale_cp
= CP_ACP
;
2442 if (!lpSrcStr
|| !cchSrc
|| cchDest
< 0)
2444 SetLastError(ERROR_INVALID_PARAMETER
);
2448 if (!(dwMapFlags
& LOCALE_USE_CP_ACP
)) locale_cp
= get_lcid_codepage(Locale
);
2450 srclenW
= MultiByteToWideChar(locale_cp
, 0, lpSrcStr
, cchSrc
, bufW
, 260);
2455 srclenW
= MultiByteToWideChar(locale_cp
, 0, lpSrcStr
, cchSrc
, NULL
, 0);
2456 srcW
= HeapAlloc(GetProcessHeap(), 0, srclenW
* sizeof(WCHAR
));
2459 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2462 MultiByteToWideChar(locale_cp
, 0, lpSrcStr
, cchSrc
, srcW
, srclenW
);
2465 if (dwMapFlags
& LCMAP_SORTKEY
)
2467 if (lpSrcStr
== lpDestStr
)
2469 SetLastError(ERROR_INVALID_FLAGS
);
2470 goto map_string_exit
;
2472 ret
= wine_get_sortkey(dwMapFlags
, srcW
, srclenW
, lpDestStr
, cchDest
);
2474 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2477 goto map_string_exit
;
2480 if (dwMapFlags
& SORT_STRINGSORT
)
2482 SetLastError(ERROR_INVALID_FLAGS
);
2483 goto map_string_exit
;
2486 dstlenW
= LCMapStringW(Locale
, dwMapFlags
, srcW
, srclenW
, NULL
, 0);
2488 goto map_string_exit
;
2490 dstW
= HeapAlloc(GetProcessHeap(), 0, dstlenW
* sizeof(WCHAR
));
2493 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2494 goto map_string_exit
;
2497 LCMapStringW(Locale
, dwMapFlags
, srcW
, srclenW
, dstW
, dstlenW
);
2498 ret
= WideCharToMultiByte(locale_cp
, 0, dstW
, dstlenW
, lpDestStr
, cchDest
, NULL
, NULL
);
2499 HeapFree(GetProcessHeap(), 0, dstW
);
2502 if (srcW
!= bufW
) HeapFree(GetProcessHeap(), 0, srcW
);
2523 if (!lpSrcStr
|| !cchSrc
|| cchDest
< 0)
2525 SetLastError(ERROR_INVALID_PARAMETER
);
2529 /* mutually exclusive flags */
2530 if ((dwMapFlags
& (LCMAP_LOWERCASE
| LCMAP_UPPERCASE
)) == (LCMAP_LOWERCASE
| LCMAP_UPPERCASE
) ||
2531 (dwMapFlags
& (LCMAP_HIRAGANA
| LCMAP_KATAKANA
)) == (LCMAP_HIRAGANA
| LCMAP_KATAKANA
) ||
2532 (dwMapFlags
& (LCMAP_HALFWIDTH
| LCMAP_FULLWIDTH
)) == (LCMAP_HALFWIDTH
| LCMAP_FULLWIDTH
) ||
2533 (dwMapFlags
& (LCMAP_TRADITIONAL_CHINESE
| LCMAP_SIMPLIFIED_CHINESE
)) == (LCMAP_TRADITIONAL_CHINESE
| LCMAP_SIMPLIFIED_CHINESE
))
2535 SetLastError(ERROR_INVALID_FLAGS
);
2539 if (!cchDest
) lpDestStr
= NULL
;
2541 Locale
= ConvertDefaultLocale(Locale
);
2543 if (dwMapFlags
& LCMAP_SORTKEY
)
2546 if (lpSrcStr
== lpDestStr
)
2548 SetLastError(ERROR_INVALID_FLAGS
);
2552 if (cchSrc
< 0) cchSrc
= wcslen(lpSrcStr
);
2554 ret
= wine_get_sortkey(dwMapFlags
, lpSrcStr
, cchSrc
, (char *)lpDestStr
, cchDest
);
2556 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2560 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
2561 if (dwMapFlags
& SORT_STRINGSORT
)
2563 SetLastError(ERROR_INVALID_FLAGS
);
2567 if (cchSrc
< 0) cchSrc
= wcslen(lpSrcStr
) + 1;
2569 if (!lpDestStr
) /* return required string length */
2573 for (len
= 0; cchSrc
; lpSrcStr
++, cchSrc
--)
2575 WCHAR wch
= *lpSrcStr
;
2576 /* tests show that win2k just ignores NORM_IGNORENONSPACE,
2577 * and skips white space and punctuation characters for
2578 * NORM_IGNORESYMBOLS.
2580 if ((dwMapFlags
& NORM_IGNORESYMBOLS
) && (iswctype(wch
, _SPACE
| _PUNCT
)))
2587 if (dwMapFlags
& LCMAP_UPPERCASE
)
2589 for (dst_ptr
= lpDestStr
; cchSrc
&& cchDest
; lpSrcStr
++, cchSrc
--)
2591 WCHAR wch
= *lpSrcStr
;
2592 if ((dwMapFlags
& NORM_IGNORESYMBOLS
) && (iswctype(wch
, _SPACE
| _PUNCT
)))
2594 *dst_ptr
++ = towupper(wch
);
2598 else if (dwMapFlags
& LCMAP_LOWERCASE
)
2600 for (dst_ptr
= lpDestStr
; cchSrc
&& cchDest
; lpSrcStr
++, cchSrc
--)
2602 WCHAR wch
= *lpSrcStr
;
2603 if ((dwMapFlags
& NORM_IGNORESYMBOLS
) && (iswctype(wch
, _SPACE
| _PUNCT
)))
2605 *dst_ptr
++ = towlower(wch
);
2611 if (lpSrcStr
== lpDestStr
)
2613 SetLastError(ERROR_INVALID_FLAGS
);
2616 for (dst_ptr
= lpDestStr
; cchSrc
&& cchDest
; lpSrcStr
++, cchSrc
--)
2618 WCHAR wch
= *lpSrcStr
;
2619 if ((dwMapFlags
& NORM_IGNORESYMBOLS
) && (iswctype(wch
, _SPACE
| _PUNCT
)))
2628 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2632 return dst_ptr
- lpDestStr
;
2647 if (!Locale
|| !lpCalData
)
2649 SetLastError(ERROR_INVALID_PARAMETER
);
2655 case CAL_NOUSEROVERRIDE
:
2656 case CAL_RETURN_NUMBER
:
2657 case CAL_USE_CP_ACP
:
2660 SetLastError(ERROR_INVALID_FLAGS
);
2664 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2679 if (!Locale
|| !lpCalData
)
2681 SetLastError(ERROR_INVALID_PARAMETER
);
2687 case CAL_NOUSEROVERRIDE
:
2688 case CAL_RETURN_NUMBER
:
2689 case CAL_USE_CP_ACP
:
2692 SetLastError(ERROR_INVALID_FLAGS
);
2696 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2701 /**********************************************************************
2703 * RIPPED FROM WINE's dlls\kernel\locale.c ver 0.9.29
2705 * SetLocaleInfoA (KERNEL32.@)
2707 * Set the current locale info.
2710 * Locale [I] LCID of the locale
2711 * LCType [I] LCTYPE_ flags from "winnls.h"
2712 * lpLCData [I] Information to set
2715 * Success: TRUE. The information given will be returned by GetLocaleInfoA()
2716 * whenever it is called without LOCALE_NOUSEROVERRIDE.
2717 * Failure: FALSE. Use GetLastError() to determine the cause.
2727 UINT codepage
= CP_ACP
;
2732 if (!(LCType
& LOCALE_USE_CP_ACP
)) codepage
= get_lcid_codepage( Locale
);
2736 SetLastError( ERROR_INVALID_PARAMETER
);
2739 len
= MultiByteToWideChar( codepage
, 0, lpLCData
, -1, NULL
, 0 );
2740 if (!(strW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
2742 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
2745 MultiByteToWideChar( codepage
, 0, lpLCData
, -1, strW
, len
);
2746 ret
= SetLocaleInfoW( Locale
, LCType
, strW
);
2747 HeapFree( GetProcessHeap(), 0, strW
);
2752 /**********************************************************************
2754 * RIPPED FROM WINE's dlls\kernel\locale.c ver 0.9.29
2756 * SetLocaleInfoW (KERNEL32.@)
2758 * See SetLocaleInfoA.
2770 UNICODE_STRING valueW
;
2775 value
= RosGetLocaleValueName( LCType
);
2777 if (!lpLCData
|| !value
)
2779 SetLastError( ERROR_INVALID_PARAMETER
);
2783 if (LCType
== LOCALE_IDATE
|| LCType
== LOCALE_ILDATE
)
2785 SetLastError( ERROR_INVALID_FLAGS
);
2789 if (!(hkey
= RosCreateRegistryKey())) return FALSE
;
2790 RtlInitUnicodeString( &valueW
, value
);
2791 status
= NtSetValueKey( hkey
, &valueW
, 0, REG_SZ
, (PVOID
)lpLCData
, (lstrlenW(lpLCData
)+1)*sizeof(WCHAR
) );
2793 if (LCType
== LOCALE_SSHORTDATE
|| LCType
== LOCALE_SLONGDATE
)
2795 /* Set I-value from S value */
2796 WCHAR
*lpD
, *lpM
, *lpY
;
2799 lpD
= wcschr(lpLCData
, 'd');
2800 lpM
= wcschr(lpLCData
, 'M');
2801 lpY
= wcschr(lpLCData
, 'y');
2805 szBuff
[0] = '1'; /* D-M-Y */
2810 szBuff
[0] = '2'; /* Y-M-D */
2812 szBuff
[0] = '0'; /* M-D-Y */
2817 if (LCType
== LOCALE_SSHORTDATE
)
2818 LCType
= LOCALE_IDATE
;
2820 LCType
= LOCALE_ILDATE
;
2822 value
= RosGetLocaleValueName( LCType
);
2824 RtlInitUnicodeString( &valueW
, value
);
2825 status
= NtSetValueKey( hkey
, &valueW
, 0, REG_SZ
, szBuff
, sizeof(szBuff
) );
2830 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
2835 /**********************************************************************
2837 * RIPPED FROM WINE's dlls\kernel\locale.c rev 1.42
2839 * SetThreadLocale (KERNEL32.@)
2841 * Set the current threads locale.
2844 * lcid [I] LCID of the locale to set
2847 * Success: TRUE. The threads locale is set to lcid.
2848 * Failure: FALSE. Use GetLastError() to determine the cause.
2851 BOOL WINAPI
SetThreadLocale( LCID lcid
)
2853 DPRINT("SetThreadLocale(0x%04lX)\n", lcid
);
2855 lcid
= ConvertDefaultLocale(lcid
);
2857 if (lcid
!= GetThreadLocale())
2859 if (!IsValidLocale(lcid
, LCID_SUPPORTED
))
2861 SetLastError(ERROR_INVALID_PARAMETER
);
2865 NtCurrentTeb()->CurrentLocale
= lcid
;
2866 /* FIXME: NtCurrentTeb()->code_page = get_lcid_codepage( lcid );
2867 * Wine save the acp for easy/fast access, but ROS has no such Teb member.
2868 * Maybe add this member to ros as well?
2872 Lag test app for å se om locale etc, endres i en app. etter at prosessen er
2873 startet, eller om bare nye prosesser blir berørt.
2884 SetUserDefaultLCID(LCID lcid
)
2888 Status
= NtSetDefaultLocale(TRUE
, lcid
);
2889 if (!NT_SUCCESS(Status
))
2891 SetLastErrorByStatus(Status
);
2902 SetUserDefaultUILanguage(LANGID LangId
)
2906 Status
= NtSetDefaultUILanguage(LangId
);
2907 if (!NT_SUCCESS(Status
))
2909 SetLastErrorByStatus(Status
);
2924 static const WCHAR geoW
[] = {'G','e','o',0};
2925 static const WCHAR nationW
[] = {'N','a','t','i','o','n',0};
2926 static const WCHAR formatW
[] = {'%','i',0};
2927 UNICODE_STRING nameW
,keyW
;
2929 OBJECT_ATTRIBUTES attr
;
2932 if(!(hkey
= create_registry_key())) return FALSE
;
2934 attr
.Length
= sizeof(attr
);
2935 attr
.RootDirectory
= hkey
;
2936 attr
.ObjectName
= &nameW
;
2937 attr
.Attributes
= 0;
2938 attr
.SecurityDescriptor
= NULL
;
2939 attr
.SecurityQualityOfService
= NULL
;
2940 RtlInitUnicodeString( &nameW
, geoW
);
2941 RtlInitUnicodeString( &keyW
, nationW
);
2943 if (NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
)
2946 NtClose(attr
.RootDirectory
);
2950 swprintf(bufferW
, formatW
, GeoId
);
2951 NtSetValueKey(hkey
, &keyW
, 0, REG_SZ
, bufferW
, (wcslen(bufferW
) + 1) * sizeof(WCHAR
));
2952 NtClose(attr
.RootDirectory
);
2969 return GetLocaleInfoA( MAKELCID(wLang
, SORT_DEFAULT
), LOCALE_SENGLANGUAGE
, szLang
, nSize
);
2984 return GetLocaleInfoW( MAKELCID(wLang
, SORT_DEFAULT
), LOCALE_SENGLANGUAGE
, szLang
, nSize
);
2987 /***********************************************************************
2988 * LCIDToLocaleName (KERNEL32.@) Wine 13.02.2009
2990 INT WINAPI
LCIDToLocaleName( LCID lcid
, LPWSTR name
, INT count
, DWORD flags
)
2992 if (flags
) DPRINT1( "unsupported flags %x\n", flags
);
2994 return GetLocaleInfoW( lcid
, LOCALE_SNAME
| LOCALE_NOUSEROVERRIDE
, name
, count
);