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|LOCALE_RETURN_NUMBER)
32 #define CALINFO_MAX_YEAR 2029
34 //static LCID SystemLocale = MAKELCID(LANG_ENGLISH, SORT_DEFAULT);
36 //static RTL_CRITICAL_SECTION LocalesListLock;
38 extern int wine_fold_string(int flags
, const WCHAR
*src
, int srclen
, WCHAR
*dst
, int dstlen
);
39 extern int wine_get_sortkey(int flags
, const WCHAR
*src
, int srclen
, char *dst
, int dstlen
);
40 extern int wine_compare_string(int flags
, const WCHAR
*str1
, int len1
, const WCHAR
*str2
, int len2
);
46 UILANGUAGE_ENUMPROCA procA
;
47 UILANGUAGE_ENUMPROCW procW
;
51 } ENUM_UILANG_CALLBACK
;
53 static const WCHAR szLocaleKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NLS\\Locale";
54 static const WCHAR szLangGroupsKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NLS\\Language Groups";
56 /******************************************************************************
58 * RIPPED FROM WINE's dlls\kernel\locale.c rev 1.42
60 * ConvertDefaultLocale (KERNEL32.@)
62 * Convert a default locale identifier into a real identifier.
65 * lcid [I] LCID identifier of the locale to convert
68 * lcid unchanged, if not a default locale or its sublanguage is
69 * not SUBLANG_NEUTRAL.
70 * GetSystemDefaultLCID(), if lcid == LOCALE_SYSTEM_DEFAULT.
71 * GetUserDefaultLCID(), if lcid == LOCALE_USER_DEFAULT or LOCALE_NEUTRAL.
72 * Otherwise, lcid with sublanguage changed to SUBLANG_DEFAULT.
75 ConvertDefaultLocale(LCID lcid
)
81 case LOCALE_SYSTEM_DEFAULT
:
82 lcid
= GetSystemDefaultLCID();
85 case LOCALE_USER_DEFAULT
:
87 lcid
= GetUserDefaultLCID();
91 /* Replace SUBLANG_NEUTRAL with SUBLANG_DEFAULT */
92 langid
= LANGIDFROMLCID(lcid
);
93 if (SUBLANGID(langid
) == SUBLANG_NEUTRAL
)
95 langid
= MAKELANGID(PRIMARYLANGID(langid
), SUBLANG_DEFAULT
);
96 lcid
= MAKELCID(langid
, SORTIDFROMLCID(lcid
));
104 /**************************************************************************
105 * EnumDateFormatsExA (KERNEL32.@)
107 * FIXME: MSDN mentions only LOCALE_USE_CP_ACP, should we handle
108 * LOCALE_NOUSEROVERRIDE here as well?
113 DATEFMT_ENUMPROCEXA lpDateFmtEnumProcEx
,
120 if (!lpDateFmtEnumProcEx
)
122 SetLastError(ERROR_INVALID_PARAMETER
);
126 if (!GetLocaleInfoW(Locale
,
127 LOCALE_ICALENDARTYPE
|LOCALE_RETURN_NUMBER
,
129 sizeof(cal_id
)/sizeof(WCHAR
)))
134 switch (dwFlags
& ~LOCALE_USE_CP_ACP
)
138 if (GetLocaleInfoA(Locale
,
139 LOCALE_SSHORTDATE
| (dwFlags
& LOCALE_USE_CP_ACP
),
142 lpDateFmtEnumProcEx(szBuf
, cal_id
);
147 if (GetLocaleInfoA(Locale
,
148 LOCALE_SLONGDATE
| (dwFlags
& LOCALE_USE_CP_ACP
),
151 lpDateFmtEnumProcEx(szBuf
, cal_id
);
156 if (GetLocaleInfoA(Locale
,
157 LOCALE_SYEARMONTH
| (dwFlags
& LOCALE_USE_CP_ACP
),
160 lpDateFmtEnumProcEx(szBuf
, cal_id
);
165 // FIXME: Unknown date format
166 SetLastError(ERROR_INVALID_PARAMETER
);
173 /**************************************************************************
174 * EnumDateFormatsExW (KERNEL32.@)
179 DATEFMT_ENUMPROCEXW lpDateFmtEnumProcEx
,
184 WCHAR wbuf
[256]; // FIXME
186 if (!lpDateFmtEnumProcEx
)
188 SetLastError(ERROR_INVALID_PARAMETER
);
192 if (!GetLocaleInfoW(Locale
,
193 LOCALE_ICALENDARTYPE
| LOCALE_RETURN_NUMBER
,
195 sizeof(cal_id
)/sizeof(WCHAR
)))
200 switch (dwFlags
& ~LOCALE_USE_CP_ACP
)
204 if (GetLocaleInfoW(Locale
,
205 LOCALE_SSHORTDATE
| (dwFlags
& LOCALE_USE_CP_ACP
),
209 lpDateFmtEnumProcEx(wbuf
, cal_id
);
214 if (GetLocaleInfoW(Locale
,
215 LOCALE_SLONGDATE
| (dwFlags
& LOCALE_USE_CP_ACP
),
219 lpDateFmtEnumProcEx(wbuf
, cal_id
);
224 if (GetLocaleInfoW(Locale
,
225 LOCALE_SYEARMONTH
| (dwFlags
& LOCALE_USE_CP_ACP
),
229 lpDateFmtEnumProcEx(wbuf
, cal_id
);
234 // FIXME: Unknown date format
235 SetLastError(ERROR_INVALID_PARAMETER
);
242 static BOOL
NLS_RegEnumValue(HANDLE hKey
, UINT ulIndex
,
243 LPWSTR szValueName
, ULONG valueNameSize
,
244 LPWSTR szValueData
, ULONG valueDataSize
)
247 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
250 if (NtEnumerateValueKey( hKey
, ulIndex
, KeyValueFullInformation
,
251 buffer
, sizeof(buffer
), &dwLen
) != STATUS_SUCCESS
||
252 info
->NameLength
> valueNameSize
||
253 info
->DataLength
> valueDataSize
)
258 DPRINT("info->Name %s info->DataLength %d\n", info
->Name
, info
->DataLength
);
260 memcpy( szValueName
, info
->Name
, info
->NameLength
);
261 szValueName
[info
->NameLength
/ sizeof(WCHAR
)] = '\0';
262 memcpy( szValueData
, buffer
+ info
->DataOffset
, info
->DataLength
);
263 szValueData
[info
->DataLength
/ sizeof(WCHAR
)] = '\0';
265 DPRINT("returning %s %s\n", szValueName
, szValueData
);
270 static HANDLE
NLS_RegOpenKey(HANDLE hRootKey
, LPCWSTR szKeyName
)
272 UNICODE_STRING keyName
;
273 OBJECT_ATTRIBUTES attr
;
276 RtlInitUnicodeString( &keyName
, szKeyName
);
277 InitializeObjectAttributes(&attr
, &keyName
, OBJ_CASE_INSENSITIVE
, hRootKey
, NULL
);
279 if (NtOpenKey( &hkey
, KEY_ALL_ACCESS
, &attr
) != STATUS_SUCCESS
)
285 static BOOL
NLS_RegEnumSubKey(HANDLE hKey
, UINT ulIndex
, LPWSTR szKeyName
,
289 KEY_BASIC_INFORMATION
*info
= (KEY_BASIC_INFORMATION
*)buffer
;
292 if (NtEnumerateKey( hKey
, ulIndex
, KeyBasicInformation
, buffer
,
293 sizeof(buffer
), &dwLen
) != STATUS_SUCCESS
||
294 info
->NameLength
> keyNameSize
)
299 DPRINT("info->Name %s info->NameLength %d\n", info
->Name
, info
->NameLength
);
301 memcpy( szKeyName
, info
->Name
, info
->NameLength
);
302 szKeyName
[info
->NameLength
/ sizeof(WCHAR
)] = '\0';
304 DPRINT("returning %s\n", szKeyName
);
308 static BOOL
NLS_RegGetDword(HANDLE hKey
, LPCWSTR szValueName
, DWORD
*lpVal
)
311 const KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
312 DWORD dwSize
= sizeof(buffer
);
313 UNICODE_STRING valueName
;
315 RtlInitUnicodeString( &valueName
, szValueName
);
317 DPRINT("%p, %s\n", hKey
, szValueName
);
318 if (NtQueryValueKey( hKey
, &valueName
, KeyValuePartialInformation
,
319 buffer
, dwSize
, &dwSize
) == STATUS_SUCCESS
&&
320 info
->DataLength
== sizeof(DWORD
))
322 memcpy(lpVal
, info
->Data
, sizeof(DWORD
));
329 static BOOL
NLS_GetLanguageGroupName(LGRPID lgrpid
, LPWSTR szName
, ULONG nameSize
)
332 LPCWSTR szResourceName
= MAKEINTRESOURCEW(((lgrpid
+ 0x2000) >> 4) + 1);
336 /* FIXME: Is it correct to use the system default langid? */
337 langId
= GetSystemDefaultLangID();
339 if (SUBLANGID(langId
) == SUBLANG_NEUTRAL
)
340 langId
= MAKELANGID( PRIMARYLANGID(langId
), SUBLANG_DEFAULT
);
342 hResource
= FindResourceExW( hCurrentModule
, (LPWSTR
)RT_STRING
, szResourceName
, langId
);
346 HGLOBAL hResDir
= LoadResource( hCurrentModule
, hResource
);
350 ULONG iResourceIndex
= lgrpid
& 0xf;
351 LPCWSTR lpResEntry
= LockResource( hResDir
);
354 for (i
= 0; i
< iResourceIndex
; i
++)
355 lpResEntry
+= *lpResEntry
+ 1;
357 if (*lpResEntry
< nameSize
)
359 memcpy( szName
, lpResEntry
+ 1, *lpResEntry
* sizeof(WCHAR
) );
360 szName
[*lpResEntry
] = '\0';
365 FreeResource( hResource
);
367 else DPRINT1("FindResourceExW() failed\n");
373 /* Callback function ptrs for EnumLanguageGrouplocalesA/W */
376 LANGGROUPLOCALE_ENUMPROCA procA
;
377 LANGGROUPLOCALE_ENUMPROCW procW
;
381 } ENUMLANGUAGEGROUPLOCALE_CALLBACKS
;
383 /* Internal implementation of EnumLanguageGrouplocalesA/W */
384 static BOOL
NLS_EnumLanguageGroupLocales(ENUMLANGUAGEGROUPLOCALE_CALLBACKS
*lpProcs
)
386 static const WCHAR szAlternateSortsKeyName
[] = {
387 'A','l','t','e','r','n','a','t','e',' ','S','o','r','t','s','\0'
389 WCHAR szNumber
[10], szValue
[4];
391 BOOL bContinue
= TRUE
, bAlternate
= FALSE
;
393 ULONG ulIndex
= 1; /* Ignore default entry of 1st key */
395 if (!lpProcs
|| !lpProcs
->lgrpid
|| lpProcs
->lgrpid
> LGRPID_ARMENIAN
)
397 SetLastError(ERROR_INVALID_PARAMETER
);
401 if (lpProcs
->dwFlags
)
403 SetLastError(ERROR_INVALID_FLAGS
);
407 hKey
= NLS_RegOpenKey( 0, szLocaleKeyName
);
411 DPRINT1("NLS_RegOpenKey() failed\n");
417 if (NLS_RegEnumValue( hKey
, ulIndex
, szNumber
, sizeof(szNumber
),
418 szValue
, sizeof(szValue
) ))
420 lgrpid
= wcstoul( szValue
, NULL
, 16 );
422 DPRINT("lcid %s, grpid %d (%smatched)\n", szNumber
,
423 lgrpid
, lgrpid
== lpProcs
->lgrpid
? "" : "not ");
425 if (lgrpid
== lpProcs
->lgrpid
)
429 lcid
= wcstoul( szNumber
, NULL
, 16 );
431 /* FIXME: native returns extra text for a few (17/150) locales, e.g:
432 * '00000437 ;Georgian'
433 * At present we only pass the LCID string.
437 bContinue
= lpProcs
->procW( lgrpid
, lcid
, szNumber
, lpProcs
->lParam
);
440 char szNumberA
[sizeof(szNumber
)/sizeof(WCHAR
)];
442 WideCharToMultiByte(CP_ACP
, 0, szNumber
, -1, szNumberA
, sizeof(szNumberA
), 0, 0);
444 bContinue
= lpProcs
->procA( lgrpid
, lcid
, szNumberA
, lpProcs
->lParam
);
452 /* Finished enumerating this key */
455 /* Enumerate alternate sorts also */
456 hKey
= NLS_RegOpenKey( hKey
, szAlternateSortsKeyName
);
461 bContinue
= FALSE
; /* Finished both keys */
480 EnumLanguageGroupLocalesA(
481 LANGGROUPLOCALE_ENUMPROCA lpLangGroupLocaleEnumProc
,
482 LGRPID LanguageGroup
,
486 ENUMLANGUAGEGROUPLOCALE_CALLBACKS callbacks
;
488 DPRINT("(%p,0x%08X,0x%08X,0x%08lX)\n", lpLangGroupLocaleEnumProc
, LanguageGroup
, dwFlags
, lParam
);
490 callbacks
.procA
= lpLangGroupLocaleEnumProc
;
491 callbacks
.procW
= NULL
;
492 callbacks
.dwFlags
= dwFlags
;
493 callbacks
.lgrpid
= LanguageGroup
;
494 callbacks
.lParam
= lParam
;
496 return NLS_EnumLanguageGroupLocales( lpLangGroupLocaleEnumProc
? &callbacks
: NULL
);
505 EnumLanguageGroupLocalesW(
506 LANGGROUPLOCALE_ENUMPROCW lpLangGroupLocaleEnumProc
,
507 LGRPID LanguageGroup
,
511 ENUMLANGUAGEGROUPLOCALE_CALLBACKS callbacks
;
513 DPRINT("(%p,0x%08X,0x%08X,0x%08lX)\n", lpLangGroupLocaleEnumProc
, LanguageGroup
, dwFlags
, lParam
);
515 callbacks
.procA
= NULL
;
516 callbacks
.procW
= lpLangGroupLocaleEnumProc
;
517 callbacks
.dwFlags
= dwFlags
;
518 callbacks
.lgrpid
= LanguageGroup
;
519 callbacks
.lParam
= lParam
;
521 return NLS_EnumLanguageGroupLocales( lpLangGroupLocaleEnumProc
? &callbacks
: NULL
);
525 /* Callback function ptrs for EnumSystemCodePagesA/W */
528 CODEPAGE_ENUMPROCA procA
;
529 CODEPAGE_ENUMPROCW procW
;
531 } ENUMSYSTEMCODEPAGES_CALLBACKS
;
533 /* Internal implementation of EnumSystemCodePagesA/W */
534 static BOOL
NLS_EnumSystemCodePages(ENUMSYSTEMCODEPAGES_CALLBACKS
*lpProcs
)
536 WCHAR szNumber
[5 + 1], szValue
[MAX_PATH
];
538 BOOL bContinue
= TRUE
;
543 SetLastError(ERROR_INVALID_PARAMETER
);
547 switch (lpProcs
->dwFlags
)
553 SetLastError(ERROR_INVALID_FLAGS
);
557 hKey
= NLS_RegOpenKey(0, L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage");
560 DPRINT1("NLS_RegOpenKey() failed\n");
566 if (NLS_RegEnumValue(hKey
, ulIndex
, szNumber
, sizeof(szNumber
),
567 szValue
, sizeof(szValue
)))
569 if ((lpProcs
->dwFlags
== CP_SUPPORTED
)||
570 ((lpProcs
->dwFlags
== CP_INSTALLED
)&&(wcslen(szValue
) > 2)))
574 bContinue
= lpProcs
->procW(szNumber
);
578 char szNumberA
[sizeof(szNumber
)/sizeof(WCHAR
)];
580 WideCharToMultiByte(CP_ACP
, 0, szNumber
, -1, szNumberA
, sizeof(szNumberA
), 0, 0);
581 bContinue
= lpProcs
->procA(szNumberA
);
587 } else bContinue
= FALSE
;
604 EnumSystemCodePagesW (
605 CODEPAGE_ENUMPROCW lpCodePageEnumProc
,
609 ENUMSYSTEMCODEPAGES_CALLBACKS procs
;
611 DPRINT("(%p,0x%08X,0x%08lX)\n", lpCodePageEnumProc
, dwFlags
);
614 procs
.procW
= lpCodePageEnumProc
;
615 procs
.dwFlags
= dwFlags
;
617 return NLS_EnumSystemCodePages(lpCodePageEnumProc
? &procs
: NULL
);
626 EnumSystemCodePagesA (
627 CODEPAGE_ENUMPROCA lpCodePageEnumProc
,
631 ENUMSYSTEMCODEPAGES_CALLBACKS procs
;
633 DPRINT("(%p,0x%08X,0x%08lX)\n", lpCodePageEnumProc
, dwFlags
);
635 procs
.procA
= lpCodePageEnumProc
;
637 procs
.dwFlags
= dwFlags
;
639 return NLS_EnumSystemCodePages(lpCodePageEnumProc
? &procs
: NULL
);
650 GEOID ParentGeoId
, // reserved
651 GEO_ENUMPROC lpGeoEnumProc
)
653 WCHAR szNumber
[5 + 1];
657 DPRINT("(0x%08X,0x%08X,%p)\n", GeoClass
, ParentGeoId
, lpGeoEnumProc
);
659 if(!lpGeoEnumProc
|| GeoClass
!= GEOCLASS_NATION
)
661 SetLastError(ERROR_INVALID_PARAMETER
);
665 hKey
= NLS_RegOpenKey(0, L
"\\REGISTRY\\Machine\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Country List");
668 DPRINT1("NLS_RegOpenKey() failed\n");
672 while (NLS_RegEnumSubKey(hKey
, ulIndex
, szNumber
, sizeof(szNumber
)))
674 BOOL bContinue
= TRUE
;
676 HANDLE hSubKey
= NLS_RegOpenKey(hKey
, szNumber
);
680 if (NLS_RegGetDword(hSubKey
, L
"CountryCode", &dwGeoId
))
682 if (!lpGeoEnumProc(dwGeoId
))
702 /* Callback function ptrs for EnumSystemLanguageGroupsA/W */
705 LANGUAGEGROUP_ENUMPROCA procA
;
706 LANGUAGEGROUP_ENUMPROCW procW
;
709 } ENUMLANGUAGEGROUP_CALLBACKS
;
712 /* Internal implementation of EnumSystemLanguageGroupsA/W */
713 static BOOL
NLS_EnumSystemLanguageGroups(ENUMLANGUAGEGROUP_CALLBACKS
*lpProcs
)
715 WCHAR szNumber
[10], szValue
[4];
717 BOOL bContinue
= TRUE
;
722 SetLastError(ERROR_INVALID_PARAMETER
);
726 switch (lpProcs
->dwFlags
)
729 /* Default to LGRPID_INSTALLED */
730 lpProcs
->dwFlags
= LGRPID_INSTALLED
;
731 /* Fall through... */
732 case LGRPID_INSTALLED
:
733 case LGRPID_SUPPORTED
:
736 SetLastError(ERROR_INVALID_FLAGS
);
740 hKey
= NLS_RegOpenKey( 0, szLangGroupsKeyName
);
744 DPRINT1("NLS_RegOpenKey() failed, KeyName='%S'\n", szLangGroupsKeyName
);
750 if (NLS_RegEnumValue( hKey
, ulIndex
, szNumber
, sizeof(szNumber
),
751 szValue
, sizeof(szValue
) ))
753 BOOL bInstalled
= szValue
[0] == '1' ? TRUE
: FALSE
;
754 LGRPID lgrpid
= wcstoul( szNumber
, NULL
, 16 );
756 DPRINT("grpid %s (%sinstalled)\n", szNumber
,
757 bInstalled
? "" : "not ");
759 if (lpProcs
->dwFlags
== LGRPID_SUPPORTED
|| bInstalled
)
763 if (!NLS_GetLanguageGroupName( lgrpid
, szGrpName
, sizeof(szGrpName
) / sizeof(WCHAR
) ))
767 bContinue
= lpProcs
->procW( lgrpid
, szNumber
, szGrpName
, lpProcs
->dwFlags
,
771 char szNumberA
[sizeof(szNumber
)/sizeof(WCHAR
)];
774 /* FIXME: MSDN doesn't say which code page the W->A translation uses,
775 * or whether the language names are ever localised. Assume CP_ACP.
778 WideCharToMultiByte(CP_ACP
, 0, szNumber
, -1, szNumberA
, sizeof(szNumberA
), 0, 0);
779 WideCharToMultiByte(CP_ACP
, 0, szGrpName
, -1, szGrpNameA
, sizeof(szGrpNameA
), 0, 0);
781 bContinue
= lpProcs
->procA( lgrpid
, szNumberA
, szGrpNameA
, lpProcs
->dwFlags
,
807 EnumSystemLanguageGroupsA(
808 LANGUAGEGROUP_ENUMPROCA pLangGroupEnumProc
,
812 ENUMLANGUAGEGROUP_CALLBACKS procs
;
814 DPRINT("(%p,0x%08X,0x%08lX)\n", pLangGroupEnumProc
, dwFlags
, lParam
);
816 procs
.procA
= pLangGroupEnumProc
;
818 procs
.dwFlags
= dwFlags
;
819 procs
.lParam
= lParam
;
821 return NLS_EnumSystemLanguageGroups( pLangGroupEnumProc
? &procs
: NULL
);
830 EnumSystemLanguageGroupsW(
831 LANGUAGEGROUP_ENUMPROCW pLangGroupEnumProc
,
835 ENUMLANGUAGEGROUP_CALLBACKS procs
;
837 DPRINT("(%p,0x%08X,0x%08lX)\n", pLangGroupEnumProc
, dwFlags
, lParam
);
840 procs
.procW
= pLangGroupEnumProc
;
841 procs
.dwFlags
= dwFlags
;
842 procs
.lParam
= lParam
;
844 return NLS_EnumSystemLanguageGroups( pLangGroupEnumProc
? &procs
: NULL
);
848 /* Callback function ptrs for EnumSystemLocalesA/W */
851 LOCALE_ENUMPROCA procA
;
852 LOCALE_ENUMPROCW procW
;
854 } ENUMSYSTEMLOCALES_CALLBACKS
;
857 /* Internal implementation of EnumSystemLocalesA/W */
858 static BOOL
NLS_EnumSystemLocales(ENUMSYSTEMLOCALES_CALLBACKS
*lpProcs
)
860 WCHAR szNumber
[10], szValue
[4];
862 BOOL bContinue
= TRUE
;
867 SetLastError(ERROR_INVALID_PARAMETER
);
871 switch (lpProcs
->dwFlags
)
873 case LCID_ALTERNATE_SORTS
:
878 SetLastError(ERROR_INVALID_FLAGS
);
882 hKey
= NLS_RegOpenKey(0, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\Locale");
886 DPRINT1("NLS_RegOpenKey() failed\n");
892 if (NLS_RegEnumValue( hKey
, ulIndex
, szNumber
, sizeof(szNumber
),
893 szValue
, sizeof(szValue
)))
895 if ((lpProcs
->dwFlags
== LCID_SUPPORTED
)||
896 ((lpProcs
->dwFlags
== LCID_INSTALLED
)&&(wcslen(szValue
) > 0)))
900 bContinue
= lpProcs
->procW(szNumber
);
904 char szNumberA
[sizeof(szNumber
)/sizeof(WCHAR
)];
906 WideCharToMultiByte(CP_ACP
, 0, szNumber
, -1, szNumberA
, sizeof(szNumberA
), 0, 0);
907 bContinue
= lpProcs
->procA(szNumberA
);
932 LOCALE_ENUMPROCA lpLocaleEnumProc
,
936 ENUMSYSTEMLOCALES_CALLBACKS procs
;
938 DPRINT("(%p,0x%08X)\n", lpLocaleEnumProc
, dwFlags
);
940 procs
.procA
= lpLocaleEnumProc
;
942 procs
.dwFlags
= dwFlags
;
944 return NLS_EnumSystemLocales(lpLocaleEnumProc
? &procs
: NULL
);
954 LOCALE_ENUMPROCW lpLocaleEnumProc
,
958 ENUMSYSTEMLOCALES_CALLBACKS procs
;
960 DPRINT("(%p,0x%08X)\n", lpLocaleEnumProc
, dwFlags
);
963 procs
.procW
= lpLocaleEnumProc
;
964 procs
.dwFlags
= dwFlags
;
966 return NLS_EnumSystemLocales(lpLocaleEnumProc
? &procs
: NULL
);
970 static BOOL CALLBACK
enum_uilang_proc_a( HMODULE hModule
, LPCSTR type
,
971 LPCSTR name
, WORD LangID
, LONG_PTR lParam
)
973 ENUM_UILANG_CALLBACK
*enum_uilang
= (ENUM_UILANG_CALLBACK
*)lParam
;
976 sprintf(buf
, "%08x", (UINT
)LangID
);
977 return enum_uilang
->u
.procA( buf
, enum_uilang
->param
);
987 UILANGUAGE_ENUMPROCA lpUILanguageEnumProc
,
991 ENUM_UILANG_CALLBACK enum_uilang
;
993 DPRINT("%p, %x, %lx\n", lpUILanguageEnumProc
, dwFlags
, lParam
);
995 if(!lpUILanguageEnumProc
) {
996 SetLastError(ERROR_INVALID_PARAMETER
);
1000 SetLastError(ERROR_INVALID_FLAGS
);
1004 enum_uilang
.u
.procA
= lpUILanguageEnumProc
;
1005 enum_uilang
.flags
= dwFlags
;
1006 enum_uilang
.param
= lParam
;
1008 EnumResourceLanguagesA( hCurrentModule
, (LPCSTR
)RT_STRING
,
1009 (LPCSTR
)LOCALE_ILANGUAGE
, enum_uilang_proc_a
,
1010 (LONG_PTR
)&enum_uilang
);
1014 static BOOL CALLBACK
enum_uilang_proc_w( HMODULE hModule
, LPCWSTR type
,
1015 LPCWSTR name
, WORD LangID
, LONG_PTR lParam
)
1017 static const WCHAR formatW
[] = {'%','0','8','x',0};
1018 ENUM_UILANG_CALLBACK
*enum_uilang
= (ENUM_UILANG_CALLBACK
*)lParam
;
1021 swprintf( buf
, formatW
, (UINT
)LangID
);
1022 return enum_uilang
->u
.procW( buf
, enum_uilang
->param
);
1031 UILANGUAGE_ENUMPROCW lpUILanguageEnumProc
,
1035 ENUM_UILANG_CALLBACK enum_uilang
;
1037 DPRINT("%p, %x, %lx\n", lpUILanguageEnumProc
, dwFlags
, lParam
);
1040 if(!lpUILanguageEnumProc
) {
1041 SetLastError(ERROR_INVALID_PARAMETER
);
1045 SetLastError(ERROR_INVALID_FLAGS
);
1049 enum_uilang
.u
.procW
= lpUILanguageEnumProc
;
1050 enum_uilang
.flags
= dwFlags
;
1051 enum_uilang
.param
= lParam
;
1053 EnumResourceLanguagesW( hCurrentModule
, (LPCWSTR
)RT_STRING
,
1054 (LPCWSTR
)LOCALE_ILANGUAGE
, enum_uilang_proc_w
,
1055 (LONG_PTR
)&enum_uilang
);
1074 LPWSTR lpCalDataW
= NULL
;
1076 if (NLS_IsUnicodeOnlyLcid(lcid
))
1078 SetLastError(ERROR_INVALID_PARAMETER
);
1083 !(lpCalDataW
= HeapAlloc(GetProcessHeap(), 0, cchData
*sizeof(WCHAR
))))
1086 ret
= GetCalendarInfoW(lcid
, Calendar
, CalType
, lpCalDataW
, cchData
, lpValue
);
1087 if(ret
&& lpCalDataW
&& lpCalData
)
1088 WideCharToMultiByte(CP_ACP
, 0, lpCalDataW
, cchData
, lpCalData
, cchData
, NULL
, NULL
);
1089 HeapFree(GetProcessHeap(), 0, lpCalDataW
);
1108 if (CalType
& CAL_NOUSEROVERRIDE
)
1109 DPRINT("FIXME: flag CAL_NOUSEROVERRIDE used, not fully implemented\n");
1110 if (CalType
& CAL_USE_CP_ACP
)
1111 DPRINT("FIXME: flag CAL_USE_CP_ACP used, not fully implemented\n");
1113 if (CalType
& CAL_RETURN_NUMBER
) {
1114 if (lpCalData
!= NULL
)
1115 DPRINT("WARNING: lpCalData not NULL (%p) when it should!\n", lpCalData
);
1117 DPRINT("WARNING: cchData not 0 (%d) when it should!\n", cchData
);
1119 if (lpValue
!= NULL
)
1120 DPRINT("WARNING: lpValue not NULL (%p) when it should!\n", lpValue
);
1123 /* FIXME: No verification is made yet wrt Locale
1124 * for the CALTYPES not requiring GetLocaleInfoA */
1125 switch (CalType
& ~(CAL_NOUSEROVERRIDE
|CAL_RETURN_NUMBER
|CAL_USE_CP_ACP
)) {
1126 case CAL_ICALINTVALUE
:
1127 DPRINT("FIXME: Unimplemented caltype %d\n", CalType
& 0xffff);
1130 DPRINT("FIXME: Unimplemented caltype %d\n", CalType
& 0xffff);
1132 case CAL_IYEAROFFSETRANGE
:
1133 DPRINT("FIXME: Unimplemented caltype %d\n", CalType
& 0xffff);
1135 case CAL_SERASTRING
:
1136 DPRINT("FIXME: Unimplemented caltype %d\n", CalType
& 0xffff);
1138 case CAL_SSHORTDATE
:
1139 return GetLocaleInfoW(Locale
, LOCALE_SSHORTDATE
, lpCalData
, cchData
);
1141 return GetLocaleInfoW(Locale
, LOCALE_SLONGDATE
, lpCalData
, cchData
);
1143 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME1
, lpCalData
, cchData
);
1145 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME2
, lpCalData
, cchData
);
1147 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME3
, lpCalData
, cchData
);
1149 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME4
, lpCalData
, cchData
);
1151 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME5
, lpCalData
, cchData
);
1153 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME6
, lpCalData
, cchData
);
1155 return GetLocaleInfoW(Locale
, LOCALE_SDAYNAME7
, lpCalData
, cchData
);
1156 case CAL_SABBREVDAYNAME1
:
1157 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME1
, lpCalData
, cchData
);
1158 case CAL_SABBREVDAYNAME2
:
1159 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME2
, lpCalData
, cchData
);
1160 case CAL_SABBREVDAYNAME3
:
1161 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME3
, lpCalData
, cchData
);
1162 case CAL_SABBREVDAYNAME4
:
1163 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME4
, lpCalData
, cchData
);
1164 case CAL_SABBREVDAYNAME5
:
1165 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME5
, lpCalData
, cchData
);
1166 case CAL_SABBREVDAYNAME6
:
1167 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME6
, lpCalData
, cchData
);
1168 case CAL_SABBREVDAYNAME7
:
1169 return GetLocaleInfoW(Locale
, LOCALE_SABBREVDAYNAME7
, lpCalData
, cchData
);
1170 case CAL_SMONTHNAME1
:
1171 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME1
, lpCalData
, cchData
);
1172 case CAL_SMONTHNAME2
:
1173 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME2
, lpCalData
, cchData
);
1174 case CAL_SMONTHNAME3
:
1175 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME3
, lpCalData
, cchData
);
1176 case CAL_SMONTHNAME4
:
1177 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME4
, lpCalData
, cchData
);
1178 case CAL_SMONTHNAME5
:
1179 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME5
, lpCalData
, cchData
);
1180 case CAL_SMONTHNAME6
:
1181 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME6
, lpCalData
, cchData
);
1182 case CAL_SMONTHNAME7
:
1183 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME7
, lpCalData
, cchData
);
1184 case CAL_SMONTHNAME8
:
1185 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME8
, lpCalData
, cchData
);
1186 case CAL_SMONTHNAME9
:
1187 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME9
, lpCalData
, cchData
);
1188 case CAL_SMONTHNAME10
:
1189 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME10
, lpCalData
, cchData
);
1190 case CAL_SMONTHNAME11
:
1191 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME11
, lpCalData
, cchData
);
1192 case CAL_SMONTHNAME12
:
1193 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME12
, lpCalData
, cchData
);
1194 case CAL_SMONTHNAME13
:
1195 return GetLocaleInfoW(Locale
, LOCALE_SMONTHNAME13
, lpCalData
, cchData
);
1196 case CAL_SABBREVMONTHNAME1
:
1197 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME1
, lpCalData
, cchData
);
1198 case CAL_SABBREVMONTHNAME2
:
1199 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME2
, lpCalData
, cchData
);
1200 case CAL_SABBREVMONTHNAME3
:
1201 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME3
, lpCalData
, cchData
);
1202 case CAL_SABBREVMONTHNAME4
:
1203 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME4
, lpCalData
, cchData
);
1204 case CAL_SABBREVMONTHNAME5
:
1205 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME5
, lpCalData
, cchData
);
1206 case CAL_SABBREVMONTHNAME6
:
1207 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME6
, lpCalData
, cchData
);
1208 case CAL_SABBREVMONTHNAME7
:
1209 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME7
, lpCalData
, cchData
);
1210 case CAL_SABBREVMONTHNAME8
:
1211 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME8
, lpCalData
, cchData
);
1212 case CAL_SABBREVMONTHNAME9
:
1213 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME9
, lpCalData
, cchData
);
1214 case CAL_SABBREVMONTHNAME10
:
1215 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME10
, lpCalData
, cchData
);
1216 case CAL_SABBREVMONTHNAME11
:
1217 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME11
, lpCalData
, cchData
);
1218 case CAL_SABBREVMONTHNAME12
:
1219 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME12
, lpCalData
, cchData
);
1220 case CAL_SABBREVMONTHNAME13
:
1221 return GetLocaleInfoW(Locale
, LOCALE_SABBREVMONTHNAME13
, lpCalData
, cchData
);
1222 case CAL_SYEARMONTH
:
1223 return GetLocaleInfoW(Locale
, LOCALE_SYEARMONTH
, lpCalData
, cchData
);
1224 case CAL_ITWODIGITYEARMAX
:
1225 if (lpValue
) *lpValue
= CALINFO_MAX_YEAR
;
1227 default: DPRINT("Unknown caltype %d\n",CalType
& 0xffff);
1239 GetCPInfo(UINT CodePage
,
1240 LPCPINFO CodePageInfo
)
1242 PCODEPAGE_ENTRY CodePageEntry
;
1246 SetLastError(ERROR_INVALID_PARAMETER
);
1250 CodePageEntry
= IntGetCodePageEntry(CodePage
);
1251 if (CodePageEntry
== NULL
)
1257 CodePageInfo
->DefaultChar
[0] = 0x3f;
1258 CodePageInfo
->DefaultChar
[1] = 0;
1259 CodePageInfo
->LeadByte
[0] = CodePageInfo
->LeadByte
[1] = 0;
1260 CodePageInfo
->MaxCharSize
= (CodePage
== CP_UTF7
) ? 5 : 4;
1264 SetLastError( ERROR_INVALID_PARAMETER
);
1268 if (CodePageEntry
->CodePageTable
.DefaultChar
& 0xff00)
1270 CodePageInfo
->DefaultChar
[0] = (CodePageEntry
->CodePageTable
.DefaultChar
& 0xff00) >> 8;
1271 CodePageInfo
->DefaultChar
[1] = CodePageEntry
->CodePageTable
.DefaultChar
& 0x00ff;
1275 CodePageInfo
->DefaultChar
[0] = CodePageEntry
->CodePageTable
.DefaultChar
& 0xff;
1276 CodePageInfo
->DefaultChar
[1] = 0;
1279 if ((CodePageInfo
->MaxCharSize
= CodePageEntry
->CodePageTable
.MaximumCharacterSize
) == 2)
1280 memcpy(CodePageInfo
->LeadByte
, CodePageEntry
->CodePageTable
.LeadByte
, sizeof(CodePageInfo
->LeadByte
));
1282 CodePageInfo
->LeadByte
[0] = CodePageInfo
->LeadByte
[1] = 0;
1288 GetLocalisedText(DWORD dwResId
, WCHAR
*lpszDest
)
1296 dwId
= dwResId
* 100;
1300 lcid
= GetUserDefaultLCID();
1301 lcid
= ConvertDefaultLocale(lcid
);
1303 langId
= LANGIDFROMLCID(lcid
);
1305 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
1306 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
);
1308 hrsrc
= FindResourceExW(hCurrentModule
,
1310 MAKEINTRESOURCEW((dwId
>> 4) + 1),
1314 HGLOBAL hmem
= LoadResource(hCurrentModule
, hrsrc
);
1321 p
= LockResource(hmem
);
1322 for (i
= 0; i
< (dwId
& 0x0f); i
++) p
+= *p
+ 1;
1324 memcpy(lpszDest
, p
+ 1, *p
* sizeof(WCHAR
));
1325 lpszDest
[*p
] = '\0';
1331 DPRINT1("Could not get codepage name. dwResId = %ld\n", dwResId
);
1340 GetCPInfoExW(UINT CodePage
,
1342 LPCPINFOEXW lpCPInfoEx
)
1344 if (!GetCPInfo(CodePage
, (LPCPINFO
) lpCPInfoEx
))
1351 lpCPInfoEx
->CodePage
= CP_UTF7
;
1352 lpCPInfoEx
->UnicodeDefaultChar
= 0x3f;
1353 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
);
1359 lpCPInfoEx
->CodePage
= CP_UTF8
;
1360 lpCPInfoEx
->UnicodeDefaultChar
= 0x3f;
1361 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
);
1366 PCODEPAGE_ENTRY CodePageEntry
;
1368 CodePageEntry
= IntGetCodePageEntry(CodePage
);
1369 if (CodePageEntry
== NULL
)
1371 DPRINT1("Could not get CodePage Entry! CodePageEntry = 0\n");
1372 SetLastError(ERROR_INVALID_PARAMETER
);
1376 lpCPInfoEx
->CodePage
= CodePageEntry
->CodePageTable
.CodePage
;
1377 lpCPInfoEx
->UnicodeDefaultChar
= CodePageEntry
->CodePageTable
.UniDefaultChar
;
1378 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
);
1390 GetCPInfoExA(UINT CodePage
,
1392 LPCPINFOEXA lpCPInfoEx
)
1396 if (!GetCPInfoExW(CodePage
, dwFlags
, &CPInfo
))
1399 /* the layout is the same except for CodePageName */
1400 memcpy(lpCPInfoEx
, &CPInfo
, sizeof(CPINFOEXA
));
1402 WideCharToMultiByte(CP_ACP
,
1404 CPInfo
.CodePageName
,
1406 lpCPInfoEx
->CodePageName
,
1407 sizeof(lpCPInfoEx
->CodePageName
),
1414 NLS_GetGeoFriendlyName(GEOID Location
, LPWSTR szFriendlyName
, int cchData
)
1417 WCHAR szPath
[MAX_PATH
];
1418 UNICODE_STRING ValueName
;
1419 KEY_VALUE_PARTIAL_INFORMATION
*info
;
1420 static const int info_size
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1425 swprintf(szPath
, L
"\\REGISTRY\\Machine\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Country List\\%d", Location
);
1427 hKey
= NLS_RegOpenKey(0, szPath
);
1430 DPRINT1("NLS_RegOpenKey() failed\n");
1434 dwSize
= info_size
+ cchData
* sizeof(WCHAR
);
1436 if (!(info
= HeapAlloc(GetProcessHeap(), 0, dwSize
)))
1439 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1443 RtlInitUnicodeString(&ValueName
, L
"Name");
1445 Status
= NtQueryValueKey(hKey
, &ValueName
, KeyValuePartialInformation
,
1446 (LPBYTE
)info
, dwSize
, &dwSize
);
1450 Ret
= (dwSize
- info_size
) / sizeof(WCHAR
);
1452 if (!Ret
|| ((WCHAR
*)info
->Data
)[Ret
-1])
1454 if (Ret
< cchData
|| !szFriendlyName
) Ret
++;
1457 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1462 if (Ret
&& szFriendlyName
)
1464 memcpy(szFriendlyName
, info
->Data
, (Ret
-1) * sizeof(WCHAR
));
1465 szFriendlyName
[Ret
-1] = 0;
1468 else if (Status
== STATUS_BUFFER_OVERFLOW
&& !szFriendlyName
)
1470 Ret
= (dwSize
- info_size
) / sizeof(WCHAR
) + 1;
1472 else if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1478 SetLastError(RtlNtStatusToDosError(Status
));
1483 HeapFree(GetProcessHeap(), 0, info
);
1500 DPRINT("%d %d %p %d %d\n", Location
, GeoType
, lpGeoData
, cchData
, LangId
);
1502 if ((GeoType
== GEO_TIMEZONES
)||(GeoType
== GEO_OFFICIALLANGUAGES
))
1504 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1509 case GEO_FRIENDLYNAME
:
1511 return NLS_GetGeoFriendlyName(Location
, lpGeoData
, cchData
);
1520 case GEO_OFFICIALNAME
:
1521 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1541 DPRINT("%d %d %p %d %d\n", Location
, GeoType
, lpGeoData
, cchData
, LangId
);
1543 if ((GeoType
== GEO_TIMEZONES
)||(GeoType
== GEO_OFFICIALLANGUAGES
))
1545 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1550 case GEO_FRIENDLYNAME
:
1552 WCHAR szBuffer
[MAX_PATH
];
1555 Ret
= NLS_GetGeoFriendlyName(Location
, szBuffer
, cchData
);
1556 char szBufferA
[sizeof(szBuffer
)/sizeof(WCHAR
)];
1558 WideCharToMultiByte(CP_ACP
, 0, szBuffer
, -1, szBufferA
, sizeof(szBufferA
), 0, 0);
1559 strcpy(lpGeoData
, szBufferA
);
1570 case GEO_OFFICIALNAME
:
1571 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1578 const WCHAR
*RosGetLocaleValueName( DWORD lctype
)
1580 switch (lctype
& ~LOCALE_LOCALEINFOFLAGSMASK
)
1582 /* These values are used by SetLocaleInfo and GetLocaleInfo, and
1583 * the values are stored in the registry, confirmed under Windows.
1585 case LOCALE_ICALENDARTYPE
: return L
"iCalendarType";
1586 case LOCALE_ICURRDIGITS
: return L
"iCurrDigits";
1587 case LOCALE_ICURRENCY
: return L
"iCurrency";
1588 case LOCALE_IDIGITS
: return L
"iDigits";
1589 case LOCALE_IFIRSTDAYOFWEEK
: return L
"iFirstDayOfWeek";
1590 case LOCALE_IFIRSTWEEKOFYEAR
: return L
"iFirstWeekOfYear";
1591 case LOCALE_ILZERO
: return L
"iLZero";
1592 case LOCALE_IMEASURE
: return L
"iMeasure";
1593 case LOCALE_INEGCURR
: return L
"iNegCurr";
1594 case LOCALE_INEGNUMBER
: return L
"iNegNumber";
1595 case LOCALE_IPAPERSIZE
: return L
"iPaperSize";
1596 case LOCALE_ITIME
: return L
"iTime";
1597 case LOCALE_S1159
: return L
"s1159";
1598 case LOCALE_S2359
: return L
"s2359";
1599 case LOCALE_SCURRENCY
: return L
"sCurrency";
1600 case LOCALE_SDATE
: return L
"sDate";
1601 case LOCALE_SDECIMAL
: return L
"sDecimal";
1602 case LOCALE_SGROUPING
: return L
"sGrouping";
1603 case LOCALE_SLIST
: return L
"sList";
1604 case LOCALE_SLONGDATE
: return L
"sLongDate";
1605 case LOCALE_SMONDECIMALSEP
: return L
"sMonDecimalSep";
1606 case LOCALE_SMONGROUPING
: return L
"sMonGrouping";
1607 case LOCALE_SMONTHOUSANDSEP
: return L
"sMonThousandSep";
1608 case LOCALE_SNEGATIVESIGN
: return L
"sNegativeSign";
1609 case LOCALE_SPOSITIVESIGN
: return L
"sPositiveSign";
1610 case LOCALE_SSHORTDATE
: return L
"sShortDate";
1611 case LOCALE_STHOUSAND
: return L
"sThousand";
1612 case LOCALE_STIME
: return L
"sTime";
1613 case LOCALE_STIMEFORMAT
: return L
"sTimeFormat";
1614 case LOCALE_SYEARMONTH
: return L
"sYearMonth";
1616 /* The following are not listed under MSDN as supported,
1617 * but seem to be used and also stored in the registry.
1619 case LOCALE_ICOUNTRY
: return L
"iCountry";
1620 case LOCALE_IDATE
: return L
"iDate";
1621 case LOCALE_ILDATE
: return L
"iLDate";
1622 case LOCALE_ITLZERO
: return L
"iTLZero";
1623 case LOCALE_SCOUNTRY
: return L
"sCountry";
1624 case LOCALE_SLANGUAGE
: return L
"sLanguage";
1629 HKEY
RosCreateRegistryKey(void)
1631 OBJECT_ATTRIBUTES objAttr
;
1632 UNICODE_STRING nameW
;
1635 if (RtlOpenCurrentUser( KEY_ALL_ACCESS
, &hKey
) != STATUS_SUCCESS
) return 0;
1637 objAttr
.Length
= sizeof(objAttr
);
1638 objAttr
.RootDirectory
= hKey
;
1639 objAttr
.ObjectName
= &nameW
;
1640 objAttr
.Attributes
= 0;
1641 objAttr
.SecurityDescriptor
= NULL
;
1642 objAttr
.SecurityQualityOfService
= NULL
;
1643 RtlInitUnicodeString( &nameW
, L
"Control Panel\\International");
1645 if (NtCreateKey( &hKey
, KEY_ALL_ACCESS
, &objAttr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
) hKey
= 0;
1646 NtClose( objAttr
.RootDirectory
);
1650 INT
RosGetRegistryLocaleInfo( LPCWSTR lpValue
, LPWSTR lpBuffer
, INT nLen
)
1656 UNICODE_STRING usNameW
;
1657 KEY_VALUE_PARTIAL_INFORMATION
*kvpiInfo
;
1658 const int nInfoSize
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1660 if (!(hKey
= RosCreateRegistryKey())) return -1;
1662 RtlInitUnicodeString( &usNameW
, lpValue
);
1663 dwSize
= nInfoSize
+ nLen
* sizeof(WCHAR
);
1665 if (!(kvpiInfo
= HeapAlloc( GetProcessHeap(), 0, dwSize
)))
1668 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1672 ntStatus
= NtQueryValueKey( hKey
, &usNameW
, KeyValuePartialInformation
, kvpiInfo
, dwSize
, &dwSize
);
1673 if (ntStatus
== STATUS_BUFFER_OVERFLOW
&& !lpBuffer
) ntStatus
= 0;
1677 nRet
= (dwSize
- nInfoSize
) / sizeof(WCHAR
);
1679 if (!nRet
|| ((WCHAR
*)kvpiInfo
->Data
)[nRet
- 1])
1681 if (nRet
< nLen
|| !lpBuffer
) nRet
++;
1684 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1688 if (nRet
&& lpBuffer
)
1690 memcpy( lpBuffer
, kvpiInfo
->Data
, (nRet
- 1) * sizeof(WCHAR
) );
1691 lpBuffer
[nRet
- 1] = 0;
1696 if (ntStatus
== STATUS_OBJECT_NAME_NOT_FOUND
) nRet
= -1;
1699 SetLastError( RtlNtStatusToDosError(ntStatus
) );
1704 HeapFree( GetProcessHeap(), 0, kvpiInfo
);
1711 LPCWSTR lpLocaleName
,
1741 if (cchData
< 0 || (cchData
&& !lpLCData
))
1743 SetLastError( ERROR_INVALID_PARAMETER
);
1746 if (!cchData
) lpLCData
= NULL
;
1748 if (Locale
== LOCALE_NEUTRAL
|| Locale
== LOCALE_SYSTEM_DEFAULT
) Locale
= GetSystemDefaultLCID();
1749 else if (Locale
== LOCALE_USER_DEFAULT
) Locale
= GetUserDefaultLCID();
1751 uiFlags
= LCType
& LOCALE_LOCALEINFOFLAGSMASK
;
1752 LCType
&= ~LOCALE_LOCALEINFOFLAGSMASK
;
1754 if (!(uiFlags
& LOCALE_NOUSEROVERRIDE
) && Locale
== GetUserDefaultLCID())
1756 const WCHAR
*value
= RosGetLocaleValueName(LCType
);
1758 if (value
&& ((nRet
= RosGetRegistryLocaleInfo( value
, lpLCData
, cchData
)) != -1)) return nRet
;
1761 liLangID
= LANGIDFROMLCID( Locale
);
1763 if (SUBLANGID(liLangID
) == SUBLANG_NEUTRAL
)
1764 liLangID
= MAKELANGID(PRIMARYLANGID(liLangID
), SUBLANG_DEFAULT
);
1766 hModule
= GetModuleHandleW( L
"kernel32.dll" );
1767 if (!(hRsrc
= FindResourceExW( hModule
, (LPWSTR
)RT_STRING
, (LPCWSTR
)((LCType
>> 4) + 1), liLangID
)))
1769 SetLastError( ERROR_INVALID_FLAGS
);
1772 if (!(hMem
= LoadResource( hModule
, hRsrc
)))
1775 ch
= LockResource( hMem
);
1776 for (i
= 0; i
< (int)(LCType
& 0x0f); i
++) ch
+= *ch
+ 1;
1778 if (uiFlags
& LOCALE_RETURN_NUMBER
) nRet
= sizeof(UINT
) / sizeof(WCHAR
);
1779 else nRet
= (LCType
== LOCALE_FONTSIGNATURE
) ? *ch
: *ch
+ 1;
1781 if (!lpLCData
) return nRet
;
1785 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1789 if (uiFlags
& LOCALE_RETURN_NUMBER
)
1792 WCHAR
*chEnd
, *chTmp
= HeapAlloc( GetProcessHeap(), 0, (*ch
+ 1) * sizeof(WCHAR
) );
1797 memcpy( chTmp
, ch
+ 1, *ch
* sizeof(WCHAR
) );
1799 uiNum
= wcstol( chTmp
, &chEnd
, 10 );
1802 memcpy( lpLCData
, &uiNum
, sizeof(uiNum
) );
1805 SetLastError( ERROR_INVALID_FLAGS
);
1808 HeapFree( GetProcessHeap(), 0, chTmp
);
1812 memcpy( lpLCData
, ch
+ 1, *ch
* sizeof(WCHAR
) );
1813 if (LCType
!= LOCALE_FONTSIGNATURE
) lpLCData
[nRet
-1] = 0;
1820 /***********************************************************************
1823 * Retrieve the ANSI codepage for a given locale.
1825 __inline
static UINT
get_lcid_codepage( LCID lcid
)
1828 if (!GetLocaleInfoW( lcid
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
, (WCHAR
*)&ret
,
1829 sizeof(ret
)/sizeof(WCHAR
) )) ret
= 0;
1834 /*************************************************************************
1835 * FoldStringA (KERNEL32.@)
1837 * Map characters in a string.
1840 * dwFlags [I] Flags controlling chars to map (MAP_ constants from "winnls.h")
1841 * src [I] String to map
1842 * srclen [I] Length of src, or -1 if src is NUL terminated
1843 * dst [O] Destination for mapped string
1844 * dstlen [I] Length of dst, or 0 to find the required length for the mapped string
1847 * Success: The length of the string written to dst, including the terminating NUL. If
1848 * dstlen is 0, the value returned is the same, but nothing is written to dst,
1849 * and dst may be NULL.
1850 * Failure: 0. Use GetLastError() to determine the cause.
1852 INT WINAPI
FoldStringA(DWORD dwFlags
, LPCSTR src
, INT srclen
,
1853 LPSTR dst
, INT dstlen
)
1855 INT ret
= 0, srclenW
= 0;
1856 WCHAR
*srcW
= NULL
, *dstW
= NULL
;
1858 if (!src
|| !srclen
|| dstlen
< 0 || (dstlen
&& !dst
) || src
== dst
)
1860 SetLastError(ERROR_INVALID_PARAMETER
);
1864 srclenW
= MultiByteToWideChar(CP_ACP
, dwFlags
& MAP_COMPOSITE
? MB_COMPOSITE
: 0,
1865 src
, srclen
, NULL
, 0);
1866 srcW
= HeapAlloc(GetProcessHeap(), 0, srclenW
* sizeof(WCHAR
));
1870 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1871 goto FoldStringA_exit
;
1874 MultiByteToWideChar(CP_ACP
, dwFlags
& MAP_COMPOSITE
? MB_COMPOSITE
: 0,
1875 src
, srclen
, srcW
, srclenW
);
1877 dwFlags
= (dwFlags
& ~MAP_PRECOMPOSED
) | MAP_FOLDCZONE
;
1879 ret
= FoldStringW(dwFlags
, srcW
, srclenW
, NULL
, 0);
1882 dstW
= HeapAlloc(GetProcessHeap(), 0, ret
* sizeof(WCHAR
));
1886 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1887 goto FoldStringA_exit
;
1890 ret
= FoldStringW(dwFlags
, srcW
, srclenW
, dstW
, ret
);
1891 if (!WideCharToMultiByte(CP_ACP
, 0, dstW
, ret
, dst
, dstlen
, NULL
, NULL
))
1894 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1898 HeapFree(GetProcessHeap(), 0, dstW
);
1901 HeapFree(GetProcessHeap(), 0, srcW
);
1905 /*************************************************************************
1906 * FoldStringW (KERNEL32.@)
1910 INT WINAPI
FoldStringW(DWORD dwFlags
, LPCWSTR src
, INT srclen
,
1911 LPWSTR dst
, INT dstlen
)
1915 switch (dwFlags
& (MAP_COMPOSITE
|MAP_PRECOMPOSED
|MAP_EXPAND_LIGATURES
))
1920 /* Fall through for dwFlags == 0 */
1921 case MAP_PRECOMPOSED
|MAP_COMPOSITE
:
1922 case MAP_PRECOMPOSED
|MAP_EXPAND_LIGATURES
:
1923 case MAP_COMPOSITE
|MAP_EXPAND_LIGATURES
:
1924 SetLastError(ERROR_INVALID_FLAGS
);
1928 if (!src
|| !srclen
|| dstlen
< 0 || (dstlen
&& !dst
) || src
== dst
)
1930 SetLastError(ERROR_INVALID_PARAMETER
);
1934 ret
= wine_fold_string(dwFlags
, src
, srclen
, dst
, dstlen
);
1936 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1942 * @implemented (Synced to Wine-22112008)
1955 WCHAR
*buf1W
= NtCurrentTeb()->StaticUnicodeBuffer
;
1956 WCHAR
*buf2W
= buf1W
+ 130;
1957 LPWSTR str1W
, str2W
;
1958 INT len1W
, len2W
, ret
;
1959 UINT locale_cp
= CP_ACP
;
1961 if (!lpString1
|| !lpString2
)
1963 SetLastError(ERROR_INVALID_PARAMETER
);
1966 if (cchCount1
< 0) cchCount1
= strlen(lpString1
);
1967 if (cchCount2
< 0) cchCount2
= strlen(lpString2
);
1969 if (!(dwCmpFlags
& LOCALE_USE_CP_ACP
)) locale_cp
= get_lcid_codepage(Locale
);
1971 len1W
= MultiByteToWideChar(locale_cp
, 0, lpString1
, cchCount1
, buf1W
, 130);
1976 len1W
= MultiByteToWideChar(locale_cp
, 0, lpString1
, cchCount1
, NULL
, 0);
1977 str1W
= HeapAlloc(GetProcessHeap(), 0, len1W
* sizeof(WCHAR
));
1980 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1983 MultiByteToWideChar(locale_cp
, 0, lpString1
, cchCount1
, str1W
, len1W
);
1985 len2W
= MultiByteToWideChar(locale_cp
, 0, lpString2
, cchCount2
, buf2W
, 130);
1990 len2W
= MultiByteToWideChar(locale_cp
, 0, lpString2
, cchCount2
, NULL
, 0);
1991 str2W
= HeapAlloc(GetProcessHeap(), 0, len2W
* sizeof(WCHAR
));
1994 if (str1W
!= buf1W
) HeapFree(GetProcessHeap(), 0, str1W
);
1995 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1998 MultiByteToWideChar(locale_cp
, 0, lpString2
, cchCount2
, str2W
, len2W
);
2001 ret
= CompareStringW(Locale
, dwCmpFlags
, str1W
, len1W
, str2W
, len2W
);
2003 if (str1W
!= buf1W
) HeapFree(GetProcessHeap(), 0, str1W
);
2004 if (str2W
!= buf2W
) HeapFree(GetProcessHeap(), 0, str2W
);
2009 * @implemented (Synced to Wine-22/11/2008)
2024 if (!lpString1
|| !lpString2
)
2026 SetLastError(ERROR_INVALID_PARAMETER
);
2030 if (dwCmpFlags
& ~(NORM_IGNORECASE
| NORM_IGNORENONSPACE
|
2031 NORM_IGNORESYMBOLS
| SORT_STRINGSORT
| NORM_IGNOREKANATYPE
|
2032 NORM_IGNOREWIDTH
| LOCALE_USE_CP_ACP
| 0x10000000))
2034 SetLastError(ERROR_INVALID_FLAGS
);
2038 /* this style is related to diacritics in Arabic, Japanese, and Hebrew */
2039 if (dwCmpFlags
& 0x10000000)
2040 DPRINT1("Ignoring unknown style 0x10000000\n");
2042 if (cchCount1
< 0) cchCount1
= wcslen(lpString1
);
2043 if (cchCount2
< 0) cchCount2
= wcslen(lpString2
);
2045 Result
= wine_compare_string(dwCmpFlags
, lpString1
, cchCount1
, lpString2
, cchCount2
);
2047 if (Result
) /* need to translate result */
2048 return (Result
< 0) ? CSTR_LESS_THAN
: CSTR_GREATER_THAN
;
2059 * Get information about an aspect of a locale.
2062 * lcid [I] LCID of the locale
2063 * lctype [I] LCTYPE_ flags from "winnls.h"
2064 * buffer [O] Destination for the information
2065 * len [I] Length of buffer in characters
2068 * Success: The size of the data requested. If buffer is non-NULL, it is filled
2069 * with the information.
2070 * Failure: 0. Use GetLastError() to determine the cause.
2073 * - LOCALE_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT
2074 * - The string returned is NUL terminated, except for LOCALE_FONTSIGNATURE,
2075 * which is a bit string.
2077 INT WINAPI
GetLocaleInfoA( LCID lcid
, LCTYPE lctype
, LPSTR buffer
, INT len
)
2082 if (len
< 0 || (len
&& !buffer
))
2084 SetLastError( ERROR_INVALID_PARAMETER
);
2087 if (!len
) buffer
= NULL
;
2089 if (!(lenW
= GetLocaleInfoW( lcid
, lctype
, NULL
, 0 ))) return 0;
2091 if (!(bufferW
= HeapAlloc( GetProcessHeap(), 0, lenW
* sizeof(WCHAR
) )))
2093 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
2096 if ((ret
= GetLocaleInfoW( lcid
, lctype
, bufferW
, lenW
)))
2098 if ((lctype
& LOCALE_RETURN_NUMBER
) ||
2099 ((lctype
& ~LOCALE_LOCALEINFOFLAGSMASK
) == LOCALE_FONTSIGNATURE
))
2101 /* it's not an ASCII string, just bytes */
2102 ret
*= sizeof(WCHAR
);
2105 if (ret
<= len
) memcpy( buffer
, bufferW
, ret
);
2108 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
2115 UINT codepage
= CP_ACP
;
2116 if (!(lctype
& LOCALE_USE_CP_ACP
)) codepage
= get_lcid_codepage( lcid
);
2117 ret
= WideCharToMultiByte( codepage
, 0, bufferW
, ret
, buffer
, len
, NULL
, NULL
);
2120 HeapFree( GetProcessHeap(), 0, bufferW
);
2129 GetSystemDefaultLangID(VOID
)
2131 return LANGIDFROMLCID(GetSystemDefaultLCID());
2139 GetSystemDefaultLCID(VOID
)
2143 NtQueryDefaultLocale(FALSE
, &lcid
);
2153 GetSystemDefaultUILanguage(VOID
)
2158 Status
= NtQueryInstallUILanguage(&LanguageId
);
2159 if (!NT_SUCCESS(Status
))
2161 SetLastErrorByStatus(Status
);
2173 GetThreadLocale(VOID
)
2175 return NtCurrentTeb()->CurrentLocale
;
2183 GetUserDefaultLangID(VOID
)
2185 return LANGIDFROMLCID(GetUserDefaultLCID());
2193 GetUserDefaultLCID(VOID
)
2198 Status
= NtQueryDefaultLocale(TRUE
, &lcid
);
2199 if (!NT_SUCCESS(Status
))
2201 SetLastErrorByStatus(Status
);
2213 GetUserDefaultUILanguage(VOID
)
2218 Status
= NtQueryDefaultUILanguage(&LangId
);
2219 if (!NT_SUCCESS(Status
))
2221 SetLastErrorByStatus(Status
);
2229 /***********************************************************************
2230 * create_registry_key
2232 * Create the Control Panel\\International registry key.
2234 static inline HANDLE
create_registry_key(void)
2236 static const WCHAR intlW
[] = {'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
2237 'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
2238 OBJECT_ATTRIBUTES attr
;
2239 UNICODE_STRING nameW
;
2242 if (RtlOpenCurrentUser( KEY_ALL_ACCESS
, &hkey
) != STATUS_SUCCESS
) return 0;
2244 attr
.Length
= sizeof(attr
);
2245 attr
.RootDirectory
= hkey
;
2246 attr
.ObjectName
= &nameW
;
2247 attr
.Attributes
= 0;
2248 attr
.SecurityDescriptor
= NULL
;
2249 attr
.SecurityQualityOfService
= NULL
;
2250 RtlInitUnicodeString( &nameW
, intlW
);
2252 if (NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
) hkey
= 0;
2253 NtClose( attr
.RootDirectory
);
2266 GEOID ret
= GEOID_NOT_AVAILABLE
;
2267 static const WCHAR geoW
[] = {'G','e','o',0};
2268 static const WCHAR nationW
[] = {'N','a','t','i','o','n',0};
2269 WCHAR bufferW
[40], *end
;
2271 HANDLE hkey
, hSubkey
= 0;
2272 UNICODE_STRING keyW
;
2273 const KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)bufferW
;
2274 RtlInitUnicodeString( &keyW
, nationW
);
2275 count
= sizeof(bufferW
);
2277 if(!(hkey
= create_registry_key())) return ret
;
2280 case GEOCLASS_NATION
:
2281 if ((hSubkey
= NLS_RegOpenKey(hkey
, geoW
)))
2283 if((NtQueryValueKey(hSubkey
, &keyW
, KeyValuePartialInformation
,
2284 (LPBYTE
)bufferW
, count
, &count
) == STATUS_SUCCESS
) && info
->DataLength
)
2285 ret
= wcstol((LPCWSTR
)info
->Data
, &end
, 10);
2288 case GEOCLASS_REGION
:
2289 DPRINT("GEOCLASS_REGION not handled yet\n");
2294 if (hSubkey
) NtClose(hSubkey
);
2299 /******************************************************************************
2300 * IsValidLanguageGroup
2302 * Determine if a language group is supported and/or installed.
2305 * LanguageGroup [I] Language Group Id (LGRPID_ values from "winnls.h")
2306 * dwFlags [I] LGRPID_SUPPORTED=Supported, LGRPID_INSTALLED=Installed
2309 * TRUE, if lgrpid is supported and/or installed, according to dwFlags.
2316 IsValidLanguageGroup(
2317 LGRPID LanguageGroup
,
2320 static const WCHAR szFormat
[] = { '%','x','\0' };
2321 WCHAR szValueName
[16], szValue
[2];
2322 BOOL bSupported
= FALSE
, bInstalled
= FALSE
;
2328 case LGRPID_INSTALLED
:
2329 case LGRPID_SUPPORTED
:
2331 hKey
= NLS_RegOpenKey( 0, szLangGroupsKeyName
);
2333 swprintf( szValueName
, szFormat
, LanguageGroup
);
2335 if (NLS_RegGetDword( hKey
, szValueName
, (LPDWORD
)szValue
))
2339 if (szValue
[0] == '1')
2349 if ((dwFlags
== LGRPID_SUPPORTED
&& bSupported
) ||
2350 (dwFlags
== LGRPID_INSTALLED
&& bInstalled
))
2357 /******************************************************************************
2360 * Determine if a locale is valid.
2363 * Locale [I] LCID of the locale to check
2364 * dwFlags [I] LCID_SUPPORTED = Valid
2365 * LCID_INSTALLED = Valid and installed on the system
2368 * TRUE, if Locale is valid,
2374 IsValidLocale(LCID Locale
,
2377 OBJECT_ATTRIBUTES ObjectAttributes
;
2378 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo
;
2379 WCHAR ValueNameBuffer
[9];
2380 UNICODE_STRING KeyName
;
2381 UNICODE_STRING ValueName
;
2388 DPRINT("IsValidLocale() called\n");
2390 if ((dwFlags
& ~(LCID_SUPPORTED
| LCID_INSTALLED
)) ||
2391 (dwFlags
== (LCID_SUPPORTED
| LCID_INSTALLED
)))
2393 DPRINT("Invalid flags: %lx\n", dwFlags
);
2397 if (Locale
& 0xFFFF0000)
2399 RtlInitUnicodeString(&KeyName
,
2400 L
"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Nls\\Locale\\Alternate Sorts");
2404 RtlInitUnicodeString(&KeyName
,
2405 L
"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Nls\\Locale");
2408 InitializeObjectAttributes(&ObjectAttributes
,
2410 OBJ_CASE_INSENSITIVE
,
2414 Status
= NtOpenKey(&KeyHandle
,
2417 if (!NT_SUCCESS(Status
))
2419 DPRINT("NtOpenKey() failed (Status %lx)\n", Status
);
2423 swprintf(ValueNameBuffer
, L
"%08lx", (ULONG
)Locale
);
2424 RtlInitUnicodeString(&ValueName
, ValueNameBuffer
);
2426 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4 * sizeof(WCHAR
);
2427 KeyInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
2430 if (KeyInfo
== NULL
)
2432 DPRINT("RtlAllocateHeap() failed (Status %lx)\n", Status
);
2437 Status
= NtQueryValueKey(KeyHandle
,
2439 KeyValuePartialInformation
,
2445 if (!NT_SUCCESS(Status
))
2447 DPRINT("NtQueryValueKey() failed (Status %lx)\n", Status
);
2448 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo
);
2452 if (dwFlags
& LCID_SUPPORTED
)
2454 DPRINT("Locale is supported\n");
2455 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo
);
2459 ValueData
= (PWSTR
)&KeyInfo
->Data
[0];
2460 if ((KeyInfo
->Type
== REG_SZ
) &&
2461 (KeyInfo
->DataLength
== 2 * sizeof(WCHAR
)) &&
2462 (ValueData
[0] == L
'1'))
2464 DPRINT("Locale is supported and installed\n");
2465 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo
);
2469 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo
);
2471 DPRINT("IsValidLocale() called\n");
2490 WCHAR
*bufW
= NtCurrentTeb()->StaticUnicodeBuffer
;
2492 INT ret
= 0, srclenW
, dstlenW
;
2493 UINT locale_cp
= CP_ACP
;
2495 if (!lpSrcStr
|| !cchSrc
|| cchDest
< 0)
2497 SetLastError(ERROR_INVALID_PARAMETER
);
2501 if (!(dwMapFlags
& LOCALE_USE_CP_ACP
)) locale_cp
= get_lcid_codepage(Locale
);
2503 srclenW
= MultiByteToWideChar(locale_cp
, 0, lpSrcStr
, cchSrc
, bufW
, 260);
2508 srclenW
= MultiByteToWideChar(locale_cp
, 0, lpSrcStr
, cchSrc
, NULL
, 0);
2509 srcW
= HeapAlloc(GetProcessHeap(), 0, srclenW
* sizeof(WCHAR
));
2512 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2515 MultiByteToWideChar(locale_cp
, 0, lpSrcStr
, cchSrc
, srcW
, srclenW
);
2518 if (dwMapFlags
& LCMAP_SORTKEY
)
2520 if (lpSrcStr
== lpDestStr
)
2522 SetLastError(ERROR_INVALID_FLAGS
);
2523 goto map_string_exit
;
2525 ret
= wine_get_sortkey(dwMapFlags
, srcW
, srclenW
, lpDestStr
, cchDest
);
2527 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2528 goto map_string_exit
;
2531 if (dwMapFlags
& SORT_STRINGSORT
)
2533 SetLastError(ERROR_INVALID_FLAGS
);
2534 goto map_string_exit
;
2537 dstlenW
= LCMapStringW(Locale
, dwMapFlags
, srcW
, srclenW
, NULL
, 0);
2539 goto map_string_exit
;
2541 dstW
= HeapAlloc(GetProcessHeap(), 0, dstlenW
* sizeof(WCHAR
));
2544 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2545 goto map_string_exit
;
2548 LCMapStringW(Locale
, dwMapFlags
, srcW
, srclenW
, dstW
, dstlenW
);
2549 ret
= WideCharToMultiByte(locale_cp
, 0, dstW
, dstlenW
, lpDestStr
, cchDest
, NULL
, NULL
);
2550 HeapFree(GetProcessHeap(), 0, dstW
);
2553 if (srcW
!= bufW
) HeapFree(GetProcessHeap(), 0, srcW
);
2574 if (!lpSrcStr
|| !cchSrc
|| cchDest
< 0)
2576 SetLastError(ERROR_INVALID_PARAMETER
);
2580 /* mutually exclusive flags */
2581 if ((dwMapFlags
& (LCMAP_LOWERCASE
| LCMAP_UPPERCASE
)) == (LCMAP_LOWERCASE
| LCMAP_UPPERCASE
) ||
2582 (dwMapFlags
& (LCMAP_HIRAGANA
| LCMAP_KATAKANA
)) == (LCMAP_HIRAGANA
| LCMAP_KATAKANA
) ||
2583 (dwMapFlags
& (LCMAP_HALFWIDTH
| LCMAP_FULLWIDTH
)) == (LCMAP_HALFWIDTH
| LCMAP_FULLWIDTH
) ||
2584 (dwMapFlags
& (LCMAP_TRADITIONAL_CHINESE
| LCMAP_SIMPLIFIED_CHINESE
)) == (LCMAP_TRADITIONAL_CHINESE
| LCMAP_SIMPLIFIED_CHINESE
))
2586 SetLastError(ERROR_INVALID_FLAGS
);
2590 if (!cchDest
) lpDestStr
= NULL
;
2592 Locale
= ConvertDefaultLocale(Locale
);
2594 if (dwMapFlags
& LCMAP_SORTKEY
)
2597 if (lpSrcStr
== lpDestStr
)
2599 SetLastError(ERROR_INVALID_FLAGS
);
2603 if (cchSrc
< 0) cchSrc
= wcslen(lpSrcStr
);
2605 ret
= wine_get_sortkey(dwMapFlags
, lpSrcStr
, cchSrc
, (char *)lpDestStr
, cchDest
);
2607 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2611 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
2612 if (dwMapFlags
& SORT_STRINGSORT
)
2614 SetLastError(ERROR_INVALID_FLAGS
);
2618 if (cchSrc
< 0) cchSrc
= wcslen(lpSrcStr
) + 1;
2620 if (!lpDestStr
) /* return required string length */
2624 for (len
= 0; cchSrc
; lpSrcStr
++, cchSrc
--)
2626 WCHAR wch
= *lpSrcStr
;
2627 /* tests show that win2k just ignores NORM_IGNORENONSPACE,
2628 * and skips white space and punctuation characters for
2629 * NORM_IGNORESYMBOLS.
2631 if ((dwMapFlags
& NORM_IGNORESYMBOLS
) && (iswctype(wch
, _SPACE
| _PUNCT
)))
2638 if (dwMapFlags
& LCMAP_UPPERCASE
)
2640 for (dst_ptr
= lpDestStr
; cchSrc
&& cchDest
; lpSrcStr
++, cchSrc
--)
2642 WCHAR wch
= *lpSrcStr
;
2643 if ((dwMapFlags
& NORM_IGNORESYMBOLS
) && (iswctype(wch
, _SPACE
| _PUNCT
)))
2645 *dst_ptr
++ = towupper(wch
);
2649 else if (dwMapFlags
& LCMAP_LOWERCASE
)
2651 for (dst_ptr
= lpDestStr
; cchSrc
&& cchDest
; lpSrcStr
++, cchSrc
--)
2653 WCHAR wch
= *lpSrcStr
;
2654 if ((dwMapFlags
& NORM_IGNORESYMBOLS
) && (iswctype(wch
, _SPACE
| _PUNCT
)))
2656 *dst_ptr
++ = towlower(wch
);
2662 if (lpSrcStr
== lpDestStr
)
2664 SetLastError(ERROR_INVALID_FLAGS
);
2667 for (dst_ptr
= lpDestStr
; cchSrc
&& cchDest
; lpSrcStr
++, cchSrc
--)
2669 WCHAR wch
= *lpSrcStr
;
2670 if ((dwMapFlags
& NORM_IGNORESYMBOLS
) && (iswctype(wch
, _SPACE
| _PUNCT
)))
2679 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2683 return dst_ptr
- lpDestStr
;
2698 if (!Locale
|| !lpCalData
)
2700 SetLastError(ERROR_INVALID_PARAMETER
);
2706 case CAL_NOUSEROVERRIDE
:
2707 case CAL_RETURN_NUMBER
:
2708 case CAL_USE_CP_ACP
:
2711 SetLastError(ERROR_INVALID_FLAGS
);
2715 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2730 if (!Locale
|| !lpCalData
)
2732 SetLastError(ERROR_INVALID_PARAMETER
);
2738 case CAL_NOUSEROVERRIDE
:
2739 case CAL_RETURN_NUMBER
:
2740 case CAL_USE_CP_ACP
:
2743 SetLastError(ERROR_INVALID_FLAGS
);
2747 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2752 /**********************************************************************
2754 * RIPPED FROM WINE's dlls\kernel\locale.c ver 0.9.29
2756 * SetLocaleInfoA (KERNEL32.@)
2758 * Set the current locale info.
2761 * Locale [I] LCID of the locale
2762 * LCType [I] LCTYPE_ flags from "winnls.h"
2763 * lpLCData [I] Information to set
2766 * Success: TRUE. The information given will be returned by GetLocaleInfoA()
2767 * whenever it is called without LOCALE_NOUSEROVERRIDE.
2768 * Failure: FALSE. Use GetLastError() to determine the cause.
2778 UINT codepage
= CP_ACP
;
2783 if (!(LCType
& LOCALE_USE_CP_ACP
)) codepage
= get_lcid_codepage( Locale
);
2787 SetLastError( ERROR_INVALID_PARAMETER
);
2790 len
= MultiByteToWideChar( codepage
, 0, lpLCData
, -1, NULL
, 0 );
2791 if (!(strW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
2793 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
2796 MultiByteToWideChar( codepage
, 0, lpLCData
, -1, strW
, len
);
2797 ret
= SetLocaleInfoW( Locale
, LCType
, strW
);
2798 HeapFree( GetProcessHeap(), 0, strW
);
2803 /**********************************************************************
2805 * RIPPED FROM WINE's dlls\kernel\locale.c ver 0.9.29
2807 * SetLocaleInfoW (KERNEL32.@)
2809 * See SetLocaleInfoA.
2821 UNICODE_STRING valueW
;
2826 value
= RosGetLocaleValueName( LCType
);
2828 if (!lpLCData
|| !value
)
2830 SetLastError( ERROR_INVALID_PARAMETER
);
2834 if (LCType
== LOCALE_IDATE
|| LCType
== LOCALE_ILDATE
)
2836 SetLastError( ERROR_INVALID_FLAGS
);
2840 if (!(hkey
= RosCreateRegistryKey())) return FALSE
;
2841 RtlInitUnicodeString( &valueW
, value
);
2842 status
= NtSetValueKey( hkey
, &valueW
, 0, REG_SZ
, (PVOID
)lpLCData
, (lstrlenW(lpLCData
)+1)*sizeof(WCHAR
) );
2844 if (LCType
== LOCALE_SSHORTDATE
|| LCType
== LOCALE_SLONGDATE
)
2846 /* Set I-value from S value */
2847 WCHAR
*lpD
, *lpM
, *lpY
;
2850 lpD
= wcschr(lpLCData
, 'd');
2851 lpM
= wcschr(lpLCData
, 'M');
2852 lpY
= wcschr(lpLCData
, 'y');
2856 szBuff
[0] = '1'; /* D-M-Y */
2861 szBuff
[0] = '2'; /* Y-M-D */
2863 szBuff
[0] = '0'; /* M-D-Y */
2868 if (LCType
== LOCALE_SSHORTDATE
)
2869 LCType
= LOCALE_IDATE
;
2871 LCType
= LOCALE_ILDATE
;
2873 value
= RosGetLocaleValueName( LCType
);
2875 RtlInitUnicodeString( &valueW
, value
);
2876 status
= NtSetValueKey( hkey
, &valueW
, 0, REG_SZ
, szBuff
, sizeof(szBuff
) );
2881 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
2886 /**********************************************************************
2888 * RIPPED FROM WINE's dlls\kernel\locale.c rev 1.42
2890 * SetThreadLocale (KERNEL32.@)
2892 * Set the current threads locale.
2895 * lcid [I] LCID of the locale to set
2898 * Success: TRUE. The threads locale is set to lcid.
2899 * Failure: FALSE. Use GetLastError() to determine the cause.
2902 BOOL WINAPI
SetThreadLocale( LCID lcid
)
2904 DPRINT("SetThreadLocale(0x%04lX)\n", lcid
);
2906 lcid
= ConvertDefaultLocale(lcid
);
2908 if (lcid
!= GetThreadLocale())
2910 if (!IsValidLocale(lcid
, LCID_SUPPORTED
))
2912 SetLastError(ERROR_INVALID_PARAMETER
);
2916 NtCurrentTeb()->CurrentLocale
= lcid
;
2917 /* FIXME: NtCurrentTeb()->code_page = get_lcid_codepage( lcid );
2918 * Wine save the acp for easy/fast access, but ROS has no such Teb member.
2919 * Maybe add this member to ros as well?
2923 Lag test app for å se om locale etc, endres i en app. etter at prosessen er
2924 startet, eller om bare nye prosesser blir berørt.
2935 SetUserDefaultLCID(LCID lcid
)
2939 Status
= NtSetDefaultLocale(TRUE
, lcid
);
2940 if (!NT_SUCCESS(Status
))
2942 SetLastErrorByStatus(Status
);
2953 SetUserDefaultUILanguage(LANGID LangId
)
2957 Status
= NtSetDefaultUILanguage(LangId
);
2958 if (!NT_SUCCESS(Status
))
2960 SetLastErrorByStatus(Status
);
2975 static const WCHAR geoW
[] = {'G','e','o',0};
2976 static const WCHAR nationW
[] = {'N','a','t','i','o','n',0};
2977 static const WCHAR formatW
[] = {'%','i',0};
2978 UNICODE_STRING nameW
,keyW
;
2980 OBJECT_ATTRIBUTES attr
;
2983 if(!(hkey
= create_registry_key())) return FALSE
;
2985 attr
.Length
= sizeof(attr
);
2986 attr
.RootDirectory
= hkey
;
2987 attr
.ObjectName
= &nameW
;
2988 attr
.Attributes
= 0;
2989 attr
.SecurityDescriptor
= NULL
;
2990 attr
.SecurityQualityOfService
= NULL
;
2991 RtlInitUnicodeString( &nameW
, geoW
);
2992 RtlInitUnicodeString( &keyW
, nationW
);
2994 if (NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
)
2997 NtClose(attr
.RootDirectory
);
3001 swprintf(bufferW
, formatW
, GeoId
);
3002 NtSetValueKey(hkey
, &keyW
, 0, REG_SZ
, bufferW
, (wcslen(bufferW
) + 1) * sizeof(WCHAR
));
3003 NtClose(attr
.RootDirectory
);
3020 return GetLocaleInfoA( MAKELCID(wLang
, SORT_DEFAULT
), LOCALE_SENGLANGUAGE
, szLang
, nSize
);
3035 return GetLocaleInfoW( MAKELCID(wLang
, SORT_DEFAULT
), LOCALE_SENGLANGUAGE
, szLang
, nSize
);