/* * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * FILE: dll/win32/kernel32/file/lang.c * PURPOSE: National Laguage Support related funcs * PROGRAMMER: Thomas Weidenmueller * Gunnar Andre Dalsnes * Aleksey Bragin * Eric Kohl * Alex Ionescu * Richard Campbell * James Tabor * Dmitry Chapyshev * UPDATE HISTORY: * Created 21/09/2003 */ #include #include #define NDEBUG #include #include "lcformat_private.h" #define LOCALE_LOCALEINFOFLAGSMASK (LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP|\ LOCALE_RETURN_NUMBER|LOCALE_RETURN_GENITIVE_NAMES) #define CALINFO_MAX_YEAR 2029 //static LCID SystemLocale = MAKELCID(LANG_ENGLISH, SORT_DEFAULT); //static RTL_CRITICAL_SECTION LocalesListLock; extern int wine_fold_string(int flags, const WCHAR *src, int srclen, WCHAR *dst, int dstlen); extern int wine_get_sortkey(int flags, const WCHAR *src, int srclen, char *dst, int dstlen); extern int wine_compare_string(int flags, const WCHAR *str1, int len1, const WCHAR *str2, int len2); typedef struct { union { UILANGUAGE_ENUMPROCA procA; UILANGUAGE_ENUMPROCW procW; } u; DWORD flags; LONG_PTR param; } ENUM_UILANG_CALLBACK; static const WCHAR szLocaleKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NLS\\Locale"; static const WCHAR szLangGroupsKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NLS\\Language Groups"; /*********************************************************************** * is_genitive_name_supported * * Determine could LCTYPE basically support genitive name form or not. */ static BOOL is_genitive_name_supported( LCTYPE lctype ) { switch(lctype & 0xffff) { case LOCALE_SMONTHNAME1: case LOCALE_SMONTHNAME2: case LOCALE_SMONTHNAME3: case LOCALE_SMONTHNAME4: case LOCALE_SMONTHNAME5: case LOCALE_SMONTHNAME6: case LOCALE_SMONTHNAME7: case LOCALE_SMONTHNAME8: case LOCALE_SMONTHNAME9: case LOCALE_SMONTHNAME10: case LOCALE_SMONTHNAME11: case LOCALE_SMONTHNAME12: case LOCALE_SMONTHNAME13: return TRUE; default: return FALSE; } } /*********************************************************************** * create_registry_key * * Create the Control Panel\\International registry key. */ static inline HANDLE create_registry_key(void) { static const WCHAR intlW[] = {'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\', 'I','n','t','e','r','n','a','t','i','o','n','a','l',0}; OBJECT_ATTRIBUTES attr; UNICODE_STRING nameW; HANDLE hkey; if (RtlOpenCurrentUser( KEY_ALL_ACCESS, &hkey ) != STATUS_SUCCESS) return 0; attr.Length = sizeof(attr); attr.RootDirectory = hkey; attr.ObjectName = &nameW; attr.Attributes = 0; attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; RtlInitUnicodeString( &nameW, intlW ); if (NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS) hkey = 0; NtClose( attr.RootDirectory ); return hkey; } /****************************************************************************** * @implemented * RIPPED FROM WINE's dlls\kernel\locale.c rev 1.42 * * ConvertDefaultLocale (KERNEL32.@) * * Convert a default locale identifier into a real identifier. * * PARAMS * lcid [I] LCID identifier of the locale to convert * * RETURNS * lcid unchanged, if not a default locale or its sublanguage is * not SUBLANG_NEUTRAL. * GetSystemDefaultLCID(), if lcid == LOCALE_SYSTEM_DEFAULT. * GetUserDefaultLCID(), if lcid == LOCALE_USER_DEFAULT or LOCALE_NEUTRAL. * Otherwise, lcid with sublanguage changed to SUBLANG_DEFAULT. */ LCID WINAPI ConvertDefaultLocale(LCID lcid) { LANGID langid; switch (lcid) { case LOCALE_SYSTEM_DEFAULT: lcid = GetSystemDefaultLCID(); break; case LOCALE_USER_DEFAULT: case LOCALE_NEUTRAL: lcid = GetUserDefaultLCID(); break; default: /* Replace SUBLANG_NEUTRAL with SUBLANG_DEFAULT */ langid = LANGIDFROMLCID(lcid); if (SUBLANGID(langid) == SUBLANG_NEUTRAL) { langid = MAKELANGID(PRIMARYLANGID(langid), SUBLANG_DEFAULT); lcid = MAKELCID(langid, SORTIDFROMLCID(lcid)); } } return lcid; } static BOOL NLS_RegEnumValue(HANDLE hKey, UINT ulIndex, LPWSTR szValueName, ULONG valueNameSize, LPWSTR szValueData, ULONG valueDataSize) { BYTE buffer[80]; KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer; DWORD dwLen; if (NtEnumerateValueKey( hKey, ulIndex, KeyValueFullInformation, buffer, sizeof(buffer), &dwLen ) != STATUS_SUCCESS || info->NameLength > valueNameSize || info->DataLength > valueDataSize) { return FALSE; } DPRINT("info->Name %s info->DataLength %d\n", info->Name, info->DataLength); memcpy( szValueName, info->Name, info->NameLength); szValueName[info->NameLength / sizeof(WCHAR)] = '\0'; memcpy( szValueData, buffer + info->DataOffset, info->DataLength ); szValueData[info->DataLength / sizeof(WCHAR)] = '\0'; DPRINT("returning %s %s\n", szValueName, szValueData); return TRUE; } static HANDLE NLS_RegOpenKey(HANDLE hRootKey, LPCWSTR szKeyName) { UNICODE_STRING keyName; OBJECT_ATTRIBUTES attr; HANDLE hkey; RtlInitUnicodeString( &keyName, szKeyName ); InitializeObjectAttributes(&attr, &keyName, OBJ_CASE_INSENSITIVE, hRootKey, NULL); if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS) { SetLastError( ERROR_BADDB ); hkey = 0; } return hkey; } static BOOL NLS_RegEnumSubKey(HANDLE hKey, UINT ulIndex, LPWSTR szKeyName, ULONG keyNameSize) { BYTE buffer[80]; KEY_BASIC_INFORMATION *info = (KEY_BASIC_INFORMATION *)buffer; DWORD dwLen; if (NtEnumerateKey( hKey, ulIndex, KeyBasicInformation, buffer, sizeof(buffer), &dwLen) != STATUS_SUCCESS || info->NameLength > keyNameSize) { return FALSE; } DPRINT("info->Name %s info->NameLength %d\n", info->Name, info->NameLength); memcpy( szKeyName, info->Name, info->NameLength); szKeyName[info->NameLength / sizeof(WCHAR)] = '\0'; DPRINT("returning %s\n", szKeyName); return TRUE; } static BOOL NLS_RegGetDword(HANDLE hKey, LPCWSTR szValueName, DWORD *lpVal) { BYTE buffer[128]; const KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; DWORD dwSize = sizeof(buffer); UNICODE_STRING valueName; RtlInitUnicodeString( &valueName, szValueName ); DPRINT("%p, %s\n", hKey, szValueName); if (NtQueryValueKey( hKey, &valueName, KeyValuePartialInformation, buffer, dwSize, &dwSize ) == STATUS_SUCCESS && info->DataLength == sizeof(DWORD)) { memcpy(lpVal, info->Data, sizeof(DWORD)); return TRUE; } return FALSE; } static BOOL NLS_GetLanguageGroupName(LGRPID lgrpid, LPWSTR szName, ULONG nameSize) { LANGID langId; LPCWSTR szResourceName = MAKEINTRESOURCEW(((lgrpid + 0x2000) >> 4) + 1); HRSRC hResource; BOOL bRet = FALSE; /* FIXME: Is it correct to use the system default langid? */ langId = GetSystemDefaultLangID(); if (SUBLANGID(langId) == SUBLANG_NEUTRAL) langId = MAKELANGID( PRIMARYLANGID(langId), SUBLANG_DEFAULT ); hResource = FindResourceExW( hCurrentModule, (LPWSTR)RT_STRING, szResourceName, langId ); if (hResource) { HGLOBAL hResDir = LoadResource( hCurrentModule, hResource ); if (hResDir) { ULONG iResourceIndex = lgrpid & 0xf; LPCWSTR lpResEntry = LockResource( hResDir ); ULONG i; for (i = 0; i < iResourceIndex; i++) lpResEntry += *lpResEntry + 1; if (*lpResEntry < nameSize) { memcpy( szName, lpResEntry + 1, *lpResEntry * sizeof(WCHAR) ); szName[*lpResEntry] = '\0'; bRet = TRUE; } } FreeResource( hResource ); } else DPRINT1("FindResourceExW() failed\n"); return bRet; } /* Callback function ptrs for EnumLanguageGrouplocalesA/W */ typedef struct { LANGGROUPLOCALE_ENUMPROCA procA; LANGGROUPLOCALE_ENUMPROCW procW; DWORD dwFlags; LGRPID lgrpid; LONG_PTR lParam; } ENUMLANGUAGEGROUPLOCALE_CALLBACKS; /* Internal implementation of EnumLanguageGrouplocalesA/W */ static BOOL NLS_EnumLanguageGroupLocales(ENUMLANGUAGEGROUPLOCALE_CALLBACKS *lpProcs) { static const WCHAR szAlternateSortsKeyName[] = { 'A','l','t','e','r','n','a','t','e',' ','S','o','r','t','s','\0' }; WCHAR szNumber[10], szValue[4]; HANDLE hKey; BOOL bContinue = TRUE, bAlternate = FALSE; LGRPID lgrpid; ULONG ulIndex = 1; /* Ignore default entry of 1st key */ if (!lpProcs || !lpProcs->lgrpid || lpProcs->lgrpid > LGRPID_ARMENIAN) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (lpProcs->dwFlags) { SetLastError(ERROR_INVALID_FLAGS); return FALSE; } hKey = NLS_RegOpenKey( 0, szLocaleKeyName ); if (!hKey) { DPRINT1("NLS_RegOpenKey() failed\n"); return FALSE; } while (bContinue) { if (NLS_RegEnumValue( hKey, ulIndex, szNumber, sizeof(szNumber), szValue, sizeof(szValue) )) { lgrpid = wcstoul( szValue, NULL, 16 ); DPRINT("lcid %s, grpid %d (%smatched)\n", szNumber, lgrpid, lgrpid == lpProcs->lgrpid ? "" : "not "); if (lgrpid == lpProcs->lgrpid) { LCID lcid; lcid = wcstoul( szNumber, NULL, 16 ); /* FIXME: native returns extra text for a few (17/150) locales, e.g: * '00000437 ;Georgian' * At present we only pass the LCID string. */ if (lpProcs->procW) bContinue = lpProcs->procW( lgrpid, lcid, szNumber, lpProcs->lParam ); else { char szNumberA[sizeof(szNumber)/sizeof(WCHAR)]; WideCharToMultiByte(CP_ACP, 0, szNumber, -1, szNumberA, sizeof(szNumberA), 0, 0); bContinue = lpProcs->procA( lgrpid, lcid, szNumberA, lpProcs->lParam ); } } ulIndex++; } else { /* Finished enumerating this key */ if (!bAlternate) { /* Enumerate alternate sorts also */ hKey = NLS_RegOpenKey( hKey, szAlternateSortsKeyName ); bAlternate = TRUE; ulIndex = 0; } else bContinue = FALSE; /* Finished both keys */ } if (!bContinue) break; } if (hKey) NtClose( hKey ); return TRUE; } /* * @implemented */ BOOL WINAPI EnumLanguageGroupLocalesA( LANGGROUPLOCALE_ENUMPROCA lpLangGroupLocaleEnumProc, LGRPID LanguageGroup, DWORD dwFlags, LONG_PTR lParam) { ENUMLANGUAGEGROUPLOCALE_CALLBACKS callbacks; DPRINT("(%p,0x%08X,0x%08X,0x%08lX)\n", lpLangGroupLocaleEnumProc, LanguageGroup, dwFlags, lParam); callbacks.procA = lpLangGroupLocaleEnumProc; callbacks.procW = NULL; callbacks.dwFlags = dwFlags; callbacks.lgrpid = LanguageGroup; callbacks.lParam = lParam; return NLS_EnumLanguageGroupLocales( lpLangGroupLocaleEnumProc ? &callbacks : NULL ); } /* * @implemented */ BOOL WINAPI EnumLanguageGroupLocalesW( LANGGROUPLOCALE_ENUMPROCW lpLangGroupLocaleEnumProc, LGRPID LanguageGroup, DWORD dwFlags, LONG_PTR lParam) { ENUMLANGUAGEGROUPLOCALE_CALLBACKS callbacks; DPRINT("(%p,0x%08X,0x%08X,0x%08lX)\n", lpLangGroupLocaleEnumProc, LanguageGroup, dwFlags, lParam); callbacks.procA = NULL; callbacks.procW = lpLangGroupLocaleEnumProc; callbacks.dwFlags = dwFlags; callbacks.lgrpid = LanguageGroup; callbacks.lParam = lParam; return NLS_EnumLanguageGroupLocales( lpLangGroupLocaleEnumProc ? &callbacks : NULL ); } /* Callback function ptrs for EnumSystemCodePagesA/W */ typedef struct { CODEPAGE_ENUMPROCA procA; CODEPAGE_ENUMPROCW procW; DWORD dwFlags; } ENUMSYSTEMCODEPAGES_CALLBACKS; /* Internal implementation of EnumSystemCodePagesA/W */ static BOOL NLS_EnumSystemCodePages(ENUMSYSTEMCODEPAGES_CALLBACKS *lpProcs) { WCHAR szNumber[5 + 1], szValue[MAX_PATH]; HANDLE hKey; BOOL bContinue = TRUE; ULONG ulIndex = 0; if (!lpProcs) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } switch (lpProcs->dwFlags) { case CP_INSTALLED: case CP_SUPPORTED: break; default: SetLastError(ERROR_INVALID_FLAGS); return FALSE; } hKey = NLS_RegOpenKey(0, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage"); if (!hKey) { DPRINT1("NLS_RegOpenKey() failed\n"); return FALSE; } while (bContinue) { if (NLS_RegEnumValue(hKey, ulIndex, szNumber, sizeof(szNumber), szValue, sizeof(szValue))) { if ((lpProcs->dwFlags == CP_SUPPORTED)|| ((lpProcs->dwFlags == CP_INSTALLED)&&(wcslen(szValue) > 2))) { if (lpProcs->procW) { bContinue = lpProcs->procW(szNumber); } else { char szNumberA[sizeof(szNumber)/sizeof(WCHAR)]; WideCharToMultiByte(CP_ACP, 0, szNumber, -1, szNumberA, sizeof(szNumberA), 0, 0); bContinue = lpProcs->procA(szNumberA); } } ulIndex++; } else bContinue = FALSE; if (!bContinue) break; } if (hKey) NtClose(hKey); return TRUE; } /* * @implemented */ BOOL WINAPI EnumSystemCodePagesW ( CODEPAGE_ENUMPROCW lpCodePageEnumProc, DWORD dwFlags ) { ENUMSYSTEMCODEPAGES_CALLBACKS procs; DPRINT("(%p,0x%08X,0x%08lX)\n", lpCodePageEnumProc, dwFlags); procs.procA = NULL; procs.procW = lpCodePageEnumProc; procs.dwFlags = dwFlags; return NLS_EnumSystemCodePages(lpCodePageEnumProc ? &procs : NULL); } /* * @implemented */ BOOL WINAPI EnumSystemCodePagesA ( CODEPAGE_ENUMPROCA lpCodePageEnumProc, DWORD dwFlags ) { ENUMSYSTEMCODEPAGES_CALLBACKS procs; DPRINT("(%p,0x%08X,0x%08lX)\n", lpCodePageEnumProc, dwFlags); procs.procA = lpCodePageEnumProc; procs.procW = NULL; procs.dwFlags = dwFlags; return NLS_EnumSystemCodePages(lpCodePageEnumProc ? &procs : NULL); } /* * @implemented */ BOOL WINAPI EnumSystemGeoID( GEOCLASS GeoClass, GEOID ParentGeoId, // reserved GEO_ENUMPROC lpGeoEnumProc) { WCHAR szNumber[5 + 1]; ULONG ulIndex = 0; HANDLE hKey; DPRINT("(0x%08X,0x%08X,%p)\n", GeoClass, ParentGeoId, lpGeoEnumProc); if(!lpGeoEnumProc || GeoClass != GEOCLASS_NATION) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } hKey = NLS_RegOpenKey(0, L"\\REGISTRY\\Machine\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Country List"); if (!hKey) { DPRINT1("NLS_RegOpenKey() failed\n"); return FALSE; } while (NLS_RegEnumSubKey(hKey, ulIndex, szNumber, sizeof(szNumber))) { BOOL bContinue = TRUE; DWORD dwGeoId; HANDLE hSubKey = NLS_RegOpenKey(hKey, szNumber); if (hSubKey) { if (NLS_RegGetDword(hSubKey, L"CountryCode", &dwGeoId)) { if (!lpGeoEnumProc(dwGeoId)) bContinue = FALSE; } NtClose(hSubKey); } if (!bContinue) break; ulIndex++; } if (hKey) NtClose(hKey); return TRUE; } /* Callback function ptrs for EnumSystemLanguageGroupsA/W */ typedef struct { LANGUAGEGROUP_ENUMPROCA procA; LANGUAGEGROUP_ENUMPROCW procW; DWORD dwFlags; LONG_PTR lParam; } ENUMLANGUAGEGROUP_CALLBACKS; /* Internal implementation of EnumSystemLanguageGroupsA/W */ static BOOL NLS_EnumSystemLanguageGroups(ENUMLANGUAGEGROUP_CALLBACKS *lpProcs) { WCHAR szNumber[10], szValue[4]; HANDLE hKey; BOOL bContinue = TRUE; ULONG ulIndex = 0; if (!lpProcs) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } switch (lpProcs->dwFlags) { case 0: /* Default to LGRPID_INSTALLED */ lpProcs->dwFlags = LGRPID_INSTALLED; /* Fall through... */ case LGRPID_INSTALLED: case LGRPID_SUPPORTED: break; default: SetLastError(ERROR_INVALID_FLAGS); return FALSE; } hKey = NLS_RegOpenKey( 0, szLangGroupsKeyName ); if (!hKey) { DPRINT1("NLS_RegOpenKey() failed, KeyName='%S'\n", szLangGroupsKeyName); return FALSE; } while (bContinue) { if (NLS_RegEnumValue( hKey, ulIndex, szNumber, sizeof(szNumber), szValue, sizeof(szValue) )) { BOOL bInstalled = szValue[0] == '1' ? TRUE : FALSE; LGRPID lgrpid = wcstoul( szNumber, NULL, 16 ); DPRINT("grpid %s (%sinstalled)\n", szNumber, bInstalled ? "" : "not "); if (lpProcs->dwFlags == LGRPID_SUPPORTED || bInstalled) { WCHAR szGrpName[48]; if (!NLS_GetLanguageGroupName( lgrpid, szGrpName, sizeof(szGrpName) / sizeof(WCHAR) )) szGrpName[0] = '\0'; if (lpProcs->procW) bContinue = lpProcs->procW( lgrpid, szNumber, szGrpName, lpProcs->dwFlags, lpProcs->lParam ); else { char szNumberA[sizeof(szNumber)/sizeof(WCHAR)]; char szGrpNameA[48]; /* FIXME: MSDN doesn't say which code page the W->A translation uses, * or whether the language names are ever localised. Assume CP_ACP. */ WideCharToMultiByte(CP_ACP, 0, szNumber, -1, szNumberA, sizeof(szNumberA), 0, 0); WideCharToMultiByte(CP_ACP, 0, szGrpName, -1, szGrpNameA, sizeof(szGrpNameA), 0, 0); bContinue = lpProcs->procA( lgrpid, szNumberA, szGrpNameA, lpProcs->dwFlags, lpProcs->lParam ); } } ulIndex++; } else bContinue = FALSE; if (!bContinue) break; } if (hKey) NtClose( hKey ); return TRUE; } /* * @implemented */ BOOL WINAPI EnumSystemLanguageGroupsA( LANGUAGEGROUP_ENUMPROCA pLangGroupEnumProc, DWORD dwFlags, LONG_PTR lParam) { ENUMLANGUAGEGROUP_CALLBACKS procs; DPRINT("(%p,0x%08X,0x%08lX)\n", pLangGroupEnumProc, dwFlags, lParam); procs.procA = pLangGroupEnumProc; procs.procW = NULL; procs.dwFlags = dwFlags; procs.lParam = lParam; return NLS_EnumSystemLanguageGroups( pLangGroupEnumProc ? &procs : NULL); } /* * @implemented */ BOOL WINAPI EnumSystemLanguageGroupsW( LANGUAGEGROUP_ENUMPROCW pLangGroupEnumProc, DWORD dwFlags, LONG_PTR lParam) { ENUMLANGUAGEGROUP_CALLBACKS procs; DPRINT("(%p,0x%08X,0x%08lX)\n", pLangGroupEnumProc, dwFlags, lParam); procs.procA = NULL; procs.procW = pLangGroupEnumProc; procs.dwFlags = dwFlags; procs.lParam = lParam; return NLS_EnumSystemLanguageGroups( pLangGroupEnumProc ? &procs : NULL); } /* Callback function ptrs for EnumSystemLocalesA/W */ typedef struct { LOCALE_ENUMPROCA procA; LOCALE_ENUMPROCW procW; DWORD dwFlags; } ENUMSYSTEMLOCALES_CALLBACKS; /* Internal implementation of EnumSystemLocalesA/W */ static BOOL NLS_EnumSystemLocales(ENUMSYSTEMLOCALES_CALLBACKS *lpProcs) { WCHAR szNumber[10], szValue[4]; HANDLE hKey; BOOL bContinue = TRUE; ULONG ulIndex = 0; if (!lpProcs) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } /* Passing 0 flags behaves like LCID_SUPPORTED */ if (lpProcs->dwFlags == 0) { lpProcs->dwFlags = LCID_SUPPORTED; } switch (lpProcs->dwFlags) { case LCID_ALTERNATE_SORTS: case LCID_INSTALLED: case LCID_SUPPORTED: break; default: SetLastError(ERROR_INVALID_FLAGS); return FALSE; } hKey = NLS_RegOpenKey(0, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\Locale"); if (!hKey) { DPRINT1("NLS_RegOpenKey() failed\n"); return FALSE; } while (bContinue) { if (NLS_RegEnumValue( hKey, ulIndex, szNumber, sizeof(szNumber), szValue, sizeof(szValue))) { if ((lpProcs->dwFlags == LCID_SUPPORTED)|| ((lpProcs->dwFlags == LCID_INSTALLED)&&(wcslen(szValue) > 0))) { if (lpProcs->procW) { bContinue = lpProcs->procW(szNumber); } else { char szNumberA[sizeof(szNumber)/sizeof(WCHAR)]; WideCharToMultiByte(CP_ACP, 0, szNumber, -1, szNumberA, sizeof(szNumberA), 0, 0); bContinue = lpProcs->procA(szNumberA); } } ulIndex++; } else bContinue = FALSE; if (!bContinue) break; } if (hKey) NtClose(hKey); return TRUE; } /* * @implemented */ BOOL WINAPI EnumSystemLocalesA ( LOCALE_ENUMPROCA lpLocaleEnumProc, DWORD dwFlags ) { ENUMSYSTEMLOCALES_CALLBACKS procs; DPRINT("(%p,0x%08X)\n", lpLocaleEnumProc, dwFlags); procs.procA = lpLocaleEnumProc; procs.procW = NULL; procs.dwFlags = dwFlags; return NLS_EnumSystemLocales(lpLocaleEnumProc ? &procs : NULL); } /* * @implemented */ BOOL WINAPI EnumSystemLocalesW ( LOCALE_ENUMPROCW lpLocaleEnumProc, DWORD dwFlags ) { ENUMSYSTEMLOCALES_CALLBACKS procs; DPRINT("(%p,0x%08X)\n", lpLocaleEnumProc, dwFlags); procs.procA = NULL; procs.procW = lpLocaleEnumProc; procs.dwFlags = dwFlags; return NLS_EnumSystemLocales(lpLocaleEnumProc ? &procs : NULL); } static BOOL CALLBACK enum_uilang_proc_a( HMODULE hModule, LPCSTR type, LPCSTR name, WORD LangID, LONG_PTR lParam ) { ENUM_UILANG_CALLBACK *enum_uilang = (ENUM_UILANG_CALLBACK *)lParam; char buf[20]; sprintf(buf, "%08x", (UINT)LangID); return enum_uilang->u.procA( buf, enum_uilang->param ); } /* * @implemented */ BOOL WINAPI EnumUILanguagesA( UILANGUAGE_ENUMPROCA lpUILanguageEnumProc, DWORD dwFlags, LONG_PTR lParam) { ENUM_UILANG_CALLBACK enum_uilang; DPRINT("%p, %x, %lx\n", lpUILanguageEnumProc, dwFlags, lParam); if(!lpUILanguageEnumProc) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if(dwFlags) { SetLastError(ERROR_INVALID_FLAGS); return FALSE; } enum_uilang.u.procA = lpUILanguageEnumProc; enum_uilang.flags = dwFlags; enum_uilang.param = lParam; EnumResourceLanguagesA( hCurrentModule, (LPCSTR)RT_STRING, (LPCSTR)LOCALE_ILANGUAGE, enum_uilang_proc_a, (LONG_PTR)&enum_uilang); return TRUE; } static BOOL CALLBACK enum_uilang_proc_w( HMODULE hModule, LPCWSTR type, LPCWSTR name, WORD LangID, LONG_PTR lParam ) { static const WCHAR formatW[] = {'%','0','8','x',0}; ENUM_UILANG_CALLBACK *enum_uilang = (ENUM_UILANG_CALLBACK *)lParam; WCHAR buf[20]; swprintf( buf, formatW, (UINT)LangID ); return enum_uilang->u.procW( buf, enum_uilang->param ); } /* * @implemented */ BOOL WINAPI EnumUILanguagesW( UILANGUAGE_ENUMPROCW lpUILanguageEnumProc, DWORD dwFlags, LONG_PTR lParam) { ENUM_UILANG_CALLBACK enum_uilang; DPRINT("%p, %x, %lx\n", lpUILanguageEnumProc, dwFlags, lParam); if(!lpUILanguageEnumProc) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if(dwFlags) { SetLastError(ERROR_INVALID_FLAGS); return FALSE; } enum_uilang.u.procW = lpUILanguageEnumProc; enum_uilang.flags = dwFlags; enum_uilang.param = lParam; EnumResourceLanguagesW( hCurrentModule, (LPCWSTR)RT_STRING, (LPCWSTR)LOCALE_ILANGUAGE, enum_uilang_proc_w, (LONG_PTR)&enum_uilang); return TRUE; } /* * @implemented */ int WINAPI GetCalendarInfoA( LCID lcid, CALID Calendar, CALTYPE CalType, LPSTR lpCalData, int cchData, LPDWORD lpValue ) { int ret; LPWSTR lpCalDataW = NULL; if (NLS_IsUnicodeOnlyLcid(lcid)) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } if (cchData && !(lpCalDataW = HeapAlloc(GetProcessHeap(), 0, cchData*sizeof(WCHAR)))) return 0; ret = GetCalendarInfoW(lcid, Calendar, CalType, lpCalDataW, cchData, lpValue); if(ret && lpCalDataW && lpCalData) WideCharToMultiByte(CP_ACP, 0, lpCalDataW, cchData, lpCalData, cchData, NULL, NULL); HeapFree(GetProcessHeap(), 0, lpCalDataW); return ret; } /* * @unimplemented */ int WINAPI GetCalendarInfoW( LCID Locale, CALID Calendar, CALTYPE CalType, LPWSTR lpCalData, int cchData, LPDWORD lpValue) { if (CalType & CAL_NOUSEROVERRIDE) DPRINT("FIXME: flag CAL_NOUSEROVERRIDE used, not fully implemented\n"); if (CalType & CAL_USE_CP_ACP) DPRINT("FIXME: flag CAL_USE_CP_ACP used, not fully implemented\n"); if (CalType & CAL_RETURN_NUMBER) { if (lpCalData != NULL) DPRINT("WARNING: lpCalData not NULL (%p) when it should!\n", lpCalData); if (cchData != 0) DPRINT("WARNING: cchData not 0 (%d) when it should!\n", cchData); } else { if (lpValue != NULL) DPRINT("WARNING: lpValue not NULL (%p) when it should!\n", lpValue); } /* FIXME: No verification is made yet wrt Locale * for the CALTYPES not requiring GetLocaleInfoA */ switch (CalType & ~(CAL_NOUSEROVERRIDE|CAL_RETURN_NUMBER|CAL_USE_CP_ACP)) { case CAL_ICALINTVALUE: DPRINT("FIXME: Unimplemented caltype %d\n", CalType & 0xffff); return E_FAIL; case CAL_SCALNAME: DPRINT("FIXME: Unimplemented caltype %d\n", CalType & 0xffff); return E_FAIL; case CAL_IYEAROFFSETRANGE: DPRINT("FIXME: Unimplemented caltype %d\n", CalType & 0xffff); return E_FAIL; case CAL_SERASTRING: DPRINT("FIXME: Unimplemented caltype %d\n", CalType & 0xffff); return E_FAIL; case CAL_SSHORTDATE: return GetLocaleInfoW(Locale, LOCALE_SSHORTDATE, lpCalData, cchData); case CAL_SLONGDATE: return GetLocaleInfoW(Locale, LOCALE_SLONGDATE, lpCalData, cchData); case CAL_SDAYNAME1: return GetLocaleInfoW(Locale, LOCALE_SDAYNAME1, lpCalData, cchData); case CAL_SDAYNAME2: return GetLocaleInfoW(Locale, LOCALE_SDAYNAME2, lpCalData, cchData); case CAL_SDAYNAME3: return GetLocaleInfoW(Locale, LOCALE_SDAYNAME3, lpCalData, cchData); case CAL_SDAYNAME4: return GetLocaleInfoW(Locale, LOCALE_SDAYNAME4, lpCalData, cchData); case CAL_SDAYNAME5: return GetLocaleInfoW(Locale, LOCALE_SDAYNAME5, lpCalData, cchData); case CAL_SDAYNAME6: return GetLocaleInfoW(Locale, LOCALE_SDAYNAME6, lpCalData, cchData); case CAL_SDAYNAME7: return GetLocaleInfoW(Locale, LOCALE_SDAYNAME7, lpCalData, cchData); case CAL_SABBREVDAYNAME1: return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME1, lpCalData, cchData); case CAL_SABBREVDAYNAME2: return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME2, lpCalData, cchData); case CAL_SABBREVDAYNAME3: return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME3, lpCalData, cchData); case CAL_SABBREVDAYNAME4: return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME4, lpCalData, cchData); case CAL_SABBREVDAYNAME5: return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME5, lpCalData, cchData); case CAL_SABBREVDAYNAME6: return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME6, lpCalData, cchData); case CAL_SABBREVDAYNAME7: return GetLocaleInfoW(Locale, LOCALE_SABBREVDAYNAME7, lpCalData, cchData); case CAL_SMONTHNAME1: return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME1, lpCalData, cchData); case CAL_SMONTHNAME2: return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME2, lpCalData, cchData); case CAL_SMONTHNAME3: return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME3, lpCalData, cchData); case CAL_SMONTHNAME4: return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME4, lpCalData, cchData); case CAL_SMONTHNAME5: return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME5, lpCalData, cchData); case CAL_SMONTHNAME6: return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME6, lpCalData, cchData); case CAL_SMONTHNAME7: return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME7, lpCalData, cchData); case CAL_SMONTHNAME8: return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME8, lpCalData, cchData); case CAL_SMONTHNAME9: return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME9, lpCalData, cchData); case CAL_SMONTHNAME10: return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME10, lpCalData, cchData); case CAL_SMONTHNAME11: return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME11, lpCalData, cchData); case CAL_SMONTHNAME12: return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME12, lpCalData, cchData); case CAL_SMONTHNAME13: return GetLocaleInfoW(Locale, LOCALE_SMONTHNAME13, lpCalData, cchData); case CAL_SABBREVMONTHNAME1: return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME1, lpCalData, cchData); case CAL_SABBREVMONTHNAME2: return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME2, lpCalData, cchData); case CAL_SABBREVMONTHNAME3: return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME3, lpCalData, cchData); case CAL_SABBREVMONTHNAME4: return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME4, lpCalData, cchData); case CAL_SABBREVMONTHNAME5: return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME5, lpCalData, cchData); case CAL_SABBREVMONTHNAME6: return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME6, lpCalData, cchData); case CAL_SABBREVMONTHNAME7: return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME7, lpCalData, cchData); case CAL_SABBREVMONTHNAME8: return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME8, lpCalData, cchData); case CAL_SABBREVMONTHNAME9: return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME9, lpCalData, cchData); case CAL_SABBREVMONTHNAME10: return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME10, lpCalData, cchData); case CAL_SABBREVMONTHNAME11: return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME11, lpCalData, cchData); case CAL_SABBREVMONTHNAME12: return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME12, lpCalData, cchData); case CAL_SABBREVMONTHNAME13: return GetLocaleInfoW(Locale, LOCALE_SABBREVMONTHNAME13, lpCalData, cchData); case CAL_SYEARMONTH: return GetLocaleInfoW(Locale, LOCALE_SYEARMONTH, lpCalData, cchData); case CAL_ITWODIGITYEARMAX: if (lpValue) *lpValue = CALINFO_MAX_YEAR; break; default: DPRINT("Unknown caltype %d\n",CalType & 0xffff); return E_FAIL; } return 0; } /* * @implemented */ BOOL WINAPI GetCPInfo(UINT CodePage, LPCPINFO CodePageInfo) { PCODEPAGE_ENTRY CodePageEntry; if (!CodePageInfo) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } CodePageEntry = IntGetCodePageEntry(CodePage); if (CodePageEntry == NULL) { switch(CodePage) { case CP_UTF7: case CP_UTF8: CodePageInfo->DefaultChar[0] = 0x3f; CodePageInfo->DefaultChar[1] = 0; CodePageInfo->LeadByte[0] = CodePageInfo->LeadByte[1] = 0; CodePageInfo->MaxCharSize = (CodePage == CP_UTF7) ? 5 : 4; return TRUE; } SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } if (CodePageEntry->CodePageTable.DefaultChar & 0xff00) { CodePageInfo->DefaultChar[0] = (CodePageEntry->CodePageTable.DefaultChar & 0xff00) >> 8; CodePageInfo->DefaultChar[1] = CodePageEntry->CodePageTable.DefaultChar & 0x00ff; } else { CodePageInfo->DefaultChar[0] = CodePageEntry->CodePageTable.DefaultChar & 0xff; CodePageInfo->DefaultChar[1] = 0; } if ((CodePageInfo->MaxCharSize = CodePageEntry->CodePageTable.MaximumCharacterSize) == 2) memcpy(CodePageInfo->LeadByte, CodePageEntry->CodePageTable.LeadByte, sizeof(CodePageInfo->LeadByte)); else CodePageInfo->LeadByte[0] = CodePageInfo->LeadByte[1] = 0; return TRUE; } static BOOL GetLocalisedText(DWORD dwResId, WCHAR *lpszDest) { HRSRC hrsrc; LCID lcid; LANGID langId; DWORD dwId; if (dwResId == 37) dwId = dwResId * 100; else dwId = dwResId; lcid = GetUserDefaultLCID(); lcid = ConvertDefaultLocale(lcid); langId = LANGIDFROMLCID(lcid); if (PRIMARYLANGID(langId) == LANG_NEUTRAL) langId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); hrsrc = FindResourceExW(hCurrentModule, (LPWSTR)RT_STRING, MAKEINTRESOURCEW((dwId >> 4) + 1), langId); if (hrsrc) { HGLOBAL hmem = LoadResource(hCurrentModule, hrsrc); if (hmem) { const WCHAR *p; unsigned int i; p = LockResource(hmem); for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1; memcpy(lpszDest, p + 1, *p * sizeof(WCHAR)); lpszDest[*p] = '\0'; return TRUE; } } DPRINT1("Could not get codepage name. dwResId = %ld\n", dwResId); return FALSE; } /* * @implemented */ BOOL WINAPI GetCPInfoExW(UINT CodePage, DWORD dwFlags, LPCPINFOEXW lpCPInfoEx) { if (!GetCPInfo(CodePage, (LPCPINFO) lpCPInfoEx)) return FALSE; switch(CodePage) { case CP_UTF7: { lpCPInfoEx->CodePage = CP_UTF7; lpCPInfoEx->UnicodeDefaultChar = 0x3f; return GetLocalisedText((DWORD)CodePage, lpCPInfoEx->CodePageName); } break; case CP_UTF8: { lpCPInfoEx->CodePage = CP_UTF8; lpCPInfoEx->UnicodeDefaultChar = 0x3f; return GetLocalisedText((DWORD)CodePage, lpCPInfoEx->CodePageName); } default: { PCODEPAGE_ENTRY CodePageEntry; CodePageEntry = IntGetCodePageEntry(CodePage); if (CodePageEntry == NULL) { DPRINT1("Could not get CodePage Entry! CodePageEntry = 0\n"); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } lpCPInfoEx->CodePage = CodePageEntry->CodePageTable.CodePage; lpCPInfoEx->UnicodeDefaultChar = CodePageEntry->CodePageTable.UniDefaultChar; return GetLocalisedText((DWORD)CodePage, lpCPInfoEx->CodePageName); } break; } } /* * @implemented */ BOOL WINAPI GetCPInfoExA(UINT CodePage, DWORD dwFlags, LPCPINFOEXA lpCPInfoEx) { CPINFOEXW CPInfo; if (!GetCPInfoExW(CodePage, dwFlags, &CPInfo)) return FALSE; /* the layout is the same except for CodePageName */ memcpy(lpCPInfoEx, &CPInfo, sizeof(CPINFOEXA)); WideCharToMultiByte(CP_ACP, 0, CPInfo.CodePageName, -1, lpCPInfoEx->CodePageName, sizeof(lpCPInfoEx->CodePageName), NULL, NULL); return TRUE; } static int NLS_GetGeoFriendlyName(GEOID Location, LPWSTR szFriendlyName, int cchData) { HANDLE hKey; WCHAR szPath[MAX_PATH]; UNICODE_STRING ValueName; KEY_VALUE_PARTIAL_INFORMATION *info; static const int info_size = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data); DWORD dwSize; NTSTATUS Status; int Ret; swprintf(szPath, L"\\REGISTRY\\Machine\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Country List\\%d", Location); hKey = NLS_RegOpenKey(0, szPath); if (!hKey) { DPRINT1("NLS_RegOpenKey() failed\n"); return 0; } dwSize = info_size + cchData * sizeof(WCHAR); if (!(info = HeapAlloc(GetProcessHeap(), 0, dwSize))) { NtClose(hKey); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return 0; } RtlInitUnicodeString(&ValueName, L"Name"); Status = NtQueryValueKey(hKey, &ValueName, KeyValuePartialInformation, (LPBYTE)info, dwSize, &dwSize); if (!Status) { Ret = (dwSize - info_size) / sizeof(WCHAR); if (!Ret || ((WCHAR *)info->Data)[Ret-1]) { if (Ret < cchData || !szFriendlyName) Ret++; else { SetLastError(ERROR_INSUFFICIENT_BUFFER); Ret = 0; } } if (Ret && szFriendlyName) { memcpy(szFriendlyName, info->Data, (Ret-1) * sizeof(WCHAR)); szFriendlyName[Ret-1] = 0; } } else if (Status == STATUS_BUFFER_OVERFLOW && !szFriendlyName) { Ret = (dwSize - info_size) / sizeof(WCHAR) + 1; } else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) { Ret = -1; } else { SetLastError(RtlNtStatusToDosError(Status)); Ret = 0; } NtClose(hKey); HeapFree(GetProcessHeap(), 0, info); return Ret; } /* * @unimplemented */ int WINAPI GetGeoInfoW( GEOID Location, GEOTYPE GeoType, LPWSTR lpGeoData, int cchData, LANGID LangId) { DPRINT("%d %d %p %d %d\n", Location, GeoType, lpGeoData, cchData, LangId); if ((GeoType == GEO_TIMEZONES)||(GeoType == GEO_OFFICIALLANGUAGES)) { SetLastError(ERROR_CALL_NOT_IMPLEMENTED); } switch (GeoType) { case GEO_FRIENDLYNAME: { return NLS_GetGeoFriendlyName(Location, lpGeoData, cchData); } case GEO_NATION: case GEO_LATITUDE: case GEO_LONGITUDE: case GEO_ISO2: case GEO_ISO3: case GEO_RFC1766: case GEO_LCID: case GEO_OFFICIALNAME: SetLastError(ERROR_CALL_NOT_IMPLEMENTED); break; } return 0; } /* * @unimplemented */ int WINAPI GetGeoInfoA( GEOID Location, GEOTYPE GeoType, LPSTR lpGeoData, int cchData, LANGID LangId) { DPRINT("%d %d %p %d %d\n", Location, GeoType, lpGeoData, cchData, LangId); if ((GeoType == GEO_TIMEZONES)||(GeoType == GEO_OFFICIALLANGUAGES)) { SetLastError(ERROR_CALL_NOT_IMPLEMENTED); } switch (GeoType) { case GEO_FRIENDLYNAME: { WCHAR szBuffer[MAX_PATH]; char szBufferA[sizeof(szBuffer)/sizeof(WCHAR)]; int Ret; Ret = NLS_GetGeoFriendlyName(Location, szBuffer, cchData); WideCharToMultiByte(CP_ACP, 0, szBuffer, -1, szBufferA, sizeof(szBufferA), 0, 0); strcpy(lpGeoData, szBufferA); return Ret; } case GEO_NATION: case GEO_LATITUDE: case GEO_LONGITUDE: case GEO_ISO2: case GEO_ISO3: case GEO_RFC1766: case GEO_LCID: case GEO_OFFICIALNAME: SetLastError(ERROR_CALL_NOT_IMPLEMENTED); break; } return 0; } const WCHAR *RosGetLocaleValueName( DWORD lctype ) { switch (lctype & ~LOCALE_LOCALEINFOFLAGSMASK) { /* These values are used by SetLocaleInfo and GetLocaleInfo, and * the values are stored in the registry, confirmed under Windows. */ case LOCALE_ICALENDARTYPE: return L"iCalendarType"; case LOCALE_ICURRDIGITS: return L"iCurrDigits"; case LOCALE_ICURRENCY: return L"iCurrency"; case LOCALE_IDIGITS: return L"iDigits"; case LOCALE_IFIRSTDAYOFWEEK: return L"iFirstDayOfWeek"; case LOCALE_IFIRSTWEEKOFYEAR: return L"iFirstWeekOfYear"; case LOCALE_ILZERO: return L"iLZero"; case LOCALE_IMEASURE: return L"iMeasure"; case LOCALE_INEGCURR: return L"iNegCurr"; case LOCALE_INEGNUMBER: return L"iNegNumber"; case LOCALE_IPAPERSIZE: return L"iPaperSize"; case LOCALE_ITIME: return L"iTime"; case LOCALE_S1159: return L"s1159"; case LOCALE_S2359: return L"s2359"; case LOCALE_SCURRENCY: return L"sCurrency"; case LOCALE_SDATE: return L"sDate"; case LOCALE_SDECIMAL: return L"sDecimal"; case LOCALE_SGROUPING: return L"sGrouping"; case LOCALE_SLIST: return L"sList"; case LOCALE_SLONGDATE: return L"sLongDate"; case LOCALE_SMONDECIMALSEP: return L"sMonDecimalSep"; case LOCALE_SMONGROUPING: return L"sMonGrouping"; case LOCALE_SMONTHOUSANDSEP: return L"sMonThousandSep"; case LOCALE_SNEGATIVESIGN: return L"sNegativeSign"; case LOCALE_SPOSITIVESIGN: return L"sPositiveSign"; case LOCALE_SSHORTDATE: return L"sShortDate"; case LOCALE_STHOUSAND: return L"sThousand"; case LOCALE_STIME: return L"sTime"; case LOCALE_STIMEFORMAT: return L"sTimeFormat"; case LOCALE_SYEARMONTH: return L"sYearMonth"; /* The following are not listed under MSDN as supported, * but seem to be used and also stored in the registry. */ case LOCALE_ICOUNTRY: return L"iCountry"; case LOCALE_IDATE: return L"iDate"; case LOCALE_ILDATE: return L"iLDate"; case LOCALE_ITLZERO: return L"iTLZero"; case LOCALE_SCOUNTRY: return L"sCountry"; case LOCALE_SLANGUAGE: return L"sLanguage"; /* The following are used in XP and later */ case LOCALE_IDIGITSUBSTITUTION: return L"NumShape"; case LOCALE_SNATIVEDIGITS: return L"sNativeDigits"; case LOCALE_ITIMEMARKPOSN: return L"iTimePrefix"; } return NULL; } HKEY RosCreateRegistryKey(void) { OBJECT_ATTRIBUTES objAttr; UNICODE_STRING nameW; HANDLE hKey; if (RtlOpenCurrentUser( KEY_ALL_ACCESS, &hKey ) != STATUS_SUCCESS) return 0; objAttr.Length = sizeof(objAttr); objAttr.RootDirectory = hKey; objAttr.ObjectName = &nameW; objAttr.Attributes = 0; objAttr.SecurityDescriptor = NULL; objAttr.SecurityQualityOfService = NULL; RtlInitUnicodeString( &nameW, L"Control Panel\\International"); if (NtCreateKey( &hKey, KEY_ALL_ACCESS, &objAttr, 0, NULL, 0, NULL ) != STATUS_SUCCESS) hKey = 0; NtClose( objAttr.RootDirectory ); return hKey; } INT RosGetRegistryLocaleInfo( LPCWSTR lpValue, LPWSTR lpBuffer, INT nLen ) { DWORD dwSize; HKEY hKey; INT nRet; NTSTATUS ntStatus; UNICODE_STRING usNameW; KEY_VALUE_PARTIAL_INFORMATION *kvpiInfo; const int nInfoSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data); if (!(hKey = RosCreateRegistryKey())) return -1; RtlInitUnicodeString( &usNameW, lpValue ); dwSize = nInfoSize + nLen * sizeof(WCHAR); if (!(kvpiInfo = HeapAlloc( GetProcessHeap(), 0, dwSize ))) { NtClose( hKey ); SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return 0; } ntStatus = NtQueryValueKey( hKey, &usNameW, KeyValuePartialInformation, kvpiInfo, dwSize, &dwSize ); if (!ntStatus) { nRet = (dwSize - nInfoSize) / sizeof(WCHAR); if (!nRet || ((WCHAR *)kvpiInfo->Data)[nRet - 1]) { if (nRet < nLen || !lpBuffer) nRet++; else { SetLastError( ERROR_INSUFFICIENT_BUFFER ); nRet = 0; } } if (nRet && lpBuffer) { memcpy( lpBuffer, kvpiInfo->Data, (nRet - 1) * sizeof(WCHAR) ); lpBuffer[nRet - 1] = 0; } } else if (ntStatus == STATUS_BUFFER_OVERFLOW && !lpBuffer) { nRet = (dwSize - nInfoSize) / sizeof(WCHAR) + 1; } else if (ntStatus == STATUS_OBJECT_NAME_NOT_FOUND) { nRet = -1; } else { SetLastError( RtlNtStatusToDosError(ntStatus) ); nRet = 0; } NtClose( hKey ); HeapFree( GetProcessHeap(), 0, kvpiInfo ); return nRet; } int WINAPI GetLocaleInfoEx ( LPCWSTR lpLocaleName, LCTYPE LCType, LPWSTR lpLCData, int cchData ) { return -1; } /* * @implemented */ int WINAPI GetLocaleInfoW ( LCID Locale, LCTYPE LCType, LPWSTR lpLCData, int cchData ) { LANGID liLangID; HRSRC hRsrc; HGLOBAL hMem; HMODULE hModule; INT nRet; UINT uiFlags; const WCHAR *ch; int i; if (cchData < 0 || (cchData && !lpLCData)) { SetLastError( ERROR_INVALID_PARAMETER ); return 0; } if (LCType & LOCALE_RETURN_GENITIVE_NAMES && !is_genitive_name_supported( LCType )) { SetLastError( ERROR_INVALID_FLAGS ); return 0; } if (!cchData) lpLCData = NULL; if (Locale == LOCALE_NEUTRAL || Locale == LOCALE_SYSTEM_DEFAULT) Locale = GetSystemDefaultLCID(); else if (Locale == LOCALE_USER_DEFAULT) Locale = GetUserDefaultLCID(); uiFlags = LCType & LOCALE_LOCALEINFOFLAGSMASK; LCType &= ~LOCALE_LOCALEINFOFLAGSMASK; if (!(uiFlags & LOCALE_NOUSEROVERRIDE) && Locale == GetUserDefaultLCID()) { const WCHAR *value = RosGetLocaleValueName(LCType); if (value && ((nRet = RosGetRegistryLocaleInfo( value, lpLCData, cchData )) != -1)) return nRet; } liLangID = LANGIDFROMLCID( Locale ); if (SUBLANGID(liLangID) == SUBLANG_NEUTRAL) liLangID = MAKELANGID(PRIMARYLANGID(liLangID), SUBLANG_DEFAULT); hModule = GetModuleHandleW( L"kernel32.dll" ); if (!(hRsrc = FindResourceExW( hModule, (LPWSTR)RT_STRING, (LPCWSTR)((LCType >> 4) + 1), liLangID ))) { SetLastError( ERROR_INVALID_FLAGS ); return 0; } if (!(hMem = LoadResource( hModule, hRsrc ))) return 0; ch = LockResource( hMem ); for (i = 0; i < (LCType & 0x0f); i++) ch += *ch + 1; if (uiFlags & LOCALE_RETURN_NUMBER) nRet = sizeof(UINT) / sizeof(WCHAR); else if (is_genitive_name_supported( LCType ) && *ch) { /* genitive form's stored after a null separator from a nominative */ for (i = 1; i <= *ch; i++) if (!ch[i]) break; if (i <= *ch && (uiFlags & LOCALE_RETURN_GENITIVE_NAMES)) { nRet = *ch - i + 1; ch += i; } else nRet = i; } else nRet = (LCType == LOCALE_FONTSIGNATURE) ? *ch : *ch + 1; if (!lpLCData) return nRet; if (nRet > cchData) { SetLastError( ERROR_INSUFFICIENT_BUFFER ); return 0; } if (uiFlags & LOCALE_RETURN_NUMBER) { UINT uiNum; WCHAR *chEnd, *chTmp = HeapAlloc( GetProcessHeap(), 0, (*ch + 1) * sizeof(WCHAR) ); if (!chTmp) return 0; memcpy( chTmp, ch + 1, *ch * sizeof(WCHAR) ); chTmp[*ch] = L'\0'; uiNum = wcstol( chTmp, &chEnd, 10 ); if (!*chEnd) memcpy( lpLCData, &uiNum, sizeof(uiNum) ); else { SetLastError( ERROR_INVALID_FLAGS ); nRet = 0; } HeapFree( GetProcessHeap(), 0, chTmp ); } else { memcpy( lpLCData, ch + 1, nRet * sizeof(WCHAR) ); if (LCType != LOCALE_FONTSIGNATURE) lpLCData[nRet-1] = 0; } return nRet; } /*********************************************************************** * get_lcid_codepage * * Retrieve the ANSI codepage for a given locale. */ __inline static UINT get_lcid_codepage( LCID lcid ) { UINT ret; if (!GetLocaleInfoW( lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER, (WCHAR *)&ret, sizeof(ret)/sizeof(WCHAR) )) ret = 0; return ret; } /************************************************************************* * FoldStringA (KERNEL32.@) * * Map characters in a string. * * PARAMS * dwFlags [I] Flags controlling chars to map (MAP_ constants from "winnls.h") * src [I] String to map * srclen [I] Length of src, or -1 if src is NUL terminated * dst [O] Destination for mapped string * dstlen [I] Length of dst, or 0 to find the required length for the mapped string * * RETURNS * Success: The length of the string written to dst, including the terminating NUL. If * dstlen is 0, the value returned is the same, but nothing is written to dst, * and dst may be NULL. * Failure: 0. Use GetLastError() to determine the cause. */ INT WINAPI FoldStringA(DWORD dwFlags, LPCSTR src, INT srclen, LPSTR dst, INT dstlen) { INT ret = 0, srclenW = 0; WCHAR *srcW = NULL, *dstW = NULL; if (!src || !srclen || dstlen < 0 || (dstlen && !dst) || src == dst) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } srclenW = MultiByteToWideChar(CP_ACP, dwFlags & MAP_COMPOSITE ? MB_COMPOSITE : 0, src, srclen, NULL, 0); srcW = HeapAlloc(GetProcessHeap(), 0, srclenW * sizeof(WCHAR)); if (!srcW) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto FoldStringA_exit; } MultiByteToWideChar(CP_ACP, dwFlags & MAP_COMPOSITE ? MB_COMPOSITE : 0, src, srclen, srcW, srclenW); dwFlags = (dwFlags & ~MAP_PRECOMPOSED) | MAP_FOLDCZONE; ret = FoldStringW(dwFlags, srcW, srclenW, NULL, 0); if (ret && dstlen) { dstW = HeapAlloc(GetProcessHeap(), 0, ret * sizeof(WCHAR)); if (!dstW) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto FoldStringA_exit; } ret = FoldStringW(dwFlags, srcW, srclenW, dstW, ret); if (!WideCharToMultiByte(CP_ACP, 0, dstW, ret, dst, dstlen, NULL, NULL)) { ret = 0; SetLastError(ERROR_INSUFFICIENT_BUFFER); } } HeapFree(GetProcessHeap(), 0, dstW); FoldStringA_exit: HeapFree(GetProcessHeap(), 0, srcW); return ret; } /************************************************************************* * FoldStringW (KERNEL32.@) * * See FoldStringA. */ INT WINAPI FoldStringW(DWORD dwFlags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen) { int ret; switch (dwFlags & (MAP_COMPOSITE|MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES)) { case 0: if (dwFlags) break; /* Fall through for dwFlags == 0 */ case MAP_PRECOMPOSED|MAP_COMPOSITE: case MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES: case MAP_COMPOSITE|MAP_EXPAND_LIGATURES: SetLastError(ERROR_INVALID_FLAGS); return 0; } if (!src || !srclen || dstlen < 0 || (dstlen && !dst) || src == dst) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } ret = wine_fold_string(dwFlags, src, srclen, dst, dstlen); if (!ret) SetLastError(ERROR_INSUFFICIENT_BUFFER); return ret; } /* * @implemented (Synced to Wine-22112008) */ int WINAPI CompareStringA ( LCID Locale, DWORD dwCmpFlags, LPCSTR lpString1, int cchCount1, LPCSTR lpString2, int cchCount2 ) { WCHAR *buf1W = NtCurrentTeb()->StaticUnicodeBuffer; WCHAR *buf2W = buf1W + 130; LPWSTR str1W, str2W; INT len1W, len2W, ret; UINT locale_cp = CP_ACP; if (!lpString1 || !lpString2) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } if (cchCount1 < 0) cchCount1 = strlen(lpString1); if (cchCount2 < 0) cchCount2 = strlen(lpString2); if (!(dwCmpFlags & LOCALE_USE_CP_ACP)) locale_cp = get_lcid_codepage(Locale); len1W = MultiByteToWideChar(locale_cp, 0, lpString1, cchCount1, buf1W, 130); if (len1W) str1W = buf1W; else { len1W = MultiByteToWideChar(locale_cp, 0, lpString1, cchCount1, NULL, 0); str1W = HeapAlloc(GetProcessHeap(), 0, len1W * sizeof(WCHAR)); if (!str1W) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return 0; } MultiByteToWideChar(locale_cp, 0, lpString1, cchCount1, str1W, len1W); } len2W = MultiByteToWideChar(locale_cp, 0, lpString2, cchCount2, buf2W, 130); if (len2W) str2W = buf2W; else { len2W = MultiByteToWideChar(locale_cp, 0, lpString2, cchCount2, NULL, 0); str2W = HeapAlloc(GetProcessHeap(), 0, len2W * sizeof(WCHAR)); if (!str2W) { if (str1W != buf1W) HeapFree(GetProcessHeap(), 0, str1W); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return 0; } MultiByteToWideChar(locale_cp, 0, lpString2, cchCount2, str2W, len2W); } ret = CompareStringW(Locale, dwCmpFlags, str1W, len1W, str2W, len2W); if (str1W != buf1W) HeapFree(GetProcessHeap(), 0, str1W); if (str2W != buf2W) HeapFree(GetProcessHeap(), 0, str2W); return ret; } /* * @implemented (Synced to Wine-22/11/2008) */ int WINAPI CompareStringW ( LCID Locale, DWORD dwCmpFlags, LPCWSTR lpString1, int cchCount1, LPCWSTR lpString2, int cchCount2 ) { INT Result; if (!lpString1 || !lpString2) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } if (dwCmpFlags & ~(NORM_IGNORECASE | NORM_IGNORENONSPACE | NORM_IGNORESYMBOLS | SORT_STRINGSORT | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH | LOCALE_USE_CP_ACP | 0x10000000)) { SetLastError(ERROR_INVALID_FLAGS); return 0; } /* this style is related to diacritics in Arabic, Japanese, and Hebrew */ if (dwCmpFlags & 0x10000000) DPRINT1("Ignoring unknown style 0x10000000\n"); if (cchCount1 < 0) cchCount1 = wcslen(lpString1); if (cchCount2 < 0) cchCount2 = wcslen(lpString2); Result = wine_compare_string(dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2); if (Result) /* need to translate result */ return (Result < 0) ? CSTR_LESS_THAN : CSTR_GREATER_THAN; return CSTR_EQUAL; } /* * @implemented * * Get information about an aspect of a locale. * * PARAMS * lcid [I] LCID of the locale * lctype [I] LCTYPE_ flags from "winnls.h" * buffer [O] Destination for the information * len [I] Length of buffer in characters * * RETURNS * Success: The size of the data requested. If buffer is non-NULL, it is filled * with the information. * Failure: 0. Use GetLastError() to determine the cause. * * NOTES * - LOCALE_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT * - The string returned is NUL terminated, except for LOCALE_FONTSIGNATURE, * which is a bit string. */ INT WINAPI GetLocaleInfoA( LCID lcid, LCTYPE lctype, LPSTR buffer, INT len ) { WCHAR *bufferW; INT lenW, ret; if (len < 0 || (len && !buffer)) { SetLastError( ERROR_INVALID_PARAMETER ); return 0; } if (lctype & LOCALE_RETURN_GENITIVE_NAMES ) { SetLastError( ERROR_INVALID_FLAGS ); return 0; } if (!len) buffer = NULL; if (!(lenW = GetLocaleInfoW( lcid, lctype, NULL, 0 ))) return 0; if (!(bufferW = HeapAlloc( GetProcessHeap(), 0, lenW * sizeof(WCHAR) ))) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return 0; } if ((ret = GetLocaleInfoW( lcid, lctype, bufferW, lenW ))) { if ((lctype & LOCALE_RETURN_NUMBER) || ((lctype & ~LOCALE_LOCALEINFOFLAGSMASK) == LOCALE_FONTSIGNATURE)) { /* it's not an ASCII string, just bytes */ ret *= sizeof(WCHAR); if (buffer) { if (ret <= len) memcpy( buffer, bufferW, ret ); else { SetLastError( ERROR_INSUFFICIENT_BUFFER ); ret = 0; } } } else { UINT codepage = CP_ACP; if (!(lctype & LOCALE_USE_CP_ACP)) codepage = get_lcid_codepage( lcid ); ret = WideCharToMultiByte( codepage, 0, bufferW, ret, buffer, len, NULL, NULL ); } } HeapFree( GetProcessHeap(), 0, bufferW ); return ret; } /* * @implemented */ LANGID WINAPI GetSystemDefaultLangID(VOID) { return LANGIDFROMLCID(GetSystemDefaultLCID()); } /* * @implemented */ LCID WINAPI GetSystemDefaultLCID(VOID) { LCID lcid; NtQueryDefaultLocale(FALSE, &lcid); return lcid; } /* * @implemented */ LANGID WINAPI GetSystemDefaultUILanguage(VOID) { LANGID LanguageId; NTSTATUS Status; Status = NtQueryInstallUILanguage(&LanguageId); if (!NT_SUCCESS(Status)) { SetLastErrorByStatus(Status); return 0; } return LanguageId; } /* * @implemented */ LCID WINAPI GetThreadLocale(VOID) { return NtCurrentTeb()->CurrentLocale; } /* * @implemented */ LANGID WINAPI GetUserDefaultLangID(VOID) { return LANGIDFROMLCID(GetUserDefaultLCID()); } /* * @implemented */ LCID WINAPI GetUserDefaultLCID(VOID) { LCID lcid; NTSTATUS Status; Status = NtQueryDefaultLocale(TRUE, &lcid); if (!NT_SUCCESS(Status)) { SetLastErrorByStatus(Status); return 0; } return lcid; } /* * @implemented */ LANGID WINAPI GetUserDefaultUILanguage(VOID) { LANGID LangId; NTSTATUS Status; Status = NtQueryDefaultUILanguage(&LangId); if (!NT_SUCCESS(Status)) { SetLastErrorByStatus(Status); return 0; } return LangId; } /* * @unimplemented */ GEOID WINAPI GetUserGeoID( GEOCLASS GeoClass) { GEOID ret = GEOID_NOT_AVAILABLE; static const WCHAR geoW[] = {'G','e','o',0}; static const WCHAR nationW[] = {'N','a','t','i','o','n',0}; WCHAR bufferW[40], *end; DWORD count; HANDLE hkey, hSubkey = 0; UNICODE_STRING keyW; const KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)bufferW; RtlInitUnicodeString( &keyW, nationW ); count = sizeof(bufferW); if(!(hkey = create_registry_key())) return ret; switch( GeoClass ){ case GEOCLASS_NATION: if ((hSubkey = NLS_RegOpenKey(hkey, geoW))) { if((NtQueryValueKey(hSubkey, &keyW, KeyValuePartialInformation, (LPBYTE)bufferW, count, &count) == STATUS_SUCCESS ) && info->DataLength) ret = wcstol((LPCWSTR)info->Data, &end, 10); } break; case GEOCLASS_REGION: DPRINT("GEOCLASS_REGION not handled yet\n"); break; } NtClose(hkey); if (hSubkey) NtClose(hSubkey); return ret; } /****************************************************************************** * IsValidLanguageGroup * * Determine if a language group is supported and/or installed. * * PARAMS * LanguageGroup [I] Language Group Id (LGRPID_ values from "winnls.h") * dwFlags [I] LGRPID_SUPPORTED=Supported, LGRPID_INSTALLED=Installed * * RETURNS * TRUE, if lgrpid is supported and/or installed, according to dwFlags. * FALSE otherwise. * * @implemented */ BOOL WINAPI IsValidLanguageGroup( LGRPID LanguageGroup, DWORD dwFlags) { static const WCHAR szFormat[] = { '%','x','\0' }; WCHAR szValueName[16], szValue[2]; BOOL bSupported = FALSE, bInstalled = FALSE; HANDLE hKey; switch (dwFlags) { case LGRPID_INSTALLED: case LGRPID_SUPPORTED: hKey = NLS_RegOpenKey( 0, szLangGroupsKeyName ); if (!hKey) break; swprintf( szValueName, szFormat, LanguageGroup ); if (NLS_RegGetDword( hKey, szValueName, (LPDWORD)szValue )) { bSupported = TRUE; if (szValue[0] == '1') bInstalled = TRUE; } NtClose( hKey ); break; default: DPRINT("Invalid flags: %lx\n", dwFlags); return FALSE; } if ((dwFlags == LGRPID_SUPPORTED && bSupported) || (dwFlags == LGRPID_INSTALLED && bInstalled)) return TRUE; return FALSE; } /****************************************************************************** * IsValidLocale * * Determine if a locale is valid. * * PARAMS * Locale [I] LCID of the locale to check * dwFlags [I] LCID_SUPPORTED = Valid * LCID_INSTALLED = Valid and installed on the system * * RETURN * TRUE, if Locale is valid, * FALSE, otherwise. * * @implemented */ BOOL WINAPI IsValidLocale(LCID Locale, DWORD dwFlags) { OBJECT_ATTRIBUTES ObjectAttributes; PKEY_VALUE_PARTIAL_INFORMATION KeyInfo; WCHAR ValueNameBuffer[9]; UNICODE_STRING KeyName; UNICODE_STRING ValueName; ULONG KeyInfoSize; ULONG ReturnedSize; HANDLE KeyHandle; PWSTR ValueData; NTSTATUS Status; BOOL Installed = FALSE; DPRINT("IsValidLocale() called\n"); if ((dwFlags & ~(LCID_SUPPORTED | LCID_INSTALLED)) || (dwFlags == (LCID_SUPPORTED | LCID_INSTALLED))) { DPRINT("Invalid flags: %lx\n", dwFlags); return FALSE; } if (Locale & 0xFFFF0000) { RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Nls\\Locale\\Alternate Sorts"); } else { RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Nls\\Locale"); } InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DPRINT("NtOpenKey() failed (Status %lx)\n", Status); SetLastError(ERROR_BADDB); return FALSE; } swprintf(ValueNameBuffer, L"%08lx", (ULONG)Locale); RtlInitUnicodeString(&ValueName, ValueNameBuffer); KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4 * sizeof(WCHAR); KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, KeyInfoSize); if (KeyInfo == NULL) { DPRINT("RtlAllocateHeap() failed (Status %lx)\n", Status); NtClose(KeyHandle); return FALSE; } Status = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation, KeyInfo, KeyInfoSize, &ReturnedSize); NtClose(KeyHandle); if (!NT_SUCCESS(Status)) { DPRINT("NtQueryValueKey() failed (Status %lx)\n", Status); RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo); return FALSE; } if (dwFlags & LCID_SUPPORTED) { DPRINT("Locale is supported\n"); RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo); return TRUE; } ValueData = (PWSTR)&KeyInfo->Data[0]; if ((KeyInfo->Type == REG_SZ) && (KeyInfo->DataLength == 2 * sizeof(WCHAR))) { /* Find out if there is support for the language group * installed, to which this language belongs */ KeyHandle = NLS_RegOpenKey(0, szLangGroupsKeyName); if (KeyHandle) { WCHAR Value[2]; if (NLS_RegGetDword(KeyHandle, ValueData, (LPDWORD) Value) && Value[0] == L'1') { Installed = TRUE; DPRINT("Locale is supported and installed\n"); } NtClose(KeyHandle); } } RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo); DPRINT("IsValidLocale() called\n"); return Installed; } /* * @implemented */ int WINAPI LCMapStringA ( LCID Locale, DWORD dwMapFlags, LPCSTR lpSrcStr, int cchSrc, LPSTR lpDestStr, int cchDest ) { WCHAR *bufW = NtCurrentTeb()->StaticUnicodeBuffer; LPWSTR srcW, dstW; INT ret = 0, srclenW, dstlenW; UINT locale_cp = CP_ACP; if (!lpSrcStr || !cchSrc || cchDest < 0) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } if (!(dwMapFlags & LOCALE_USE_CP_ACP)) locale_cp = get_lcid_codepage(Locale); srclenW = MultiByteToWideChar(locale_cp, 0, lpSrcStr, cchSrc, bufW, 260); if (srclenW) srcW = bufW; else { srclenW = MultiByteToWideChar(locale_cp, 0, lpSrcStr, cchSrc, NULL, 0); srcW = HeapAlloc(GetProcessHeap(), 0, srclenW * sizeof(WCHAR)); if (!srcW) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return 0; } MultiByteToWideChar(locale_cp, 0, lpSrcStr, cchSrc, srcW, srclenW); } if (dwMapFlags & LCMAP_SORTKEY) { if (lpSrcStr == lpDestStr) { SetLastError(ERROR_INVALID_FLAGS); goto map_string_exit; } ret = wine_get_sortkey(dwMapFlags, srcW, srclenW, lpDestStr, cchDest); if (ret == 0) SetLastError(ERROR_INSUFFICIENT_BUFFER); else ret++; goto map_string_exit; } if (dwMapFlags & SORT_STRINGSORT) { SetLastError(ERROR_INVALID_FLAGS); goto map_string_exit; } dstlenW = LCMapStringW(Locale, dwMapFlags, srcW, srclenW, NULL, 0); if (!dstlenW) goto map_string_exit; dstW = HeapAlloc(GetProcessHeap(), 0, dstlenW * sizeof(WCHAR)); if (!dstW) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto map_string_exit; } LCMapStringW(Locale, dwMapFlags, srcW, srclenW, dstW, dstlenW); ret = WideCharToMultiByte(locale_cp, 0, dstW, dstlenW, lpDestStr, cchDest, NULL, NULL); HeapFree(GetProcessHeap(), 0, dstW); map_string_exit: if (srcW != bufW) HeapFree(GetProcessHeap(), 0, srcW); return ret; } /* * @implemented */ int WINAPI LCMapStringW ( LCID Locale, DWORD dwMapFlags, LPCWSTR lpSrcStr, int cchSrc, LPWSTR lpDestStr, int cchDest ) { LPWSTR dst_ptr; if (!lpSrcStr || !cchSrc || cchDest < 0) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } /* mutually exclusive flags */ if ((dwMapFlags & (LCMAP_LOWERCASE | LCMAP_UPPERCASE)) == (LCMAP_LOWERCASE | LCMAP_UPPERCASE) || (dwMapFlags & (LCMAP_HIRAGANA | LCMAP_KATAKANA)) == (LCMAP_HIRAGANA | LCMAP_KATAKANA) || (dwMapFlags & (LCMAP_HALFWIDTH | LCMAP_FULLWIDTH)) == (LCMAP_HALFWIDTH | LCMAP_FULLWIDTH) || (dwMapFlags & (LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE)) == (LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE)) { SetLastError(ERROR_INVALID_FLAGS); return 0; } if (!cchDest) lpDestStr = NULL; Locale = ConvertDefaultLocale(Locale); if (dwMapFlags & LCMAP_SORTKEY) { INT ret; if (lpSrcStr == lpDestStr) { SetLastError(ERROR_INVALID_FLAGS); return 0; } if (cchSrc < 0) cchSrc = wcslen(lpSrcStr); ret = wine_get_sortkey(dwMapFlags, lpSrcStr, cchSrc, (char *)lpDestStr, cchDest); if (ret == 0) SetLastError(ERROR_INSUFFICIENT_BUFFER); return ret; } /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */ if (dwMapFlags & SORT_STRINGSORT) { SetLastError(ERROR_INVALID_FLAGS); return 0; } if (cchSrc < 0) cchSrc = wcslen(lpSrcStr) + 1; if (!lpDestStr) /* return required string length */ { INT len; for (len = 0; cchSrc; lpSrcStr++, cchSrc--) { WCHAR wch = *lpSrcStr; /* tests show that win2k just ignores NORM_IGNORENONSPACE, * and skips white space and punctuation characters for * NORM_IGNORESYMBOLS. */ if ((dwMapFlags & NORM_IGNORESYMBOLS) && (iswctype(wch, _SPACE | _PUNCT))) continue; len++; } return len; } if (dwMapFlags & LCMAP_UPPERCASE) { for (dst_ptr = lpDestStr; cchSrc && cchDest; lpSrcStr++, cchSrc--) { WCHAR wch = *lpSrcStr; if ((dwMapFlags & NORM_IGNORESYMBOLS) && (iswctype(wch, _SPACE | _PUNCT))) continue; *dst_ptr++ = towupper(wch); cchDest--; } } else if (dwMapFlags & LCMAP_LOWERCASE) { for (dst_ptr = lpDestStr; cchSrc && cchDest; lpSrcStr++, cchSrc--) { WCHAR wch = *lpSrcStr; if ((dwMapFlags & NORM_IGNORESYMBOLS) && (iswctype(wch, _SPACE | _PUNCT))) continue; *dst_ptr++ = towlower(wch); cchDest--; } } else { if (lpSrcStr == lpDestStr) { SetLastError(ERROR_INVALID_FLAGS); return 0; } for (dst_ptr = lpDestStr; cchSrc && cchDest; lpSrcStr++, cchSrc--) { WCHAR wch = *lpSrcStr; if ((dwMapFlags & NORM_IGNORESYMBOLS) && (iswctype(wch, _SPACE | _PUNCT))) continue; *dst_ptr++ = wch; cchDest--; } } if (cchSrc) { SetLastError(ERROR_INSUFFICIENT_BUFFER); return 0; } return dst_ptr - lpDestStr; } /* * @unimplemented */ BOOL WINAPI SetCalendarInfoA( LCID Locale, CALID Calendar, CALTYPE CalType, LPCSTR lpCalData) { if (!Locale || !lpCalData) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } switch (CalType) { case CAL_NOUSEROVERRIDE: case CAL_RETURN_NUMBER: case CAL_USE_CP_ACP: break; default: SetLastError(ERROR_INVALID_FLAGS); return FALSE; } SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /* * @unimplemented */ BOOL WINAPI SetCalendarInfoW( LCID Locale, CALID Calendar, CALTYPE CalType, LPCWSTR lpCalData) { if (!Locale || !lpCalData) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } switch (CalType) { case CAL_NOUSEROVERRIDE: case CAL_RETURN_NUMBER: case CAL_USE_CP_ACP: break; default: SetLastError(ERROR_INVALID_FLAGS); return FALSE; } SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /********************************************************************** * @implemented * RIPPED FROM WINE's dlls\kernel\locale.c ver 0.9.29 * * SetLocaleInfoA (KERNEL32.@) * * Set the current locale info. * * PARAMS * Locale [I] LCID of the locale * LCType [I] LCTYPE_ flags from "winnls.h" * lpLCData [I] Information to set * * RETURNS * Success: TRUE. The information given will be returned by GetLocaleInfoA() * whenever it is called without LOCALE_NOUSEROVERRIDE. * Failure: FALSE. Use GetLastError() to determine the cause. */ BOOL WINAPI SetLocaleInfoA ( LCID Locale, LCTYPE LCType, LPCSTR lpLCData ) { UINT codepage = CP_ACP; WCHAR *strW; DWORD len; BOOL ret; if (!(LCType & LOCALE_USE_CP_ACP)) codepage = get_lcid_codepage( Locale ); if (!lpLCData) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } len = MultiByteToWideChar( codepage, 0, lpLCData, -1, NULL, 0 ); if (!(strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return FALSE; } MultiByteToWideChar( codepage, 0, lpLCData, -1, strW, len ); ret = SetLocaleInfoW( Locale, LCType, strW ); HeapFree( GetProcessHeap(), 0, strW ); return ret; } /********************************************************************** * @implemented * RIPPED FROM WINE's dlls\kernel\locale.c ver 0.9.29 * * SetLocaleInfoW (KERNEL32.@) * * See SetLocaleInfoA. * */ BOOL WINAPI SetLocaleInfoW ( LCID Locale, LCTYPE LCType, LPCWSTR lpLCData ) { const WCHAR *value; UNICODE_STRING valueW; NTSTATUS status; HANDLE hkey; LCType &= 0xffff; value = RosGetLocaleValueName( LCType ); if (!lpLCData || !value) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } if (LCType == LOCALE_IDATE || LCType == LOCALE_ILDATE) { SetLastError( ERROR_INVALID_FLAGS ); return FALSE; } if (!(hkey = RosCreateRegistryKey())) return FALSE; RtlInitUnicodeString( &valueW, value ); status = NtSetValueKey( hkey, &valueW, 0, REG_SZ, (PVOID)lpLCData, (lstrlenW(lpLCData)+1)*sizeof(WCHAR) ); if (LCType == LOCALE_SSHORTDATE || LCType == LOCALE_SLONGDATE) { /* Set I-value from S value */ WCHAR *lpD, *lpM, *lpY; WCHAR szBuff[2]; lpD = wcschr(lpLCData, 'd'); lpM = wcschr(lpLCData, 'M'); lpY = wcschr(lpLCData, 'y'); if (lpD <= lpM) { szBuff[0] = '1'; /* D-M-Y */ } else { if (lpY <= lpM) szBuff[0] = '2'; /* Y-M-D */ else szBuff[0] = '0'; /* M-D-Y */ } szBuff[1] = '\0'; if (LCType == LOCALE_SSHORTDATE) LCType = LOCALE_IDATE; else LCType = LOCALE_ILDATE; value = RosGetLocaleValueName( LCType ); RtlInitUnicodeString( &valueW, value ); status = NtSetValueKey( hkey, &valueW, 0, REG_SZ, szBuff, sizeof(szBuff) ); } NtClose( hkey ); if (status) SetLastError( RtlNtStatusToDosError(status) ); return !status; } /********************************************************************** * @implemented * RIPPED FROM WINE's dlls\kernel\locale.c rev 1.42 * * SetThreadLocale (KERNEL32.@) * * Set the current threads locale. * * PARAMS * lcid [I] LCID of the locale to set * * RETURNS * Success: TRUE. The threads locale is set to lcid. * Failure: FALSE. Use GetLastError() to determine the cause. * */ BOOL WINAPI SetThreadLocale( LCID lcid ) { DPRINT("SetThreadLocale(0x%04lX)\n", lcid); lcid = ConvertDefaultLocale(lcid); if (lcid != GetThreadLocale()) { if (!IsValidLocale(lcid, LCID_SUPPORTED)) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } NtCurrentTeb()->CurrentLocale = lcid; /* FIXME: NtCurrentTeb()->code_page = get_lcid_codepage( lcid ); * Wine save the acp for easy/fast access, but ROS has no such Teb member. * Maybe add this member to ros as well? */ /* Lag test app for å se om locale etc, endres i en app. etter at prosessen er startet, eller om bare nye prosesser blir berørt. */ } return TRUE; } /* * @implemented */ BOOL WINAPI SetUserDefaultLCID(LCID lcid) { NTSTATUS Status; Status = NtSetDefaultLocale(TRUE, lcid); if (!NT_SUCCESS(Status)) { SetLastErrorByStatus(Status); return 0; } return 1; } /* * @implemented */ BOOL WINAPI SetUserDefaultUILanguage(LANGID LangId) { NTSTATUS Status; Status = NtSetDefaultUILanguage(LangId); if (!NT_SUCCESS(Status)) { SetLastErrorByStatus(Status); return 0; } return 1; } /* * @implemented */ BOOL WINAPI SetUserGeoID( GEOID GeoId) { static const WCHAR geoW[] = {'G','e','o',0}; static const WCHAR nationW[] = {'N','a','t','i','o','n',0}; static const WCHAR formatW[] = {'%','i',0}; UNICODE_STRING nameW,keyW; WCHAR bufferW[10]; OBJECT_ATTRIBUTES attr; HANDLE hkey; if(!(hkey = create_registry_key())) return FALSE; attr.Length = sizeof(attr); attr.RootDirectory = hkey; attr.ObjectName = &nameW; attr.Attributes = 0; attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; RtlInitUnicodeString( &nameW, geoW ); RtlInitUnicodeString( &keyW, nationW ); if (NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS) { NtClose(attr.RootDirectory); return FALSE; } swprintf(bufferW, formatW, GeoId); NtSetValueKey(hkey, &keyW, 0, REG_SZ, bufferW, (wcslen(bufferW) + 1) * sizeof(WCHAR)); NtClose(attr.RootDirectory); NtClose(hkey); return TRUE; } /* * @implemented */ DWORD WINAPI VerLanguageNameA ( DWORD wLang, LPSTR szLang, DWORD nSize ) { return GetLocaleInfoA( MAKELCID(wLang, SORT_DEFAULT), LOCALE_SENGLANGUAGE, szLang, nSize ); } /* * @implemented */ DWORD WINAPI VerLanguageNameW ( DWORD wLang, LPWSTR szLang, DWORD nSize ) { return GetLocaleInfoW( MAKELCID(wLang, SORT_DEFAULT), LOCALE_SENGLANGUAGE, szLang, nSize ); } /*********************************************************************** * LCIDToLocaleName (KERNEL32.@) Wine 13.02.2009 */ INT WINAPI LCIDToLocaleName( LCID lcid, LPWSTR name, INT count, DWORD flags ) { if (flags) DPRINT1( "unsupported flags %x\n", flags ); return GetLocaleInfoW( lcid, LOCALE_SNAME | LOCALE_NOUSEROVERRIDE, name, count ); }