1 /* $Id: lang.c,v 1.22 2004/08/26 16:03:09 hbirr Exp $
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 //#define _OLE2NLS_IN_BUILD_
29 /******************************************************************************
31 * RIPPED FROM WINE's dlls\kernel\locale.c rev 1.42
33 * ConvertDefaultLocale (KERNEL32.@)
35 * Convert a default locale identifier into a real identifier.
38 * lcid [I] LCID identifier of the locale to convert
41 * lcid unchanged, if not a default locale or its sublanguage is
42 * not SUBLANG_NEUTRAL.
43 * GetSystemDefaultLCID(), if lcid == LOCALE_SYSTEM_DEFAULT.
44 * GetUserDefaultLCID(), if lcid == LOCALE_USER_DEFAULT or LOCALE_NEUTRAL.
45 * Otherwise, lcid with sublanguage changed to SUBLANG_DEFAULT.
47 LCID WINAPI
ConvertDefaultLocale( LCID lcid
)
53 case LOCALE_SYSTEM_DEFAULT
:
54 lcid
= GetSystemDefaultLCID();
56 case LOCALE_USER_DEFAULT
:
58 lcid
= GetUserDefaultLCID();
61 /* Replace SUBLANG_NEUTRAL with SUBLANG_DEFAULT */
62 langid
= LANGIDFROMLCID(lcid
);
63 if (SUBLANGID(langid
) == SUBLANG_NEUTRAL
)
65 langid
= MAKELANGID(PRIMARYLANGID(langid
), SUBLANG_DEFAULT
);
66 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 lpLanguageGroupEnumProc
,
249 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
254 #ifndef _OLE2NLS_IN_BUILD_
262 LOCALE_ENUMPROCW lpLocaleEnumProc
,
266 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
277 LOCALE_ENUMPROCA lpLocaleEnumProc
,
281 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
296 UILANGUAGE_ENUMPROCA lpUILanguageEnumProc
,
300 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
311 UILANGUAGE_ENUMPROCW lpUILanguageEnumProc
,
315 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
332 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
350 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
355 #ifndef _OLE2NLS_IN_BUILD_
364 LPCPINFO CodePageInfo
369 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
371 CodePageInfo
->MaxCharSize
= 1;
372 CodePageInfo
->DefaultChar
[0] = '?';
373 for (i
= 1; i
< MAX_DEFAULTCHAR
; i
++)
375 CodePageInfo
->DefaultChar
[i
] = 0;
377 for (i
= 0; i
< MAX_LEADBYTES
; i
++)
379 CodePageInfo
->LeadByte
[i
] = 0;
396 LPCPINFOEXW lpCPInfoEx
)
398 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
411 LPCPINFOEXA lpCPInfoEx
)
413 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
430 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
447 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
451 const WCHAR
*RosGetLocaleValueName( DWORD lctype
)
453 switch (lctype
& ~LOCALE_LOCALEINFOFLAGSMASK
)
455 /* These values are used by SetLocaleInfo and GetLocaleInfo, and
456 * the values are stored in the registry, confirmed under Windows.
458 case LOCALE_ICALENDARTYPE
: return L
"iCalendarType";
459 case LOCALE_ICURRDIGITS
: return L
"iCurrDigits";
460 case LOCALE_ICURRENCY
: return L
"iCurrency";
461 case LOCALE_IDIGITS
: return L
"iDigits";
462 case LOCALE_IFIRSTDAYOFWEEK
: return L
"iFirstDayOfWeek";
463 case LOCALE_IFIRSTWEEKOFYEAR
: return L
"iFirstWeekOfYear";
464 case LOCALE_ILZERO
: return L
"iLZero";
465 case LOCALE_IMEASURE
: return L
"iMeasure";
466 case LOCALE_INEGCURR
: return L
"iNegCurr";
467 case LOCALE_INEGNUMBER
: return L
"iNegNumber";
468 case LOCALE_IPAPERSIZE
: return L
"iPaperSize";
469 case LOCALE_ITIME
: return L
"iTime";
470 case LOCALE_S1159
: return L
"s1159";
471 case LOCALE_S2359
: return L
"s2359";
472 case LOCALE_SCURRENCY
: return L
"sCurrency";
473 case LOCALE_SDATE
: return L
"sDate";
474 case LOCALE_SDECIMAL
: return L
"sDecimal";
475 case LOCALE_SGROUPING
: return L
"sGrouping";
476 case LOCALE_SLIST
: return L
"sList";
477 case LOCALE_SLONGDATE
: return L
"sLongDate";
478 case LOCALE_SMONDECIMALSEP
: return L
"sMonDecimalSep";
479 case LOCALE_SMONGROUPING
: return L
"sMonGrouping";
480 case LOCALE_SMONTHOUSANDSEP
: return L
"sMonThousandSep";
481 case LOCALE_SNEGATIVESIGN
: return L
"sNegativeSign";
482 case LOCALE_SPOSITIVESIGN
: return L
"sPositiveSign";
483 case LOCALE_SSHORTDATE
: return L
"sShortDate";
484 case LOCALE_STHOUSAND
: return L
"sThousand";
485 case LOCALE_STIME
: return L
"sTime";
486 case LOCALE_STIMEFORMAT
: return L
"sTimeFormat";
487 case LOCALE_SYEARMONTH
: return L
"sYearMonth";
489 /* The following are not listed under MSDN as supported,
490 * but seem to be used and also stored in the registry.
492 case LOCALE_ICOUNTRY
: return L
"iCountry";
493 case LOCALE_IDATE
: return L
"iDate";
494 case LOCALE_ILDATE
: return L
"iLDate";
495 case LOCALE_ITLZERO
: return L
"iTLZero";
496 case LOCALE_SCOUNTRY
: return L
"sCountry";
497 case LOCALE_SLANGUAGE
: return L
"sLanguage";
502 HKEY
RosCreateRegistryKey(void)
504 OBJECT_ATTRIBUTES objAttr
;
505 UNICODE_STRING nameW
;
508 if (RtlOpenCurrentUser( KEY_ALL_ACCESS
, &hKey
) != STATUS_SUCCESS
) return 0;
510 objAttr
.Length
= sizeof(objAttr
);
511 objAttr
.RootDirectory
= hKey
;
512 objAttr
.ObjectName
= &nameW
;
513 objAttr
.Attributes
= 0;
514 objAttr
.SecurityDescriptor
= NULL
;
515 objAttr
.SecurityQualityOfService
= NULL
;
516 RtlInitUnicodeString( &nameW
, L
"Control Panel\\International");
518 if (NtCreateKey( &hKey
, KEY_ALL_ACCESS
, &objAttr
, 0, NULL
, 0, NULL
) != STATUS_SUCCESS
) hKey
= 0;
519 NtClose( objAttr
.RootDirectory
);
523 INT
RosGetRegistryLocaleInfo( LPCWSTR lpValue
, LPWSTR lpBuffer
, INT nLen
)
529 UNICODE_STRING usNameW
;
530 KEY_VALUE_PARTIAL_INFORMATION
*kvpiInfo
;
531 const int nInfoSize
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
);
533 if (!(hKey
= RosCreateRegistryKey())) return -1;
535 RtlInitUnicodeString( &usNameW
, lpValue
);
536 dwSize
= nInfoSize
+ nLen
* sizeof(WCHAR
);
538 if (!(kvpiInfo
= HeapAlloc( GetProcessHeap(), 0, dwSize
)))
541 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
545 ntStatus
= NtQueryValueKey( hKey
, &usNameW
, KeyValuePartialInformation
, kvpiInfo
, dwSize
, &dwSize
);
546 if (ntStatus
== STATUS_BUFFER_OVERFLOW
&& !lpBuffer
) ntStatus
= 0;
550 nRet
= (dwSize
- nInfoSize
) / sizeof(WCHAR
);
552 if (!nRet
|| ((WCHAR
*)kvpiInfo
->Data
)[nRet
- 1])
554 if (nRet
< nLen
|| !lpBuffer
) nRet
++;
557 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
561 if (nRet
&& lpBuffer
)
563 memcpy( lpBuffer
, kvpiInfo
->Data
, (nRet
- 1) * sizeof(WCHAR
) );
564 lpBuffer
[nRet
- 1] = 0;
569 if (ntStatus
== STATUS_OBJECT_NAME_NOT_FOUND
) nRet
= -1;
572 SetLastError( RtlNtStatusToDosError(ntStatus
) );
577 HeapFree( GetProcessHeap(), 0, kvpiInfo
);
602 if (cchData
< 0 || (cchData
&& !lpLCData
))
604 SetLastError( ERROR_INVALID_PARAMETER
);
607 if (!cchData
) lpLCData
= NULL
;
609 if (Locale
== LOCALE_NEUTRAL
|| Locale
== LOCALE_SYSTEM_DEFAULT
) Locale
= GetSystemDefaultLCID();
610 else if (Locale
== LOCALE_USER_DEFAULT
) Locale
= GetUserDefaultLCID();
612 uiFlags
= LCType
& LOCALE_LOCALEINFOFLAGSMASK
;
613 LCType
&= ~LOCALE_LOCALEINFOFLAGSMASK
;
615 if (!(uiFlags
& LOCALE_NOUSEROVERRIDE
) && Locale
== GetUserDefaultLCID())
617 const WCHAR
*value
= RosGetLocaleValueName(LCType
);
619 if (value
&& ((nRet
= RosGetRegistryLocaleInfo( value
, lpLCData
, cchData
)) != -1)) return nRet
;
622 liLangID
= LANGIDFROMLCID( Locale
);
624 if (SUBLANGID(liLangID
) == SUBLANG_NEUTRAL
)
625 liLangID
= MAKELANGID(PRIMARYLANGID(liLangID
), SUBLANG_DEFAULT
);
627 hModule
= GetModuleHandleW( L
"kernel32.dll" );
628 if (!(hRsrc
= FindResourceExW( hModule
, (LPWSTR
)RT_STRING
, (LPCWSTR
)((LCType
>> 4) + 1), liLangID
)))
630 SetLastError( ERROR_INVALID_FLAGS
);
633 if (!(hMem
= LoadResource( hModule
, hRsrc
)))
636 ch
= LockResource( hMem
);
637 for (i
= 0; i
< (LCType
& 0x0f); i
++) ch
+= *ch
+ 1;
639 if (uiFlags
& LOCALE_RETURN_NUMBER
) nRet
= sizeof(UINT
) / sizeof(WCHAR
);
640 else nRet
= (LCType
== LOCALE_FONTSIGNATURE
) ? *ch
: *ch
+ 1;
642 if (!lpLCData
) return nRet
;
646 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
650 if (uiFlags
& LOCALE_RETURN_NUMBER
)
653 WCHAR
*chEnd
, *chTmp
= HeapAlloc( GetProcessHeap(), 0, (*ch
+ 1) * sizeof(WCHAR
) );
658 memcpy( chTmp
, ch
+ 1, *ch
* sizeof(WCHAR
) );
660 uiNum
= wcstol( chTmp
, &chEnd
, 10 );
663 memcpy( lpLCData
, &uiNum
, sizeof(uiNum
) );
666 SetLastError( ERROR_INVALID_FLAGS
);
669 HeapFree( GetProcessHeap(), 0, chTmp
);
673 memcpy( lpLCData
, ch
+ 1, *ch
* sizeof(WCHAR
) );
674 if (LCType
!= LOCALE_FONTSIGNATURE
) lpLCData
[nRet
-1] = 0;
681 /***********************************************************************
684 * Retrieve the ANSI codepage for a given locale.
686 inline static UINT
get_lcid_codepage( LCID lcid
)
689 if (!GetLocaleInfoW( lcid
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
, (WCHAR
*)&ret
,
690 sizeof(ret
)/sizeof(WCHAR
) )) ret
= 0;
699 * Get information about an aspect of a locale.
702 * lcid [I] LCID of the locale
703 * lctype [I] LCTYPE_ flags from "winnls.h"
704 * buffer [O] Destination for the information
705 * len [I] Length of buffer in characters
708 * Success: The size of the data requested. If buffer is non-NULL, it is filled
709 * with the information.
710 * Failure: 0. Use GetLastError() to determine the cause.
713 * - LOCALE_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT
714 * - The string returned is NUL terminated, except for LOCALE_FONTSIGNATURE,
715 * which is a bit string.
717 INT STDCALL
GetLocaleInfoA( LCID lcid
, LCTYPE lctype
, LPSTR buffer
, INT len
)
722 if (len
< 0 || (len
&& !buffer
))
724 SetLastError( ERROR_INVALID_PARAMETER
);
727 if (!len
) buffer
= NULL
;
729 if (!(lenW
= GetLocaleInfoW( lcid
, lctype
, NULL
, 0 ))) return 0;
731 if (!(bufferW
= HeapAlloc( GetProcessHeap(), 0, lenW
* sizeof(WCHAR
) )))
733 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
736 if ((ret
= GetLocaleInfoW( lcid
, lctype
, bufferW
, lenW
)))
738 if ((lctype
& LOCALE_RETURN_NUMBER
) ||
739 ((lctype
& ~LOCALE_LOCALEINFOFLAGSMASK
) == LOCALE_FONTSIGNATURE
))
741 /* it's not an ASCII string, just bytes */
742 ret
*= sizeof(WCHAR
);
745 if (ret
<= len
) memcpy( buffer
, bufferW
, ret
);
748 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
755 UINT codepage
= CP_ACP
;
756 if (!(lctype
& LOCALE_USE_CP_ACP
)) codepage
= get_lcid_codepage( lcid
);
757 ret
= WideCharToMultiByte( codepage
, 0, bufferW
, ret
, buffer
, len
, NULL
, NULL
);
760 HeapFree( GetProcessHeap(), 0, bufferW
);
765 #ifndef _OLE2NLS_IN_BUILD_
772 GetSystemDefaultLangID (VOID
)
774 return LANGIDFROMLCID(GetSystemDefaultLCID());
783 GetSystemDefaultLCID (VOID
)
786 NtQueryDefaultLocale( FALSE
, &lcid
);
789 // return SystemLocale;
800 GetSystemDefaultUILanguage(VOID
)
802 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
807 #ifndef _OLE2NLS_IN_BUILD_
814 GetThreadLocale (VOID
)
816 return NtCurrentTeb()->CurrentLocale
;
825 #ifndef _OLE2NLS_IN_BUILD_
832 GetUserDefaultLangID (VOID
)
834 return LANGIDFROMLCID(GetUserDefaultLCID());
843 GetUserDefaultLCID (VOID
)
846 NtQueryDefaultLocale(TRUE
, &lcid
);
858 GetUserDefaultUILanguage(VOID
)
860 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
873 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
883 IsValidLanguageGroup(
884 LGRPID LanguageGroup
,
887 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
893 /******************************************************************************
895 * RIPPED FROM WINE's dlls\kernel\locale.c rev 1.44
897 * IsValidLocale (KERNEL32.@)
899 * Determine if a locale is valid.
902 * lcid [I] LCID of the locale to check
903 * flags [I] LCID_SUPPORTED = Valid, LCID_INSTALLED = Valid and installed on the system
906 * TRUE, if lcid is valid,
910 * Wine does not currently make the distinction between supported and installed. All
911 * languages supported are installed by default.
919 /* check if language is registered in the kernel32 resources */
920 return FindResourceExW( hCurrentModule
, (LPWSTR
)RT_STRING
,
921 (LPCWSTR
)LOCALE_ILANGUAGE
, LANGIDFROMLCID(lcid
)) != 0;
926 #ifndef _OLE2NLS_IN_BUILD_
942 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
961 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
979 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
994 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
999 #ifndef _OLE2NLS_IN_BUILD_
1012 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1028 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1033 /**********************************************************************
1035 * RIPPED FROM WINE's dlls\kernel\locale.c rev 1.42
1037 * SetThreadLocale (KERNEL32.@)
1039 * Set the current threads locale.
1042 * lcid [I] LCID of the locale to set
1045 * Success: TRUE. The threads locale is set to lcid.
1046 * Failure: FALSE. Use GetLastError() to determine the cause.
1049 BOOL WINAPI
SetThreadLocale( LCID lcid
)
1051 DPRINT("SetThreadLocale(0x%04lX)\n", lcid
);
1053 lcid
= ConvertDefaultLocale(lcid
);
1055 if (lcid
!= GetThreadLocale())
1057 if (!IsValidLocale(lcid
, LCID_SUPPORTED
))
1059 SetLastError(ERROR_INVALID_PARAMETER
);
1063 NtCurrentTeb()->CurrentLocale
= lcid
;
1064 /* FIXME: NtCurrentTeb()->code_page = get_lcid_codepage( lcid );
1065 * Wine save the acp for easy/fast access, but ROS has no such Teb member.
1066 * Maybe add this member to ros as well?
1070 Lag test app for å se om locale etc, endres i en app. etter at prosessen er
1071 startet, eller om bare nye prosesser blir berørt.
1088 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);