3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT : ReactOS user mode libraries
5 * MODULE : kernel32.dll
6 * FILE : reactos/lib/kernel32/misc/lang.c
13 #include "../include/debug.h"
15 /* FIXME: these are included in winnls.h, however including this file causes alot of
16 conflicting type errors. */
18 #define LOCALE_SYEARMONTH 0x1006
19 #define LOCALE_IPAPERSIZE 0x100A
20 #define LOCALE_RETURN_NUMBER 0x20000000
21 #define LOCALE_USE_CP_ACP 0x40000000
22 #define LOCALE_LOCALEINFOFLAGSMASK (LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP|LOCALE_RETURN_NUMBER)
24 //static LCID SystemLocale = MAKELCID(LANG_ENGLISH, SORT_DEFAULT);
26 //static RTL_CRITICAL_SECTION LocalesListLock;
28 /******************************************************************************
30 * RIPPED FROM WINE's dlls\kernel\locale.c rev 1.42
32 * ConvertDefaultLocale (KERNEL32.@)
34 * Convert a default locale identifier into a real identifier.
37 * lcid [I] LCID identifier of the locale to convert
40 * lcid unchanged, if not a default locale or its sublanguage is
41 * not SUBLANG_NEUTRAL.
42 * GetSystemDefaultLCID(), if lcid == LOCALE_SYSTEM_DEFAULT.
43 * GetUserDefaultLCID(), if lcid == LOCALE_USER_DEFAULT or LOCALE_NEUTRAL.
44 * Otherwise, lcid with sublanguage changed to SUBLANG_DEFAULT.
47 ConvertDefaultLocale(LCID lcid
)
53 case LOCALE_SYSTEM_DEFAULT
:
54 lcid
= GetSystemDefaultLCID();
57 case LOCALE_USER_DEFAULT
:
59 lcid
= GetUserDefaultLCID();
63 /* Replace SUBLANG_NEUTRAL with SUBLANG_DEFAULT */
64 langid
= LANGIDFROMLCID(lcid
);
65 if (SUBLANGID(langid
) == SUBLANG_NEUTRAL
)
67 langid
= MAKELANGID(PRIMARYLANGID(langid
), SUBLANG_DEFAULT
);
68 lcid
= MAKELCID(langid
, SORTIDFROMLCID(lcid
));
82 CALINFO_ENUMPROCEXA lpCalInfoEnumProcEx
,
87 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
98 CALINFO_ENUMPROCEXW lpCalInfoEnumProcEx
,
103 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
116 DATEFMT_ENUMPROCEXA lpDateFmtEnumProcEx
,
120 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
131 DATEFMT_ENUMPROCEXW lpDateFmtEnumProcEx
,
135 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
145 EnumLanguageGroupLocalesA(
146 LANGGROUPLOCALE_ENUMPROCA lpLangGroupLocaleEnumProc
,
147 LGRPID LanguageGroup
,
151 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
161 EnumLanguageGroupLocalesW(
162 LANGGROUPLOCALE_ENUMPROCW lpLangGroupLocaleEnumProc
,
163 LGRPID LanguageGroup
,
167 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
177 EnumSystemCodePagesW (
178 CODEPAGE_ENUMPROCW lpCodePageEnumProc
,
182 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
192 EnumSystemCodePagesA (
193 CODEPAGE_ENUMPROCA lpCodePageEnumProc
,
197 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
210 GEO_ENUMPROC lpGeoEnumProc
)
214 SetLastError(ERROR_INVALID_PARAMETER
);
220 case GEOCLASS_NATION
:
221 /*RtlEnterCriticalSection(&DllLock);
223 FIXME - Get GEO IDs calling Csr
225 RtlLeaveCriticalSection(&DllLock);*/
227 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
231 SetLastError(ERROR_INVALID_FLAGS
);
244 EnumSystemLanguageGroupsA(
245 LANGUAGEGROUP_ENUMPROCA pLangGroupEnumProc
,
249 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
259 EnumSystemLanguageGroupsW(
260 LANGUAGEGROUP_ENUMPROCW pLangGroupEnumProc
,
264 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
275 LOCALE_ENUMPROCA lpLocaleEnumProc
,
279 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
290 LOCALE_ENUMPROCW lpLocaleEnumProc
,
296 UNICODE_STRING langKeyName
= RTL_CONSTANT_STRING(
297 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\Locale");
298 OBJECT_ATTRIBUTES objectAttributes
;
300 unsigned char fullInfo
[sizeof(KEY_VALUE_FULL_INFORMATION
)+255*2]; //FIXME: MAX_PATH*2
301 PKEY_VALUE_FULL_INFORMATION pFullInfo
;
303 //TODO: Combine with EnumSystemLocalesA - maybe by having one common part, driven by some
304 // unicode/non-unicode flag.
306 //FIXME: dwFlags is really not used, sorry
308 // Check if enum proc is a real one
309 if (lpLocaleEnumProc
== NULL
)
311 SetLastError(ERROR_INVALID_PARAMETER
);
315 // Open language registry key
316 //FIXME: Should we use critical section here?
318 InitializeObjectAttributes(&objectAttributes
,
320 OBJ_CASE_INSENSITIVE
,
324 result
= NtOpenKey(&langKey
,
328 if (!NT_SUCCESS(result
))
331 DPRINT1("Registry key succesfully opened\n");
333 length
= sizeof(KEY_VALUE_FULL_INFORMATION
) + 255*2;//MAX_PATH*sizeof(WCHAR);
334 pFullInfo
= (PKEY_VALUE_FULL_INFORMATION
)&fullInfo
;
335 RtlZeroMemory(pFullInfo
, length
);
339 result
= NtEnumerateValueKey(langKey
,
341 KeyValueFullInformation
,
346 DPRINT1("First enumerate call result=%x\n", result
);
347 while (result
!= STATUS_NO_MORE_ENTRIES
)
352 // TODO: Here we should check, in case dwFlags & LCID_INSTALLED is specified,
353 // if this locale is really installed
354 // but for now we skip it
357 lpLocale
[i
] = pFullInfo
->Name
[i
];
361 DPRINT1("Locale=%S\n", lpLocale
);
364 if (!lpLocaleEnumProc((LPWSTR
)lpLocale
))
367 // Zero previous values
368 RtlZeroMemory(pFullInfo
, length
);
371 result
= NtEnumerateValueKey(langKey
, index
,KeyValueFullInformation
, pFullInfo
, length
, &length
);
376 return STATUS_SUCCESS
;
386 UILANGUAGE_ENUMPROCA lpUILanguageEnumProc
,
390 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
401 UILANGUAGE_ENUMPROCW lpUILanguageEnumProc
,
405 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
422 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
440 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
452 LPCPINFO CodePageInfo
457 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
459 CodePageInfo
->MaxCharSize
= 1;
460 CodePageInfo
->DefaultChar
[0] = '?';
461 for (i
= 1; i
< MAX_DEFAULTCHAR
; i
++)
463 CodePageInfo
->DefaultChar
[i
] = 0;
465 for (i
= 0; i
< MAX_LEADBYTES
; i
++)
467 CodePageInfo
->LeadByte
[i
] = 0;
482 LPCPINFOEXW lpCPInfoEx
)
484 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
497 LPCPINFOEXA lpCPInfoEx
)
499 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
516 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
533 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
537 const WCHAR
*RosGetLocaleValueName( DWORD lctype
)
539 switch (lctype
& ~LOCALE_LOCALEINFOFLAGSMASK
)
541 /* These values are used by SetLocaleInfo and GetLocaleInfo, and
542 * the values are stored in the registry, confirmed under Windows.
544 case LOCALE_ICALENDARTYPE
: return L
"iCalendarType";
545 case LOCALE_ICURRDIGITS
: return L
"iCurrDigits";
546 case LOCALE_ICURRENCY
: return L
"iCurrency";
547 case LOCALE_IDIGITS
: return L
"iDigits";
548 case LOCALE_IFIRSTDAYOFWEEK
: return L
"iFirstDayOfWeek";
549 case LOCALE_IFIRSTWEEKOFYEAR
: return L
"iFirstWeekOfYear";
550 case LOCALE_ILZERO
: return L
"iLZero";
551 case LOCALE_IMEASURE
: return L
"iMeasure";
552 case LOCALE_INEGCURR
: return L
"iNegCurr";
553 case LOCALE_INEGNUMBER
: return L
"iNegNumber";
554 case LOCALE_IPAPERSIZE
: return L
"iPaperSize";
555 case LOCALE_ITIME
: return L
"iTime";
556 case LOCALE_S1159
: return L
"s1159";
557 case LOCALE_S2359
: return L
"s2359";
558 case LOCALE_SCURRENCY
: return L
"sCurrency";
559 case LOCALE_SDATE
: return L
"sDate";
560 case LOCALE_SDECIMAL
: return L
"sDecimal";
561 case LOCALE_SGROUPING
: return L
"sGrouping";
562 case LOCALE_SLIST
: return L
"sList";
563 case LOCALE_SLONGDATE
: return L
"sLongDate";
564 case LOCALE_SMONDECIMALSEP
: return L
"sMonDecimalSep";
565 case LOCALE_SMONGROUPING
: return L
"sMonGrouping";
566 case LOCALE_SMONTHOUSANDSEP
: return L
"sMonThousandSep";
567 case LOCALE_SNEGATIVESIGN
: return L
"sNegativeSign";
568 case LOCALE_SPOSITIVESIGN
: return L
"sPositiveSign";
569 case LOCALE_SSHORTDATE
: return L
"sShortDate";
570 case LOCALE_STHOUSAND
: return L
"sThousand";
571 case LOCALE_STIME
: return L
"sTime";
572 case LOCALE_STIMEFORMAT
: return L
"sTimeFormat";
573 case LOCALE_SYEARMONTH
: return L
"sYearMonth";
575 /* The following are not listed under MSDN as supported,
576 * but seem to be used and also stored in the registry.
578 case LOCALE_ICOUNTRY
: return L
"iCountry";
579 case LOCALE_IDATE
: return L
"iDate";
580 case LOCALE_ILDATE
: return L
"iLDate";
581 case LOCALE_ITLZERO
: return L
"iTLZero";
582 case LOCALE_SCOUNTRY
: return L
"sCountry";
583 case LOCALE_SLANGUAGE
: return L
"sLanguage";
588 HKEY
RosCreateRegistryKey(void)
590 OBJECT_ATTRIBUTES objAttr
;
591 UNICODE_STRING nameW
;
594 if (RtlOpenCurrentUser( KEY_ALL_ACCESS
, &hKey
) != STATUS_SUCCESS
) return 0;
596 objAttr
.Length
= sizeof(objAttr
);
597 objAttr
.RootDirectory
= hKey
;
598 objAttr
.ObjectName
= &nameW
;
599 objAttr
.Attributes
= 0;
600 objAttr
.SecurityDescriptor
= NULL
;
601 objAttr
.SecurityQualityOfService
= NULL
;
602 RtlInitUnicodeString( &nameW
, L
"Control Panel\\International");
604 if (NtCreateKey( &hKey
, KEY_ALL_ACCESS
, &objAttr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
) hKey
= 0;
605 NtClose( objAttr
.RootDirectory
);
609 INT
RosGetRegistryLocaleInfo( LPCWSTR lpValue
, LPWSTR lpBuffer
, INT nLen
)
615 UNICODE_STRING usNameW
;
616 KEY_VALUE_PARTIAL_INFORMATION
*kvpiInfo
;
617 const int nInfoSize
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
);
619 if (!(hKey
= RosCreateRegistryKey())) return -1;
621 RtlInitUnicodeString( &usNameW
, lpValue
);
622 dwSize
= nInfoSize
+ nLen
* sizeof(WCHAR
);
624 if (!(kvpiInfo
= HeapAlloc( GetProcessHeap(), 0, dwSize
)))
627 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
631 ntStatus
= NtQueryValueKey( hKey
, &usNameW
, KeyValuePartialInformation
, kvpiInfo
, dwSize
, &dwSize
);
632 if (ntStatus
== STATUS_BUFFER_OVERFLOW
&& !lpBuffer
) ntStatus
= 0;
636 nRet
= (dwSize
- nInfoSize
) / sizeof(WCHAR
);
638 if (!nRet
|| ((WCHAR
*)kvpiInfo
->Data
)[nRet
- 1])
640 if (nRet
< nLen
|| !lpBuffer
) nRet
++;
643 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
647 if (nRet
&& lpBuffer
)
649 memcpy( lpBuffer
, kvpiInfo
->Data
, (nRet
- 1) * sizeof(WCHAR
) );
650 lpBuffer
[nRet
- 1] = 0;
655 if (ntStatus
== STATUS_OBJECT_NAME_NOT_FOUND
) nRet
= -1;
658 SetLastError( RtlNtStatusToDosError(ntStatus
) );
663 HeapFree( GetProcessHeap(), 0, kvpiInfo
);
688 if (cchData
< 0 || (cchData
&& !lpLCData
))
690 SetLastError( ERROR_INVALID_PARAMETER
);
693 if (!cchData
) lpLCData
= NULL
;
695 if (Locale
== LOCALE_NEUTRAL
|| Locale
== LOCALE_SYSTEM_DEFAULT
) Locale
= GetSystemDefaultLCID();
696 else if (Locale
== LOCALE_USER_DEFAULT
) Locale
= GetUserDefaultLCID();
698 uiFlags
= LCType
& LOCALE_LOCALEINFOFLAGSMASK
;
699 LCType
&= ~LOCALE_LOCALEINFOFLAGSMASK
;
701 if (!(uiFlags
& LOCALE_NOUSEROVERRIDE
) && Locale
== GetUserDefaultLCID())
703 const WCHAR
*value
= RosGetLocaleValueName(LCType
);
705 if (value
&& ((nRet
= RosGetRegistryLocaleInfo( value
, lpLCData
, cchData
)) != -1)) return nRet
;
708 liLangID
= LANGIDFROMLCID( Locale
);
710 if (SUBLANGID(liLangID
) == SUBLANG_NEUTRAL
)
711 liLangID
= MAKELANGID(PRIMARYLANGID(liLangID
), SUBLANG_DEFAULT
);
713 hModule
= GetModuleHandleW( L
"kernel32.dll" );
714 if (!(hRsrc
= FindResourceExW( hModule
, (LPWSTR
)RT_STRING
, (LPCWSTR
)((LCType
>> 4) + 1), liLangID
)))
716 SetLastError( ERROR_INVALID_FLAGS
);
719 if (!(hMem
= LoadResource( hModule
, hRsrc
)))
722 ch
= LockResource( hMem
);
723 for (i
= 0; i
< (int)(LCType
& 0x0f); i
++) ch
+= *ch
+ 1;
725 if (uiFlags
& LOCALE_RETURN_NUMBER
) nRet
= sizeof(UINT
) / sizeof(WCHAR
);
726 else nRet
= (LCType
== LOCALE_FONTSIGNATURE
) ? *ch
: *ch
+ 1;
728 if (!lpLCData
) return nRet
;
732 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
736 if (uiFlags
& LOCALE_RETURN_NUMBER
)
739 WCHAR
*chEnd
, *chTmp
= HeapAlloc( GetProcessHeap(), 0, (*ch
+ 1) * sizeof(WCHAR
) );
744 memcpy( chTmp
, ch
+ 1, *ch
* sizeof(WCHAR
) );
746 uiNum
= wcstol( chTmp
, &chEnd
, 10 );
749 memcpy( lpLCData
, &uiNum
, sizeof(uiNum
) );
752 SetLastError( ERROR_INVALID_FLAGS
);
755 HeapFree( GetProcessHeap(), 0, chTmp
);
759 memcpy( lpLCData
, ch
+ 1, *ch
* sizeof(WCHAR
) );
760 if (LCType
!= LOCALE_FONTSIGNATURE
) lpLCData
[nRet
-1] = 0;
767 /***********************************************************************
770 * Retrieve the ANSI codepage for a given locale.
772 inline static UINT
get_lcid_codepage( LCID lcid
)
775 if (!GetLocaleInfoW( lcid
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
, (WCHAR
*)&ret
,
776 sizeof(ret
)/sizeof(WCHAR
) )) ret
= 0;
795 WCHAR
*buf1W
= NtCurrentTeb()->StaticUnicodeBuffer
;
796 WCHAR
*buf2W
= buf1W
+ 130;
798 INT len1W
, len2W
, ret
;
801 if (!lpString1
|| !lpString2
)
803 SetLastError(ERROR_INVALID_PARAMETER
);
806 if (cchCount1
< 0) cchCount1
= strlen(lpString1
);
807 if (cchCount2
< 0) cchCount2
= strlen(lpString2
);
809 locale_cp
= get_lcid_codepage(Locale
);
811 len1W
= MultiByteToWideChar(locale_cp
, 0, lpString1
, cchCount1
, buf1W
, 130);
816 len1W
= MultiByteToWideChar(locale_cp
, 0, lpString1
, cchCount1
, NULL
, 0);
817 str1W
= HeapAlloc(GetProcessHeap(), 0, len1W
* sizeof(WCHAR
));
820 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
823 MultiByteToWideChar(locale_cp
, 0, lpString1
, cchCount1
, str1W
, len1W
);
825 len2W
= MultiByteToWideChar(locale_cp
, 0, lpString2
, cchCount2
, buf2W
, 130);
830 len2W
= MultiByteToWideChar(locale_cp
, 0, lpString2
, cchCount2
, NULL
, 0);
831 str2W
= HeapAlloc(GetProcessHeap(), 0, len2W
* sizeof(WCHAR
));
834 if (str1W
!= buf1W
) HeapFree(GetProcessHeap(), 0, str1W
);
835 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
838 MultiByteToWideChar(locale_cp
, 0, lpString2
, cchCount2
, str2W
, len2W
);
841 ret
= CompareStringW(Locale
, dwCmpFlags
, str1W
, len1W
, str2W
, len2W
);
843 if (str1W
!= buf1W
) HeapFree(GetProcessHeap(), 0, str1W
);
844 if (str2W
!= buf2W
) HeapFree(GetProcessHeap(), 0, str2W
);
849 static int compare_unicode_string(
850 PUNICODE_STRING String1
,
851 PUNICODE_STRING String2
,
859 if (String1
&& String2
)
861 len1
= String1
->Length
/ sizeof(WCHAR
);
862 len2
= String2
->Length
/ sizeof(WCHAR
);
863 s1
= String1
->Buffer
;
864 s2
= String2
->Buffer
;
866 while (len1
> 0 && len2
> 0)
868 if (Flags
& NORM_IGNORESYMBOLS
)
871 /* FIXME: not tested */
872 if (iswctype(*s1
, _SPACE
| _PUNCT
))
878 if (iswctype(*s2
, _SPACE
| _PUNCT
))
887 /* hyphen and apostrophe are treated differently depending on
888 * whether SORT_STRINGSORT specified or not
890 if (!(Flags
& SORT_STRINGSORT
))
892 if (*s1
== '-' || *s1
== '\'')
894 if (*s2
!= '-' && *s2
!= '\'')
901 else if (*s2
== '-' || *s2
== '\'')
908 if (Flags
& NORM_IGNORECASE
)
910 c1
= len1
-- ? RtlUpcaseUnicodeChar(*s1
++) : 0;
911 c2
= len2
-- ? RtlUpcaseUnicodeChar(*s2
++) : 0;
912 if (!c1
|| !c2
|| c1
!= c2
)
917 c1
= len1
-- ? *s1
++ : 0;
918 c2
= len2
-- ? *s2
++ : 0;
919 if (!c1
|| !c2
|| c1
!= c2
)
943 UNICODE_STRING String1
, String2
;
945 if (!lpString1
|| !lpString2
)
947 SetLastError(ERROR_INVALID_PARAMETER
);
951 if (dwCmpFlags
& ~(NORM_IGNORECASE
| NORM_IGNORENONSPACE
|
952 NORM_IGNORESYMBOLS
| SORT_STRINGSORT
| NORM_IGNOREKANATYPE
|
953 NORM_IGNOREWIDTH
| 0x10000000))
955 SetLastError(ERROR_INVALID_FLAGS
);
959 if (cchCount1
< 0) cchCount1
= lstrlenW(lpString1
);
960 if (cchCount2
< 0) cchCount2
= lstrlenW(lpString2
);
962 String1
.Length
= String1
.MaximumLength
= cchCount1
* sizeof(WCHAR
);
963 String1
.Buffer
= (LPWSTR
)lpString1
;
964 String2
.Length
= String2
.MaximumLength
= cchCount2
* sizeof(WCHAR
);
965 String2
.Buffer
= (LPWSTR
)lpString2
;
968 if (dwCmpFlags
& ~NORM_IGNORECASE
)
970 DPRINT1("CompareString: STUB flags - 0x%x\n", dwCmpFlags
);
971 Result
= compare_unicode_string(&String1
, &String2
, dwCmpFlags
);
974 Result
= RtlCompareUnicodeString(
975 &String1
, &String2
, dwCmpFlags
& NORM_IGNORECASE
);
978 if (Result
) /* need to translate result */
979 return (Result
< 0) ? CSTR_LESS_THAN
: CSTR_GREATER_THAN
;
990 * Get information about an aspect of a locale.
993 * lcid [I] LCID of the locale
994 * lctype [I] LCTYPE_ flags from "winnls.h"
995 * buffer [O] Destination for the information
996 * len [I] Length of buffer in characters
999 * Success: The size of the data requested. If buffer is non-NULL, it is filled
1000 * with the information.
1001 * Failure: 0. Use GetLastError() to determine the cause.
1004 * - LOCALE_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT
1005 * - The string returned is NUL terminated, except for LOCALE_FONTSIGNATURE,
1006 * which is a bit string.
1008 INT STDCALL
GetLocaleInfoA( LCID lcid
, LCTYPE lctype
, LPSTR buffer
, INT len
)
1013 if (len
< 0 || (len
&& !buffer
))
1015 SetLastError( ERROR_INVALID_PARAMETER
);
1018 if (!len
) buffer
= NULL
;
1020 if (!(lenW
= GetLocaleInfoW( lcid
, lctype
, NULL
, 0 ))) return 0;
1022 if (!(bufferW
= HeapAlloc( GetProcessHeap(), 0, lenW
* sizeof(WCHAR
) )))
1024 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1027 if ((ret
= GetLocaleInfoW( lcid
, lctype
, bufferW
, lenW
)))
1029 if ((lctype
& LOCALE_RETURN_NUMBER
) ||
1030 ((lctype
& ~LOCALE_LOCALEINFOFLAGSMASK
) == LOCALE_FONTSIGNATURE
))
1032 /* it's not an ASCII string, just bytes */
1033 ret
*= sizeof(WCHAR
);
1036 if (ret
<= len
) memcpy( buffer
, bufferW
, ret
);
1039 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1046 UINT codepage
= CP_ACP
;
1047 if (!(lctype
& LOCALE_USE_CP_ACP
)) codepage
= get_lcid_codepage( lcid
);
1048 ret
= WideCharToMultiByte( codepage
, 0, bufferW
, ret
, buffer
, len
, NULL
, NULL
);
1051 HeapFree( GetProcessHeap(), 0, bufferW
);
1060 GetSystemDefaultLangID(VOID
)
1062 return LANGIDFROMLCID(GetSystemDefaultLCID());
1070 GetSystemDefaultLCID(VOID
)
1074 NtQueryDefaultLocale(FALSE
, &lcid
);
1084 GetSystemDefaultUILanguage(VOID
)
1089 Status
= NtQueryInstallUILanguage(&LanguageId
);
1090 if (!NT_SUCCESS(Status
))
1092 SetLastErrorByStatus(Status
);
1104 GetThreadLocale(VOID
)
1106 return NtCurrentTeb()->CurrentLocale
;
1114 GetUserDefaultLangID(VOID
)
1116 return LANGIDFROMLCID(GetUserDefaultLCID());
1124 GetUserDefaultLCID(VOID
)
1129 Status
= NtQueryDefaultLocale(TRUE
, &lcid
);
1130 if (!NT_SUCCESS(Status
))
1132 SetLastErrorByStatus(Status
);
1144 GetUserDefaultUILanguage(VOID
)
1149 Status
= NtQueryDefaultUILanguage(&LangId
);
1150 if (!NT_SUCCESS(Status
))
1152 SetLastErrorByStatus(Status
);
1168 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1178 IsValidLanguageGroup(
1179 LGRPID LanguageGroup
,
1182 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1187 /******************************************************************************
1190 * Determine if a locale is valid.
1193 * Locale [I] LCID of the locale to check
1194 * dwFlags [I] LCID_SUPPORTED = Valid
1195 * LCID_INSTALLED = Valid and installed on the system
1198 * TRUE, if Locale is valid,
1204 IsValidLocale(LCID Locale
,
1207 OBJECT_ATTRIBUTES ObjectAttributes
;
1208 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo
;
1209 WCHAR ValueNameBuffer
[9];
1210 UNICODE_STRING KeyName
;
1211 UNICODE_STRING ValueName
;
1218 DPRINT("IsValidLocale() called\n");
1220 if ((dwFlags
& ~(LCID_SUPPORTED
| LCID_INSTALLED
)) ||
1221 (dwFlags
== (LCID_SUPPORTED
| LCID_INSTALLED
)))
1223 DPRINT("Invalid flags: %lx\n", dwFlags
);
1227 if (Locale
& 0xFFFF0000)
1229 RtlInitUnicodeString(&KeyName
,
1230 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Nls\\Locale\\Alternate Sorts");
1234 RtlInitUnicodeString(&KeyName
,
1235 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Nls\\Locale");
1238 InitializeObjectAttributes(&ObjectAttributes
,
1240 OBJ_CASE_INSENSITIVE
,
1244 Status
= NtOpenKey(&KeyHandle
,
1247 if (!NT_SUCCESS(Status
))
1249 DPRINT("NtOpenKey() failed (Status %lx)\n", Status
);
1253 swprintf(ValueNameBuffer
, L
"%08lx", (ULONG
)Locale
);
1254 RtlInitUnicodeString(&ValueName
, ValueNameBuffer
);
1256 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4 * sizeof(WCHAR
);
1257 KeyInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
1260 if (KeyInfo
== NULL
)
1262 DPRINT("RtlAllocateHeap() failed (Status %lx)\n", Status
);
1267 Status
= NtQueryValueKey(KeyHandle
,
1269 KeyValuePartialInformation
,
1275 if (!NT_SUCCESS(Status
))
1277 DPRINT("NtQueryValueKey() failed (Status %lx)\n", Status
);
1278 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo
);
1282 if (dwFlags
& LCID_SUPPORTED
)
1284 DPRINT("Locale is supported\n");
1285 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo
);
1289 ValueData
= (PWSTR
)&KeyInfo
->Data
[0];
1290 if ((dwFlags
& LCID_INSTALLED
) &&
1291 (KeyInfo
->Type
== REG_SZ
) &&
1292 (KeyInfo
->DataLength
== 2 * sizeof(WCHAR
)) &&
1293 (ValueData
[0] == L
'1'))
1295 DPRINT("Locale is supported and installed\n");
1296 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo
);
1300 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo
);
1302 DPRINT("IsValidLocale() called\n");
1322 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1341 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1357 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1372 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1388 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1404 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1409 /**********************************************************************
1411 * RIPPED FROM WINE's dlls\kernel\locale.c rev 1.42
1413 * SetThreadLocale (KERNEL32.@)
1415 * Set the current threads locale.
1418 * lcid [I] LCID of the locale to set
1421 * Success: TRUE. The threads locale is set to lcid.
1422 * Failure: FALSE. Use GetLastError() to determine the cause.
1425 BOOL WINAPI
SetThreadLocale( LCID lcid
)
1427 DPRINT("SetThreadLocale(0x%04lX)\n", lcid
);
1429 lcid
= ConvertDefaultLocale(lcid
);
1431 if (lcid
!= GetThreadLocale())
1433 if (!IsValidLocale(lcid
, LCID_SUPPORTED
))
1435 SetLastError(ERROR_INVALID_PARAMETER
);
1439 NtCurrentTeb()->CurrentLocale
= lcid
;
1440 /* FIXME: NtCurrentTeb()->code_page = get_lcid_codepage( lcid );
1441 * Wine save the acp for easy/fast access, but ROS has no such Teb member.
1442 * Maybe add this member to ros as well?
1446 Lag test app for å se om locale etc, endres i en app. etter at prosessen er
1447 startet, eller om bare nye prosesser blir berørt.
1462 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);