diff --git a/dlls/kernel/Makefile.in b/dlls/kernel/Makefile.in index da2d9e1cea7..92180d84db3 100644 --- a/dlls/kernel/Makefile.in +++ b/dlls/kernel/Makefile.in @@ -8,12 +8,14 @@ ALTNAMES = krnl386.exe comm.dll stress.dll system.dll toolhelp.dll windebug.dll LDIMPORTS = ntdll.dll C_SRCS = \ + $(TOPOBJDIR)/ole/ole2nls.c \ comm.c \ console.c \ debugger.c \ editline.c \ format_msg.c \ kernel_main.c \ + locale.c \ stress.c \ string.c \ sync.c \ diff --git a/dlls/kernel/kernel32.spec b/dlls/kernel/kernel32.spec index 728140e3c0c..c12f4db57e5 100644 --- a/dlls/kernel/kernel32.spec +++ b/dlls/kernel/kernel32.spec @@ -697,7 +697,7 @@ init MAIN_KernelInit @ stdcall SetLastError(long) SetLastError @ stdcall SetLocalTime(ptr) SetLocalTime @ stdcall SetLocaleInfoA(long long str) SetLocaleInfoA -@ stub SetLocaleInfoW +@ stdcall SetLocaleInfoW(long long wstr) SetLocaleInfoW @ stub SetMailslotInfo @ stdcall SetNamedPipeHandleState(long ptr ptr ptr) SetNamedPipeHandleState @ stdcall SetPriorityClass(long long) SetPriorityClass diff --git a/dlls/kernel/kernel_main.c b/dlls/kernel/kernel_main.c index 9b64f9c64bb..b3318d62001 100644 --- a/dlls/kernel/kernel_main.c +++ b/dlls/kernel/kernel_main.c @@ -38,7 +38,7 @@ #include "module.h" #include "task.h" -extern void CODEPAGE_Init(void); +extern void LOCALE_Init(void); extern BOOL RELAY_Init(void); extern int __wine_set_signal_handler(unsigned, int (*)(unsigned)); @@ -58,7 +58,7 @@ static BOOL process_attach(void) umask( FILE_umask ); /* Setup codepage info */ - CODEPAGE_Init(); + LOCALE_Init(); /* Initialize relay entry points */ if (!RELAY_Init()) return FALSE; diff --git a/dlls/kernel/locale.c b/dlls/kernel/locale.c new file mode 100644 index 00000000000..c442978a905 --- /dev/null +++ b/dlls/kernel/locale.c @@ -0,0 +1,886 @@ +/* + * Locale support + * + * Copyright 1995 Martin von Loewis + * Copyright 1998 David Lee Lambert + * Copyright 2000 Julio César Gázquez + * Copyright 2002 Alexandre Julliard for Codeweavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" /* for RT_STRINGW */ +#include "ntddk.h" +#include "wine/unicode.h" +#include "winnls.h" +#include "winerror.h" +#include "thread.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(nls); + +#define LOCALE_LOCALEINFOFLAGSMASK (LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP|LOCALE_RETURN_NUMBER) + +extern void CODEPAGE_Init( UINT ansi, UINT oem, UINT mac, LCID lcid ); + +#define NLS_MAX_LANGUAGES 20 +typedef struct { + char lang[128]; + char country[128]; + LANGID found_lang_id[NLS_MAX_LANGUAGES]; + char found_language[NLS_MAX_LANGUAGES][3]; + char found_country[NLS_MAX_LANGUAGES][3]; + int n_found; +} LANG_FIND_DATA; + + +/*********************************************************************** + * 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; +} + + +/*********************************************************************** + * update_registry + * + * Update registry contents on startup if the user locale has changed. + * This simulates the action of the Windows control panel. + */ +inline static void update_registry( LCID lcid ) +{ + char buffer[20]; + WCHAR bufferW[80]; + DWORD count = sizeof(buffer); + HKEY hkey; + + if (RegCreateKeyExA( HKEY_CURRENT_USER, "Control Panel\\International", 0, NULL, + 0, KEY_ALL_ACCESS, NULL, &hkey, NULL )) + return; /* don't do anything if we can't create the registry key */ + + if (!RegQueryValueExA( hkey, "Locale", NULL, NULL, (LPBYTE)buffer, &count )) + { + if (strtol( buffer, NULL, 16 ) == lcid) /* already set correctly */ + { + RegCloseKey( hkey ); + return; + } + TRACE( "updating registry, locale changed %s -> %08lx\n", buffer, lcid ); + } + else TRACE( "updating registry, locale changed none -> %08lx\n", lcid ); + + sprintf( buffer, "%08lx", lcid ); + RegSetValueExA( hkey, "Locale", 0, REG_SZ, (LPBYTE)buffer, strlen(buffer)+1 ); + RegCloseKey( hkey ); + +#define UPDATE_VALUE(lctype) do { \ + GetLocaleInfoW( lcid, (lctype)|LOCALE_NOUSEROVERRIDE, bufferW, sizeof(bufferW)/sizeof(WCHAR) ); \ + SetLocaleInfoW( lcid, (lctype), bufferW ); } while (0) + + UPDATE_VALUE(LOCALE_SLANGUAGE); + UPDATE_VALUE(LOCALE_SCOUNTRY); + UPDATE_VALUE(LOCALE_ICOUNTRY); + UPDATE_VALUE(LOCALE_S1159); + UPDATE_VALUE(LOCALE_S2359); + UPDATE_VALUE(LOCALE_STIME); + UPDATE_VALUE(LOCALE_ITIME); + UPDATE_VALUE(LOCALE_ITLZERO); + UPDATE_VALUE(LOCALE_SSHORTDATE); + UPDATE_VALUE(LOCALE_IDATE); + UPDATE_VALUE(LOCALE_SLONGDATE); + UPDATE_VALUE(LOCALE_SDATE); + UPDATE_VALUE(LOCALE_SCURRENCY); + UPDATE_VALUE(LOCALE_ICURRENCY); + UPDATE_VALUE(LOCALE_INEGCURR); + UPDATE_VALUE(LOCALE_ICURRDIGITS); + UPDATE_VALUE(LOCALE_SDECIMAL); + UPDATE_VALUE(LOCALE_SLIST); + UPDATE_VALUE(LOCALE_STHOUSAND); + UPDATE_VALUE(LOCALE_IDIGITS); + UPDATE_VALUE(LOCALE_ILZERO); + UPDATE_VALUE(LOCALE_IMEASURE); +#undef UPDATE_VALUE +} + + +/*********************************************************************** + * find_language_id_proc + */ +static BOOL CALLBACK find_language_id_proc( HMODULE hModule, LPCSTR type, + LPCSTR name, WORD LangID, LPARAM lParam ) +{ + LANG_FIND_DATA *l_data = (LANG_FIND_DATA *)lParam; + LCID lcid = MAKELCID(LangID, SORT_DEFAULT); + char buf_language[128]; + char buf_country[128]; + char buf_en_language[128]; + + TRACE("%04X\n", (UINT)LangID); + if(PRIMARYLANGID(LangID) == LANG_NEUTRAL) + return TRUE; /* continue search */ + + buf_language[0] = 0; + buf_country[0] = 0; + + GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME|LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP, + buf_language, sizeof(buf_language)); + TRACE("LOCALE_SISO639LANGNAME: %s\n", buf_language); + + GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME|LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP, + buf_country, sizeof(buf_country)); + TRACE("LOCALE_SISO3166CTRYNAME: %s\n", buf_country); + + if(l_data->lang && strlen(l_data->lang) > 0 && !strcasecmp(l_data->lang, buf_language)) + { + if(l_data->country && strlen(l_data->country) > 0) + { + if(!strcasecmp(l_data->country, buf_country)) + { + l_data->found_lang_id[0] = LangID; + l_data->n_found = 1; + TRACE("Found lang_id %04X for %s_%s\n", LangID, l_data->lang, l_data->country); + return FALSE; /* stop enumeration */ + } + } + else /* l_data->country not specified */ + { + if(l_data->n_found < NLS_MAX_LANGUAGES) + { + l_data->found_lang_id[l_data->n_found] = LangID; + strncpy(l_data->found_country[l_data->n_found], buf_country, 3); + strncpy(l_data->found_language[l_data->n_found], buf_language, 3); + l_data->n_found++; + TRACE("Found lang_id %04X for %s\n", LangID, l_data->lang); + return TRUE; /* continue search */ + } + } + } + + /* Just in case, check LOCALE_SENGLANGUAGE too, + * in hope that possible alias name might have that value. + */ + buf_en_language[0] = 0; + GetLocaleInfoA(lcid, LOCALE_SENGLANGUAGE|LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP, + buf_en_language, sizeof(buf_en_language)); + TRACE("LOCALE_SENGLANGUAGE: %s\n", buf_en_language); + + if(l_data->lang && strlen(l_data->lang) > 0 && !strcasecmp(l_data->lang, buf_en_language)) + { + l_data->found_lang_id[l_data->n_found] = LangID; + strncpy(l_data->found_country[l_data->n_found], buf_country, 3); + strncpy(l_data->found_language[l_data->n_found], buf_language, 3); + l_data->n_found++; + TRACE("Found lang_id %04X for %s\n", LangID, l_data->lang); + } + + return TRUE; /* continue search */ +} + + +/*********************************************************************** + * get_language_id + * + * INPUT: + * Lang: a string whose two first chars are the iso name of a language. + * Country: a string whose two first chars are the iso name of country + * Charset: a string defining the chosen charset encoding + * Dialect: a string defining a variation of the locale + * + * all those values are from the standardized format of locale + * name in unix which is: Lang[_Country][.Charset][@Dialect] + * + * RETURNS: + * the numeric code of the language used by Windows + * + * FIXME: Charset and Dialect are not handled + */ +static LANGID get_language_id(LPCSTR Lang, LPCSTR Country, LPCSTR Charset, LPCSTR Dialect) +{ + LANG_FIND_DATA l_data; + char lang_string[256]; + + if(!Lang) + { + l_data.found_lang_id[0] = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); + goto END; + } + + memset(&l_data, 0, sizeof(LANG_FIND_DATA)); + strncpy(l_data.lang, Lang, sizeof(l_data.lang)); + + if(Country && strlen(Country) > 0) + strncpy(l_data.country, Country, sizeof(l_data.country)); + + EnumResourceLanguagesA(GetModuleHandleA("KERNEL32"), RT_STRINGA, + (LPCSTR)LOCALE_ILANGUAGE, find_language_id_proc, (LPARAM)&l_data); + + strcpy(lang_string, l_data.lang); + if(l_data.country && strlen(l_data.country) > 0) + { + strcat(lang_string, "_"); + strcat(lang_string, l_data.country); + } + + if(!l_data.n_found) + { + if(l_data.country && strlen(l_data.country) > 0) + { + MESSAGE("Warning: Language '%s' was not found, retrying without country name...\n", lang_string); + l_data.country[0] = 0; + EnumResourceLanguagesA(GetModuleHandleA("KERNEL32"), RT_STRINGA, + (LPCSTR)LOCALE_ILANGUAGE, find_language_id_proc, (LONG)&l_data); + } + } + + /* Re-evaluate lang_string */ + strcpy(lang_string, l_data.lang); + if(l_data.country && strlen(l_data.country) > 0) + { + strcat(lang_string, "_"); + strcat(lang_string, l_data.country); + } + + if(!l_data.n_found) + { + MESSAGE("Warning: Language '%s' was not recognized, defaulting to English\n", lang_string); + l_data.found_lang_id[0] = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); + } + else + { + if(l_data.n_found == 1) + TRACE("For language '%s' lang_id %04X was found\n", lang_string, l_data.found_lang_id[0]); + else /* l_data->n_found > 1 */ + { + int i; + MESSAGE("For language '%s' several language ids were found:\n", lang_string); + for(i = 0; i < l_data.n_found; i++) + MESSAGE("%s_%s - %04X; ", l_data.found_language[i], l_data.found_country[i], l_data.found_lang_id[i]); + + MESSAGE("\nInstead of using first in the list, suggest to define\n" + "your LANG environment variable like this: LANG=%s_%s\n", + l_data.found_language[0], l_data.found_country[0]); + } + } +END: + TRACE("Returning %04X\n", l_data.found_lang_id[0]); + return l_data.found_lang_id[0]; +} + + +/*********************************************************************** + * init_default_lcid + */ +static LCID init_default_lcid(void) +{ + char buf[256]; + char *lang,*country,*charset,*dialect,*next; + LCID ret = 0; + + if (GetEnvironmentVariableA( "LC_ALL", buf, sizeof(buf) ) || + GetEnvironmentVariableA( "LC_CTYPE", buf, sizeof(buf) ) || + GetEnvironmentVariableA( "LANGUAGE", buf, sizeof(buf) ) || + GetEnvironmentVariableA( "LC_MESSAGES", buf, sizeof(buf) ) || + GetEnvironmentVariableA( "LANG", buf, sizeof(buf) )) + { + if (!strcmp(buf,"POSIX") || !strcmp(buf,"C")) goto done; + + lang=buf; + + do { + next=strchr(lang,':'); if (next) *next++='\0'; + dialect=strchr(lang,'@'); if (dialect) *dialect++='\0'; + charset=strchr(lang,'.'); if (charset) *charset++='\0'; + country=strchr(lang,'_'); if (country) *country++='\0'; + + ret = get_language_id(lang, country, charset, dialect); + + lang=next; + } while (lang && !ret); + + if (!ret) MESSAGE("Warning: language '%s' not recognized, defaulting to English\n", buf); + } + + done: + if (!ret) ret = MAKELCID( MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), SORT_DEFAULT) ; + return ret; +} + + +/****************************************************************************** + * get_locale_value_name + * + * Gets the registry value name for a given lctype. + */ +static const WCHAR *get_locale_value_name( DWORD lctype ) +{ + static const WCHAR iCalendarTypeW[] = {'i','C','a','l','e','n','d','a','r','T','y','p','e',0}; + static const WCHAR iCountryW[] = {'i','C','o','u','n','t','r','y',0}; + static const WCHAR iCurrDigitsW[] = {'i','C','u','r','r','D','i','g','i','t','s',0}; + static const WCHAR iCurrencyW[] = {'i','C','u','r','r','e','n','c','y',0}; + static const WCHAR iDateW[] = {'i','D','a','t','e',0}; + static const WCHAR iDigitsW[] = {'i','D','i','g','i','t','s',0}; + static const WCHAR iFirstDayOfWeekW[] = {'i','F','i','r','s','t','D','a','y','O','f','W','e','e','k',0}; + static const WCHAR iFirstWeekOfYearW[] = {'i','F','i','r','s','t','W','e','e','k','O','f','Y','e','a','r',0}; + static const WCHAR iLDateW[] = {'i','L','D','a','t','e',0}; + static const WCHAR iLZeroW[] = {'i','L','Z','e','r','o',0}; + static const WCHAR iMeasureW[] = {'i','M','e','a','s','u','r','e',0}; + static const WCHAR iNegCurrW[] = {'i','N','e','g','C','u','r','r',0}; + static const WCHAR iNegNumberW[] = {'i','N','e','g','N','u','m','b','e','r',0}; + static const WCHAR iPaperSizeW[] = {'i','P','a','p','e','r','S','i','z','e',0}; + static const WCHAR iTLZeroW[] = {'i','T','L','Z','e','r','o',0}; + static const WCHAR iTimeW[] = {'i','T','i','m','e',0}; + static const WCHAR s1159W[] = {'s','1','1','5','9',0}; + static const WCHAR s2359W[] = {'s','2','3','5','9',0}; + static const WCHAR sCountryW[] = {'s','C','o','u','n','t','r','y',0}; + static const WCHAR sCurrencyW[] = {'s','C','u','r','r','e','n','c','y',0}; + static const WCHAR sDateW[] = {'s','D','a','t','e',0}; + static const WCHAR sDecimalW[] = {'s','D','e','c','i','m','a','l',0}; + static const WCHAR sGroupingW[] = {'s','G','r','o','u','p','i','n','g',0}; + static const WCHAR sLanguageW[] = {'s','L','a','n','g','u','a','g','e',0}; + static const WCHAR sListW[] = {'s','L','i','s','t',0}; + static const WCHAR sLongDateW[] = {'s','L','o','n','g','D','a','t','e',0}; + static const WCHAR sMonDecimalSepW[] = {'s','M','o','n','D','e','c','i','m','a','l','S','e','p',0}; + static const WCHAR sMonGroupingW[] = {'s','M','o','n','G','r','o','u','p','i','n','g',0}; + static const WCHAR sMonThousandSepW[] = {'s','M','o','n','T','h','o','u','s','a','n','d','S','e','p',0}; + static const WCHAR sNegativeSignW[] = {'s','N','e','g','a','t','i','v','e','S','i','g','n',0}; + static const WCHAR sPositiveSignW[] = {'s','P','o','s','i','t','i','v','e','S','i','g','n',0}; + static const WCHAR sShortDateW[] = {'s','S','h','o','r','t','D','a','t','e',0}; + static const WCHAR sThousandW[] = {'s','T','h','o','u','s','a','n','d',0}; + static const WCHAR sTimeFormatW[] = {'s','T','i','m','e','F','o','r','m','a','t',0}; + static const WCHAR sTimeW[] = {'s','T','i','m','e',0}; + static const WCHAR sYearMonthW[] = {'s','Y','e','a','r','M','o','n','t','h',0}; + + 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 iCalendarTypeW; + case LOCALE_ICURRDIGITS: return iCurrDigitsW; + case LOCALE_ICURRENCY: return iCurrencyW; + case LOCALE_IDIGITS: return iDigitsW; + case LOCALE_IFIRSTDAYOFWEEK: return iFirstDayOfWeekW; + case LOCALE_IFIRSTWEEKOFYEAR: return iFirstWeekOfYearW; + case LOCALE_ILZERO: return iLZeroW; + case LOCALE_IMEASURE: return iMeasureW; + case LOCALE_INEGCURR: return iNegCurrW; + case LOCALE_INEGNUMBER: return iNegNumberW; + case LOCALE_IPAPERSIZE: return iPaperSizeW; + case LOCALE_ITIME: return iTimeW; + case LOCALE_S1159: return s1159W; + case LOCALE_S2359: return s2359W; + case LOCALE_SCURRENCY: return sCurrencyW; + case LOCALE_SDATE: return sDateW; + case LOCALE_SDECIMAL: return sDecimalW; + case LOCALE_SGROUPING: return sGroupingW; + case LOCALE_SLIST: return sListW; + case LOCALE_SLONGDATE: return sLongDateW; + case LOCALE_SMONDECIMALSEP: return sMonDecimalSepW; + case LOCALE_SMONGROUPING: return sMonGroupingW; + case LOCALE_SMONTHOUSANDSEP: return sMonThousandSepW; + case LOCALE_SNEGATIVESIGN: return sNegativeSignW; + case LOCALE_SPOSITIVESIGN: return sPositiveSignW; + case LOCALE_SSHORTDATE: return sShortDateW; + case LOCALE_STHOUSAND: return sThousandW; + case LOCALE_STIME: return sTimeW; + case LOCALE_STIMEFORMAT: return sTimeFormatW; + case LOCALE_SYEARMONTH: return sYearMonthW; + + /* The following are not listed under MSDN as supported, + * but seem to be used and also stored in the registry. + */ + case LOCALE_ICOUNTRY: return iCountryW; + case LOCALE_IDATE: return iDateW; + case LOCALE_ILDATE: return iLDateW; + case LOCALE_ITLZERO: return iTLZeroW; + case LOCALE_SCOUNTRY: return sCountryW; + case LOCALE_SLANGUAGE: return sLanguageW; + } + return NULL; +} + + +/****************************************************************************** + * get_registry_locale_info + * + * Retrieve user-modified locale info from the registry. + * Return length, 0 on error, -1 if not found. + */ +static INT get_registry_locale_info( LPCWSTR value, LPWSTR buffer, INT len ) +{ + DWORD size; + INT ret; + HKEY hkey; + NTSTATUS status; + UNICODE_STRING nameW; + KEY_VALUE_PARTIAL_INFORMATION *info; + static const int info_size = info->Data - (UCHAR *)info; + + if (RegOpenKeyExA( HKEY_CURRENT_USER, "Control Panel\\International", 0, KEY_READ, &hkey)) + return -1; + + RtlInitUnicodeString( &nameW, value ); + size = info_size + len * sizeof(WCHAR); + + if (!(info = HeapAlloc( GetProcessHeap(), 0, size ))) + { + RegCloseKey( hkey ); + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return 0; + } + + status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, info, size, &size ); + if (status == STATUS_BUFFER_OVERFLOW && !buffer) status = 0; + + if (!status) + { + ret = (size - info_size) / sizeof(WCHAR); + /* append terminating null if needed */ + if (!ret || ((WCHAR *)info->Data)[ret-1]) + { + if (ret < len || !buffer) ret++; + else + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + ret = 0; + } + } + if (ret && buffer) + { + memcpy( buffer, info->Data, (ret-1) * sizeof(WCHAR) ); + buffer[ret-1] = 0; + } + } + else + { + if (status == STATUS_OBJECT_NAME_NOT_FOUND) ret = -1; + else + { + SetLastError( RtlNtStatusToDosError(status) ); + ret = 0; + } + } + RegCloseKey( hkey ); + HeapFree( GetProcessHeap(), 0, info ); + return ret; +} + + +/****************************************************************************** + * GetLocaleInfoA (KERNEL32.@) + * + * NOTES + * LANG_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT + * + * MS online documentation states that the string returned is NULL terminated + * except for LOCALE_FONTSIGNATURE which "will return a non-NULL + * terminated 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 (!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; +} + + +/****************************************************************************** + * GetLocaleInfoA (KERNEL32.@) + * + * NOTES + * LANG_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT + * + * MS online documentation states that the string returned is NULL terminated + * except for LOCALE_FONTSIGNATURE which "will return a non-NULL + * terminated string". + */ +INT WINAPI GetLocaleInfoW( LCID lcid, LCTYPE lctype, LPWSTR buffer, INT len ) +{ + LANGID lang_id; + HRSRC hrsrc; + HGLOBAL hmem; + HMODULE hModule; + INT ret; + UINT lcflags; + const WCHAR *p; + int i; + + if (len < 0 || (len && !buffer)) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return 0; + } + if (!len) buffer = NULL; + + if (lcid == LOCALE_NEUTRAL || lcid == LANG_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID(); + else if (lcid == LANG_USER_DEFAULT) lcid = GetUserDefaultLCID(); + + lcflags = lctype & LOCALE_LOCALEINFOFLAGSMASK; + lctype &= ~LOCALE_LOCALEINFOFLAGSMASK; + + /* first check for overrides in the registry */ + + if (!(lcflags & LOCALE_NOUSEROVERRIDE) && lcid == GetUserDefaultLCID()) + { + const WCHAR *value = get_locale_value_name(lctype); + + if (value && ((ret = get_registry_locale_info( value, buffer, len )) != -1)) return ret; + } + + /* now load it from kernel resources */ + + lang_id = LANGIDFROMLCID( lcid ); + + /* replace SUBLANG_NEUTRAL by SUBLANG_DEFAULT */ + if (SUBLANGID(lang_id) == SUBLANG_NEUTRAL) + lang_id = MAKELANGID(PRIMARYLANGID(lang_id), SUBLANG_DEFAULT); + + hModule = GetModuleHandleA( "kernel32.dll" ); + if (!(hrsrc = FindResourceExW( hModule, RT_STRINGW, (LPCWSTR)((lctype >> 4) + 1), lang_id ))) + { + SetLastError( ERROR_INVALID_FLAGS ); /* no such lctype */ + return 0; + } + if (!(hmem = LoadResource( hModule, hrsrc ))) + return 0; + + p = LockResource( hmem ); + for (i = 0; i < (lctype & 0x0f); i++) p += *p + 1; + + if (lcflags & LOCALE_RETURN_NUMBER) ret = sizeof(UINT)/sizeof(WCHAR); + else ret = (lctype == LOCALE_FONTSIGNATURE) ? *p : *p + 1; + + if (!buffer) return ret; + + if (ret > len) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return 0; + } + + if (lcflags & LOCALE_RETURN_NUMBER) + { + UINT number; + WCHAR *end, *tmp = HeapAlloc( GetProcessHeap(), 0, (*p + 1) * sizeof(WCHAR) ); + if (!tmp) return 0; + memcpy( tmp, p + 1, *p * sizeof(WCHAR) ); + tmp[*p] = 0; + number = strtolW( tmp, &end, 10 ); + if (!*end) + memcpy( buffer, &number, sizeof(number) ); + else /* invalid number */ + { + SetLastError( ERROR_INVALID_FLAGS ); + ret = 0; + } + HeapFree( GetProcessHeap(), 0, tmp ); + + TRACE( "(lcid=0x%lx,lctype=0x%lx,%p,%d) returning number %d\n", + lcid, lctype, buffer, len, number ); + } + else + { + memcpy( buffer, p + 1, *p * sizeof(WCHAR) ); + if (lctype != LOCALE_FONTSIGNATURE) buffer[ret-1] = 0; + + TRACE( "(lcid=0x%lx,lctype=0x%lx,%p,%d) returning %d %s\n", + lcid, lctype, buffer, len, ret, debugstr_w(buffer) ); + } + return ret; +} + + +/****************************************************************************** + * SetLocaleInfoA [KERNEL32.@] + */ +BOOL WINAPI SetLocaleInfoA(LCID lcid, LCTYPE lctype, LPCSTR data) +{ + UINT codepage = CP_ACP; + WCHAR *strW; + DWORD len; + BOOL ret; + + if (lcid == LOCALE_NEUTRAL || lcid == LANG_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID(); + else if (lcid == LANG_USER_DEFAULT) lcid = GetUserDefaultLCID(); + + if (!(lctype & LOCALE_USE_CP_ACP)) codepage = get_lcid_codepage( lcid ); + len = MultiByteToWideChar( codepage, 0, data, -1, NULL, 0 ); + if (!(strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return FALSE; + } + MultiByteToWideChar( codepage, 0, data, -1, strW, len ); + ret = SetLocaleInfoW( lcid, lctype, strW ); + HeapFree( GetProcessHeap(), 0, strW ); + return ret; +} + + +/****************************************************************************** + * SetLocaleInfoW (KERNEL32.@) + */ +BOOL WINAPI SetLocaleInfoW( LCID lcid, LCTYPE lctype, LPCWSTR data ) +{ + const WCHAR *value; + const WCHAR intlW[] = {'i','n','t','l',0 }; + UNICODE_STRING valueW; + NTSTATUS status; + HKEY hkey; + + if (lcid == LOCALE_NEUTRAL || lcid == LANG_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID(); + else if (lcid == LANG_USER_DEFAULT) lcid = GetUserDefaultLCID(); + + if (!(value = get_locale_value_name( lctype ))) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + if (lcid != GetUserDefaultLCID()) return TRUE; /* fake success */ + + TRACE("setting %lx to %s\n", lctype, debugstr_w(data) ); + + /* FIXME: should check that data to set is sane */ + + /* FIXME: profile functions should map to registry */ + WriteProfileStringW( intlW, value, data ); + + if (RegCreateKeyExA( HKEY_CURRENT_USER, "Control Panel\\International", 0, NULL, + 0, KEY_ALL_ACCESS, NULL, &hkey, NULL )) return FALSE; + RtlInitUnicodeString( &valueW, value ); + status = NtSetValueKey( hkey, &valueW, 0, REG_SZ, data, (strlenW(data)+1)*sizeof(WCHAR) ); + RegCloseKey( hkey ); + + if (status) SetLastError( RtlNtStatusToDosError(status) ); + return !status; + return TRUE; +} + + +/*********************************************************************** + * GetThreadLocale (KERNEL32.@) + */ +LCID WINAPI GetThreadLocale(void) +{ + LCID ret = NtCurrentTeb()->CurrentLocale; + if (!ret) NtCurrentTeb()->CurrentLocale = ret = GetUserDefaultLCID(); + return ret; +} + + +/********************************************************************** + * SetThreadLocale (KERNEL32.@) + * + * FIXME + * check if lcid is a valid cp + */ +BOOL WINAPI SetThreadLocale( LCID lcid ) /* [in] Locale identifier */ +{ + if (lcid == LOCALE_NEUTRAL || lcid == LANG_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID(); + else if (lcid == LANG_USER_DEFAULT) lcid = GetUserDefaultLCID(); + + NtCurrentTeb()->CurrentLocale = lcid; + NtCurrentTeb()->code_page = get_lcid_codepage( lcid ); + return TRUE; +} + + + +/****************************************************************************** + * GetStringTypeW (KERNEL32.@) + */ +BOOL WINAPI GetStringTypeW( DWORD type, LPCWSTR src, INT count, LPWORD chartype ) +{ + if (count == -1) count = strlenW(src) + 1; + switch(type) + { + case CT_CTYPE1: + while (count--) *chartype++ = get_char_typeW( *src++ ) & 0xfff; + break; + case CT_CTYPE2: + while (count--) *chartype++ = get_char_typeW( *src++ ) >> 12; + break; + case CT_CTYPE3: + { + WARN("CT_CTYPE3: semi-stub.\n"); + while (count--) + { + int c = *src; + WORD type1, type3 = 0; /* C3_NOTAPPLICABLE */ + + type1 = get_char_typeW( *src++ ) & 0xfff; + /* try to construct type3 from type1 */ + if(type1 & C1_SPACE) type3 |= C3_SYMBOL; + if(type1 & C1_ALPHA) type3 |= C3_ALPHA; + if ((c>=0x30A0)&&(c<=0x30FF)) type3 |= C3_KATAKANA; + if ((c>=0x3040)&&(c<=0x309F)) type3 |= C3_HIRAGANA; + if ((c>=0x4E00)&&(c<=0x9FAF)) type3 |= C3_IDEOGRAPH; + if ((c>=0x0600)&&(c<=0x06FF)) type3 |= C3_KASHIDA; + if ((c>=0x3000)&&(c<=0x303F)) type3 |= C3_SYMBOL; + + if ((c>=0xFF00)&&(c<=0xFF60)) type3 |= C3_FULLWIDTH; + if ((c>=0xFF00)&&(c<=0xFF20)) type3 |= C3_SYMBOL; + if ((c>=0xFF3B)&&(c<=0xFF40)) type3 |= C3_SYMBOL; + if ((c>=0xFF5B)&&(c<=0xFF60)) type3 |= C3_SYMBOL; + if ((c>=0xFF21)&&(c<=0xFF3A)) type3 |= C3_ALPHA; + if ((c>=0xFF41)&&(c<=0xFF5A)) type3 |= C3_ALPHA; + if ((c>=0xFFE0)&&(c<=0xFFE6)) type3 |= C3_FULLWIDTH; + if ((c>=0xFFE0)&&(c<=0xFFE6)) type3 |= C3_SYMBOL; + + if ((c>=0xFF61)&&(c<=0xFFDC)) type3 |= C3_HALFWIDTH; + if ((c>=0xFF61)&&(c<=0xFF64)) type3 |= C3_SYMBOL; + if ((c>=0xFF65)&&(c<=0xFF9F)) type3 |= C3_KATAKANA; + if ((c>=0xFF65)&&(c<=0xFF9F)) type3 |= C3_ALPHA; + if ((c>=0xFFE8)&&(c<=0xFFEE)) type3 |= C3_HALFWIDTH; + if ((c>=0xFFE8)&&(c<=0xFFEE)) type3 |= C3_SYMBOL; + *chartype++ = type3; + } + break; + } + default: + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + return TRUE; +} + + +/****************************************************************************** + * GetStringTypeExW (KERNEL32.@) + */ +BOOL WINAPI GetStringTypeExW( LCID locale, DWORD type, LPCWSTR src, INT count, LPWORD chartype ) +{ + /* locale is ignored for Unicode */ + return GetStringTypeW( type, src, count, chartype ); +} + + +/****************************************************************************** + * GetStringTypeA (KERNEL32.@) + */ +BOOL WINAPI GetStringTypeA( LCID locale, DWORD type, LPCSTR src, INT count, LPWORD chartype ) +{ + UINT cp; + INT countW; + LPWSTR srcW; + BOOL ret = FALSE; + + if(count == -1) count = strlen(src) + 1; + + if (!(cp = get_lcid_codepage( locale ))) + { + FIXME("For locale %04lx using current ANSI code page\n", locale); + cp = GetACP(); + } + + countW = MultiByteToWideChar(cp, 0, src, count, NULL, 0); + if((srcW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR)))) + { + MultiByteToWideChar(cp, 0, src, count, srcW, countW); + /* + * NOTE: the target buffer has 1 word for each CHARACTER in the source + * string, with multibyte characters there maybe be more bytes in count + * than character space in the buffer! + */ + ret = GetStringTypeW(type, srcW, countW, chartype); + HeapFree(GetProcessHeap(), 0, srcW); + } + return ret; +} + +/****************************************************************************** + * GetStringTypeExA (KERNEL32.@) + */ +BOOL WINAPI GetStringTypeExA( LCID locale, DWORD type, LPCSTR src, INT count, LPWORD chartype ) +{ + return GetStringTypeA(locale, type, src, count, chartype); +} + + +/****************************************************************************** + * LOCALE_Init + */ +void LOCALE_Init(void) +{ + UINT ansi = 1252, oem = 437, mac = 10000; + LCID lcid = init_default_lcid(); + + GetLocaleInfoW( lcid, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, + (LPWSTR)&ansi, sizeof(ansi)/sizeof(WCHAR) ); + GetLocaleInfoW( lcid, LOCALE_IDEFAULTMACCODEPAGE | LOCALE_RETURN_NUMBER, + (LPWSTR)&mac, sizeof(mac)/sizeof(WCHAR) ); + GetLocaleInfoW( lcid, LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER, + (LPWSTR)&oem, sizeof(oem)/sizeof(WCHAR) ); + + CODEPAGE_Init( ansi, oem, mac, lcid ); + update_registry( lcid ); +} diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in index 1f6e8ea964e..056e1575e91 100644 --- a/dlls/ntdll/Makefile.in +++ b/dlls/ntdll/Makefile.in @@ -70,7 +70,6 @@ C_SRCS = \ $(TOPOBJDIR)/msdos/ioports.c \ $(TOPOBJDIR)/msdos/ppdev.c \ $(TOPOBJDIR)/msdos/vxd.c \ - $(TOPOBJDIR)/ole/ole2nls.c \ $(TOPOBJDIR)/relay32/builtin32.c \ $(TOPOBJDIR)/relay32/relay386.c \ $(TOPOBJDIR)/relay32/snoop.c \ @@ -131,7 +130,6 @@ EXTRASUBDIRS = \ $(TOPOBJDIR)/memory \ $(TOPOBJDIR)/misc \ $(TOPOBJDIR)/msdos \ - $(TOPOBJDIR)/ole \ $(TOPOBJDIR)/relay32 \ $(TOPOBJDIR)/scheduler \ $(TOPOBJDIR)/win32 diff --git a/include/thread.h b/include/thread.h index 44648ab9bb2..872529914e8 100644 --- a/include/thread.h +++ b/include/thread.h @@ -103,7 +103,8 @@ typedef struct _TEB DWORD unknown6[5]; /* --n 1e8 Unknown */ /* The following are Wine-specific fields (NT: GDI stuff) */ - DWORD unused[4]; /* --3 1fc Was server buffer */ + UINT code_page; /* --3 1fc Thread code page */ + DWORD unused[3]; /* --3 200 Was server buffer */ int request_fd; /* --3 20c fd for sending server requests */ int reply_fd; /* --3 210 fd for receiving server replies */ int wait_fd[2]; /* --3 214 fd for sleeping server requests */ diff --git a/include/winnls.h b/include/winnls.h index 7cec81bcba3..4f1bc7e3ce1 100644 --- a/include/winnls.h +++ b/include/winnls.h @@ -39,8 +39,6 @@ extern "C" { #define LOCALE_USE_CP_ACP 0x40000000 #define LOCALE_RETURN_NUMBER 0x20000000 -#define LOCALE_LOCALEINFOFLAGSMASK 0xC0000000 - /* When adding new defines, don't forget to add an entry to the * locale_name2id map in ole/ole2nls.c */ diff --git a/memory/codepage.c b/memory/codepage.c index fdfb03e39d5..a8f21e64ad7 100644 --- a/memory/codepage.c +++ b/memory/codepage.c @@ -27,6 +27,7 @@ #include "winerror.h" #include "winnls.h" #include "wine/unicode.h" +#include "thread.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(string); @@ -35,16 +36,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(string); static const union cptable *ansi_cptable; static const union cptable *oem_cptable; static const union cptable *mac_cptable; - -/* retrieve a code page table from the locale info */ -static const union cptable *get_locale_cp( LCID lcid, LCTYPE type ) -{ - const union cptable *table = NULL; - char buf[32]; - - if (GetLocaleInfoA( lcid, type, buf, sizeof(buf) )) table = cp_get_table( atoi(buf) ); - return table; -} +static LCID default_lcid = MAKELCID( MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), SORT_DEFAULT ); /* setup default codepage info before we can get at the locale stuff */ static void init_codepages(void) @@ -66,13 +58,18 @@ static const union cptable *get_codepage_table( unsigned int codepage ) switch(codepage) { - case CP_ACP: return ansi_cptable; - case CP_OEMCP: return oem_cptable; - case CP_MACCP: return mac_cptable; - case CP_THREAD_ACP: return get_locale_cp( GetThreadLocale(), LOCALE_IDEFAULTANSICODEPAGE ); + case CP_ACP: + return ansi_cptable; + case CP_OEMCP: + return oem_cptable; + case CP_MACCP: + return mac_cptable; case CP_UTF7: case CP_UTF8: break; + case CP_THREAD_ACP: + if (!(codepage = NtCurrentTeb()->code_page)) return ansi_cptable; + /* fall through */ default: if (codepage == ansi_cptable->info.codepage) return ansi_cptable; if (codepage == oem_cptable->info.codepage) return oem_cptable; @@ -86,17 +83,17 @@ static const union cptable *get_codepage_table( unsigned int codepage ) /* initialize default code pages from locale info */ /* FIXME: should be done in init_codepages, but it can't right now */ /* since it needs KERNEL32 to be loaded for the locale info. */ -void CODEPAGE_Init(void) +void CODEPAGE_Init( UINT ansi, UINT oem, UINT mac, LCID lcid ) { extern void __wine_init_codepages( const union cptable *ansi, const union cptable *oem ); const union cptable *table; - LCID lcid = GetUserDefaultLCID(); + default_lcid = lcid; if (!ansi_cptable) init_codepages(); /* just in case */ - if ((table = get_locale_cp( lcid, LOCALE_IDEFAULTANSICODEPAGE ))) ansi_cptable = table; - if ((table = get_locale_cp( lcid, LOCALE_IDEFAULTMACCODEPAGE ))) mac_cptable = table; - if ((table = get_locale_cp( lcid, LOCALE_IDEFAULTCODEPAGE ))) oem_cptable = table; + if ((table = cp_get_table( ansi ))) ansi_cptable = table; + if ((table = cp_get_table( oem ))) oem_cptable = table; + if ((table = cp_get_table( mac ))) mac_cptable = table; __wine_init_codepages( ansi_cptable, oem_cptable ); TRACE( "ansi=%03d oem=%03d mac=%03d\n", ansi_cptable->info.codepage, @@ -111,7 +108,7 @@ void CODEPAGE_Init(void) */ UINT WINAPI GetACP(void) { - if (!ansi_cptable) init_codepages(); + if (!ansi_cptable) return 1252; return ansi_cptable->info.codepage; } @@ -121,7 +118,7 @@ UINT WINAPI GetACP(void) */ UINT WINAPI GetOEMCP(void) { - if (!oem_cptable) init_codepages(); + if (!oem_cptable) return 437; return oem_cptable->info.codepage; } @@ -143,6 +140,42 @@ BOOL WINAPI IsValidCodePage( UINT codepage ) } +/*********************************************************************** + * GetUserDefaultLangID (KERNEL32.@) + */ +LANGID WINAPI GetUserDefaultLangID(void) +{ + return LANGIDFROMLCID(default_lcid); +} + + +/*********************************************************************** + * GetSystemDefaultLangID (KERNEL32.@) + */ +LANGID WINAPI GetSystemDefaultLangID(void) +{ + return GetUserDefaultLangID(); +} + + +/*********************************************************************** + * GetUserDefaultLCID (KERNEL32.@) + */ +LCID WINAPI GetUserDefaultLCID(void) +{ + return default_lcid; +} + + +/*********************************************************************** + * GetSystemDefaultLCID (KERNEL32.@) + */ +LCID WINAPI GetSystemDefaultLCID(void) +{ + return GetUserDefaultLCID(); +} + + /*********************************************************************** * IsDBCSLeadByteEx (KERNEL32.@) */ @@ -159,7 +192,7 @@ BOOL WINAPI IsDBCSLeadByteEx( UINT codepage, BYTE testchar ) */ BOOL WINAPI IsDBCSLeadByte( BYTE testchar ) { - if (!ansi_cptable) init_codepages(); + if (!ansi_cptable) return FALSE; return is_dbcs_leadbyte( ansi_cptable, testchar ); } @@ -383,118 +416,3 @@ INT WINAPI WideCharToMultiByte( UINT page, DWORD flags, LPCWSTR src, INT srclen, } return ret; } - - -/****************************************************************************** - * GetStringTypeW (KERNEL32.@) - * - */ -BOOL WINAPI GetStringTypeW( DWORD type, LPCWSTR src, INT count, LPWORD chartype ) -{ - if (count == -1) count = strlenW(src) + 1; - switch(type) - { - case CT_CTYPE1: - while (count--) *chartype++ = get_char_typeW( *src++ ) & 0xfff; - break; - case CT_CTYPE2: - while (count--) *chartype++ = get_char_typeW( *src++ ) >> 12; - break; - case CT_CTYPE3: - { - WARN("CT_CTYPE3: semi-stub.\n"); - while (count--) - { - int c = *src; - WORD type1, type3 = 0; /* C3_NOTAPPLICABLE */ - - type1 = get_char_typeW( *src++ ) & 0xfff; - /* try to construct type3 from type1 */ - if(type1 & C1_SPACE) type3 |= C3_SYMBOL; - if(type1 & C1_ALPHA) type3 |= C3_ALPHA; - if ((c>=0x30A0)&&(c<=0x30FF)) type3 |= C3_KATAKANA; - if ((c>=0x3040)&&(c<=0x309F)) type3 |= C3_HIRAGANA; - if ((c>=0x4E00)&&(c<=0x9FAF)) type3 |= C3_IDEOGRAPH; - if ((c>=0x0600)&&(c<=0x06FF)) type3 |= C3_KASHIDA; - if ((c>=0x3000)&&(c<=0x303F)) type3 |= C3_SYMBOL; - - if ((c>=0xFF00)&&(c<=0xFF60)) type3 |= C3_FULLWIDTH; - if ((c>=0xFF00)&&(c<=0xFF20)) type3 |= C3_SYMBOL; - if ((c>=0xFF3B)&&(c<=0xFF40)) type3 |= C3_SYMBOL; - if ((c>=0xFF5B)&&(c<=0xFF60)) type3 |= C3_SYMBOL; - if ((c>=0xFF21)&&(c<=0xFF3A)) type3 |= C3_ALPHA; - if ((c>=0xFF41)&&(c<=0xFF5A)) type3 |= C3_ALPHA; - if ((c>=0xFFE0)&&(c<=0xFFE6)) type3 |= C3_FULLWIDTH; - if ((c>=0xFFE0)&&(c<=0xFFE6)) type3 |= C3_SYMBOL; - - if ((c>=0xFF61)&&(c<=0xFFDC)) type3 |= C3_HALFWIDTH; - if ((c>=0xFF61)&&(c<=0xFF64)) type3 |= C3_SYMBOL; - if ((c>=0xFF65)&&(c<=0xFF9F)) type3 |= C3_KATAKANA; - if ((c>=0xFF65)&&(c<=0xFF9F)) type3 |= C3_ALPHA; - if ((c>=0xFFE8)&&(c<=0xFFEE)) type3 |= C3_HALFWIDTH; - if ((c>=0xFFE8)&&(c<=0xFFEE)) type3 |= C3_SYMBOL; - *chartype++ = type3; - } - break; - } - default: - SetLastError( ERROR_INVALID_PARAMETER ); - return FALSE; - } - return TRUE; -} - - -/****************************************************************************** - * GetStringTypeExW (KERNEL32.@) - */ -BOOL WINAPI GetStringTypeExW( LCID locale, DWORD type, LPCWSTR src, INT count, LPWORD chartype ) -{ - /* locale is ignored for Unicode */ - return GetStringTypeW( type, src, count, chartype ); -} - -/****************************************************************************** - * GetStringTypeA [KERNEL32.@] - */ -BOOL WINAPI GetStringTypeA(LCID locale, DWORD type, LPCSTR src, INT count, LPWORD chartype) -{ - char buf[20]; - UINT cp; - INT countW; - LPWSTR srcW; - BOOL ret = FALSE; - - if(count == -1) count = strlen(src) + 1; - - if(!GetLocaleInfoA(locale, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_NOUSEROVERRIDE, - buf, sizeof(buf))) - { - FIXME("For locale %04lx using current ANSI code page\n", locale); - cp = GetACP(); - } - else - cp = atoi(buf); - - countW = MultiByteToWideChar(cp, 0, src, count, NULL, 0); - if((srcW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR)))) - { - MultiByteToWideChar(cp, 0, src, count, srcW, countW); - /* - * NOTE: the target buffer has 1 word for each CHARACTER in the source - * string, with multibyte characters there maybe be more bytes in count - * than character space in the buffer! - */ - ret = GetStringTypeW(type, srcW, countW, chartype); - HeapFree(GetProcessHeap(), 0, srcW); - } - return ret; -} - -/****************************************************************************** - * GetStringTypeExA [KERNEL32.@] - */ -BOOL WINAPI GetStringTypeExA(LCID locale, DWORD type, LPCSTR src, INT count, LPWORD chartype) -{ - return GetStringTypeA(locale, type, src, count, chartype); -} diff --git a/memory/string.c b/memory/string.c index af229d2f50e..8e33fa2103a 100644 --- a/memory/string.c +++ b/memory/string.c @@ -117,58 +117,6 @@ SEGPTR WINAPI lstrcatn16( SEGPTR dst, LPCSTR src, INT16 n ) } -/*********************************************************************** - * lstrcmp (KERNEL32.@) - * lstrcmpA (KERNEL32.@) - */ -INT WINAPI lstrcmpA( LPCSTR str1, LPCSTR str2 ) -{ - return CompareStringA(LOCALE_SYSTEM_DEFAULT,0,str1,-1,str2,-1) - 2 ; -} - - -/*********************************************************************** - * lstrcmpW (KERNEL32.@) - * FIXME : should call CompareStringW, when it is implemented. - * This implementation is not "word sort", as it should. - */ -INT WINAPI lstrcmpW( LPCWSTR str1, LPCWSTR str2 ) -{ - TRACE("%s and %s\n", - debugstr_w (str1), debugstr_w (str2)); - if (!str1 || !str2) { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - while (*str1 && (*str1 == *str2)) { str1++; str2++; } - return (INT)(*str1 - *str2); -} - - -/*********************************************************************** - * lstrcmpi (KERNEL32.@) - * lstrcmpiA (KERNEL32.@) - */ -INT WINAPI lstrcmpiA( LPCSTR str1, LPCSTR str2 ) -{ TRACE("strcmpi %s and %s\n", - debugstr_a (str1), debugstr_a (str2)); - return CompareStringA(LOCALE_SYSTEM_DEFAULT,NORM_IGNORECASE,str1,-1,str2,-1)-2; -} - - -/*********************************************************************** - * lstrcmpiW (KERNEL32.@) - */ -INT WINAPI lstrcmpiW( LPCWSTR str1, LPCWSTR str2 ) -{ - if (!str1 || !str2) { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - return strcmpiW( str1, str2 ); -} - - /*********************************************************************** * lstrcpy (KERNEL.88) */ diff --git a/ole/ole2nls.c b/ole/ole2nls.c index af15c0cffa7..7fe5ae13139 100644 --- a/ole/ole2nls.c +++ b/ole/ole2nls.c @@ -33,6 +33,7 @@ #include "winbase.h" #include "wingdi.h" #include "winuser.h" +#include "ntddk.h" #include "wine/unicode.h" #include "winver.h" #include "winnls.h" @@ -40,365 +41,8 @@ #include "winerror.h" #include "wine/debug.h" -WINE_DEFAULT_DEBUG_CHANNEL(string); +WINE_DEFAULT_DEBUG_CHANNEL(nls); -/* Locale name to id map. used by EnumSystemLocales, GetLocaleInfoA - * MUST contain all #defines from winnls.h - * last entry has NULL name, 0 id. - */ -#define LOCALE_ENTRY(x) {#x,LOCALE_##x} -static const struct tagLOCALE_NAME2ID { - const char *name; - LCTYPE id; -} locale_name2id[]= { - LOCALE_ENTRY(ILANGUAGE), - LOCALE_ENTRY(SLANGUAGE), - LOCALE_ENTRY(SENGLANGUAGE), - LOCALE_ENTRY(SABBREVLANGNAME), - LOCALE_ENTRY(SNATIVELANGNAME), - LOCALE_ENTRY(ICOUNTRY), - LOCALE_ENTRY(SCOUNTRY), - LOCALE_ENTRY(SENGCOUNTRY), - LOCALE_ENTRY(SABBREVCTRYNAME), - LOCALE_ENTRY(SNATIVECTRYNAME), - LOCALE_ENTRY(IDEFAULTLANGUAGE), - LOCALE_ENTRY(IDEFAULTCOUNTRY), - LOCALE_ENTRY(IDEFAULTCODEPAGE), - LOCALE_ENTRY(IDEFAULTANSICODEPAGE), - LOCALE_ENTRY(IDEFAULTMACCODEPAGE), - LOCALE_ENTRY(SLIST), - LOCALE_ENTRY(IMEASURE), - LOCALE_ENTRY(SDECIMAL), - LOCALE_ENTRY(STHOUSAND), - LOCALE_ENTRY(SGROUPING), - LOCALE_ENTRY(IDIGITS), - LOCALE_ENTRY(ILZERO), - LOCALE_ENTRY(INEGNUMBER), - LOCALE_ENTRY(SNATIVEDIGITS), - LOCALE_ENTRY(SCURRENCY), - LOCALE_ENTRY(SINTLSYMBOL), - LOCALE_ENTRY(SMONDECIMALSEP), - LOCALE_ENTRY(SMONTHOUSANDSEP), - LOCALE_ENTRY(SMONGROUPING), - LOCALE_ENTRY(ICURRDIGITS), - LOCALE_ENTRY(IINTLCURRDIGITS), - LOCALE_ENTRY(ICURRENCY), - LOCALE_ENTRY(INEGCURR), - LOCALE_ENTRY(SDATE), - LOCALE_ENTRY(STIME), - LOCALE_ENTRY(SSHORTDATE), - LOCALE_ENTRY(SLONGDATE), - LOCALE_ENTRY(STIMEFORMAT), - LOCALE_ENTRY(IDATE), - LOCALE_ENTRY(ILDATE), - LOCALE_ENTRY(ITIME), - LOCALE_ENTRY(ITIMEMARKPOSN), - LOCALE_ENTRY(ICENTURY), - LOCALE_ENTRY(ITLZERO), - LOCALE_ENTRY(IDAYLZERO), - LOCALE_ENTRY(IMONLZERO), - LOCALE_ENTRY(S1159), - LOCALE_ENTRY(S2359), - LOCALE_ENTRY(ICALENDARTYPE), - LOCALE_ENTRY(IOPTIONALCALENDAR), - LOCALE_ENTRY(IFIRSTDAYOFWEEK), - LOCALE_ENTRY(IFIRSTWEEKOFYEAR), - LOCALE_ENTRY(SDAYNAME1), - LOCALE_ENTRY(SDAYNAME2), - LOCALE_ENTRY(SDAYNAME3), - LOCALE_ENTRY(SDAYNAME4), - LOCALE_ENTRY(SDAYNAME5), - LOCALE_ENTRY(SDAYNAME6), - LOCALE_ENTRY(SDAYNAME7), - LOCALE_ENTRY(SABBREVDAYNAME1), - LOCALE_ENTRY(SABBREVDAYNAME2), - LOCALE_ENTRY(SABBREVDAYNAME3), - LOCALE_ENTRY(SABBREVDAYNAME4), - LOCALE_ENTRY(SABBREVDAYNAME5), - LOCALE_ENTRY(SABBREVDAYNAME6), - LOCALE_ENTRY(SABBREVDAYNAME7), - LOCALE_ENTRY(SMONTHNAME1), - LOCALE_ENTRY(SMONTHNAME2), - LOCALE_ENTRY(SMONTHNAME3), - LOCALE_ENTRY(SMONTHNAME4), - LOCALE_ENTRY(SMONTHNAME5), - LOCALE_ENTRY(SMONTHNAME6), - LOCALE_ENTRY(SMONTHNAME7), - LOCALE_ENTRY(SMONTHNAME8), - LOCALE_ENTRY(SMONTHNAME9), - LOCALE_ENTRY(SMONTHNAME10), - LOCALE_ENTRY(SMONTHNAME11), - LOCALE_ENTRY(SMONTHNAME12), - LOCALE_ENTRY(SMONTHNAME13), - LOCALE_ENTRY(SABBREVMONTHNAME1), - LOCALE_ENTRY(SABBREVMONTHNAME2), - LOCALE_ENTRY(SABBREVMONTHNAME3), - LOCALE_ENTRY(SABBREVMONTHNAME4), - LOCALE_ENTRY(SABBREVMONTHNAME5), - LOCALE_ENTRY(SABBREVMONTHNAME6), - LOCALE_ENTRY(SABBREVMONTHNAME7), - LOCALE_ENTRY(SABBREVMONTHNAME8), - LOCALE_ENTRY(SABBREVMONTHNAME9), - LOCALE_ENTRY(SABBREVMONTHNAME10), - LOCALE_ENTRY(SABBREVMONTHNAME11), - LOCALE_ENTRY(SABBREVMONTHNAME12), - LOCALE_ENTRY(SABBREVMONTHNAME13), - LOCALE_ENTRY(SPOSITIVESIGN), - LOCALE_ENTRY(SNEGATIVESIGN), - LOCALE_ENTRY(IPOSSIGNPOSN), - LOCALE_ENTRY(INEGSIGNPOSN), - LOCALE_ENTRY(IPOSSYMPRECEDES), - LOCALE_ENTRY(IPOSSEPBYSPACE), - LOCALE_ENTRY(INEGSYMPRECEDES), - LOCALE_ENTRY(INEGSEPBYSPACE), - LOCALE_ENTRY(FONTSIGNATURE), - LOCALE_ENTRY(SISO639LANGNAME), - LOCALE_ENTRY(SISO3166CTRYNAME), - {NULL,0} -}; - -static char *GetLocaleSubkeyName( DWORD lctype ); - -/*********************************************************************** - * GetUserDefaultLCID (KERNEL32.@) - */ -LCID WINAPI GetUserDefaultLCID(void) -{ - return MAKELCID( GetUserDefaultLangID() , SORT_DEFAULT ); -} - -/*********************************************************************** - * GetSystemDefaultLCID (KERNEL32.@) - */ -LCID WINAPI GetSystemDefaultLCID(void) -{ - return GetUserDefaultLCID(); -} - -#define NLS_MAX_LANGUAGES 20 -typedef struct { - char lang[128]; - char country[128]; - LANGID found_lang_id[NLS_MAX_LANGUAGES]; - char found_language[NLS_MAX_LANGUAGES][3]; - char found_country[NLS_MAX_LANGUAGES][3]; - int n_found; -} LANG_FIND_DATA; - -static BOOL CALLBACK NLS_FindLanguageID_ProcA(HMODULE hModule, LPCSTR type, - LPCSTR name, WORD LangID, LONG lParam) -{ - LANG_FIND_DATA *l_data = (LANG_FIND_DATA *)lParam; - LCID lcid = MAKELCID(LangID, SORT_DEFAULT); - char buf_language[128]; - char buf_country[128]; - char buf_en_language[128]; - - TRACE("%04X\n", (UINT)LangID); - if(PRIMARYLANGID(LangID) == LANG_NEUTRAL) - return TRUE; /* continue search */ - - buf_language[0] = 0; - buf_country[0] = 0; - - GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME|LOCALE_NOUSEROVERRIDE, - buf_language, sizeof(buf_language)); - TRACE("LOCALE_SISO639LANGNAME: %s\n", buf_language); - - GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME|LOCALE_NOUSEROVERRIDE, - buf_country, sizeof(buf_country)); - TRACE("LOCALE_SISO3166CTRYNAME: %s\n", buf_country); - - if(l_data->lang && strlen(l_data->lang) > 0 && !strcasecmp(l_data->lang, buf_language)) - { - if(l_data->country && strlen(l_data->country) > 0) - { - if(!strcasecmp(l_data->country, buf_country)) - { - l_data->found_lang_id[0] = LangID; - l_data->n_found = 1; - TRACE("Found lang_id %04X for %s_%s\n", LangID, l_data->lang, l_data->country); - return FALSE; /* stop enumeration */ - } - } - else /* l_data->country not specified */ - { - if(l_data->n_found < NLS_MAX_LANGUAGES) - { - l_data->found_lang_id[l_data->n_found] = LangID; - strncpy(l_data->found_country[l_data->n_found], buf_country, 3); - strncpy(l_data->found_language[l_data->n_found], buf_language, 3); - l_data->n_found++; - TRACE("Found lang_id %04X for %s\n", LangID, l_data->lang); - return TRUE; /* continue search */ - } - } - } - - /* Just in case, check LOCALE_SENGLANGUAGE too, - * in hope that possible alias name might have that value. - */ - buf_en_language[0] = 0; - GetLocaleInfoA(lcid, LOCALE_SENGLANGUAGE|LOCALE_NOUSEROVERRIDE, - buf_en_language, sizeof(buf_en_language)); - TRACE("LOCALE_SENGLANGUAGE: %s\n", buf_en_language); - - if(l_data->lang && strlen(l_data->lang) > 0 && !strcasecmp(l_data->lang, buf_en_language)) - { - l_data->found_lang_id[l_data->n_found] = LangID; - strncpy(l_data->found_country[l_data->n_found], buf_country, 3); - strncpy(l_data->found_language[l_data->n_found], buf_language, 3); - l_data->n_found++; - TRACE("Found lang_id %04X for %s\n", LangID, l_data->lang); - } - - return TRUE; /* continue search */ -} - -/*********************************************************************** - * NLS_GetLanguageID - * - * INPUT: - * Lang: a string whose two first chars are the iso name of a language. - * Country: a string whose two first chars are the iso name of country - * Charset: a string defining the chossen charset encoding - * Dialect: a string defining a variation of the locale - * - * all those values are from the standardized format of locale - * name in unix which is: Lang[_Country][.Charset][@Dialect] - * - * RETURNS: - * the numeric code of the language used by Windows - * - * FIXME: Charset and Dialect are not handled - */ -static LANGID NLS_GetLanguageID(LPCSTR Lang, LPCSTR Country, LPCSTR Charset, LPCSTR Dialect) -{ - LANG_FIND_DATA l_data; - char lang_string[256]; - - if(!Lang) - { - l_data.found_lang_id[0] = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); - goto END; - } - - memset(&l_data, 0, sizeof(LANG_FIND_DATA)); - strncpy(l_data.lang, Lang, sizeof(l_data.lang)); - - if(Country && strlen(Country) > 0) - strncpy(l_data.country, Country, sizeof(l_data.country)); - - EnumResourceLanguagesA(GetModuleHandleA("KERNEL32"), RT_STRINGA, - (LPCSTR)LOCALE_ILANGUAGE, NLS_FindLanguageID_ProcA, (LONG)&l_data); - - strcpy(lang_string, l_data.lang); - if(l_data.country && strlen(l_data.country) > 0) - { - strcat(lang_string, "_"); - strcat(lang_string, l_data.country); - } - - if(!l_data.n_found) - { - if(l_data.country && strlen(l_data.country) > 0) - { - MESSAGE("Warning: Language '%s' was not found, retrying without country name...\n", lang_string); - l_data.country[0] = 0; - EnumResourceLanguagesA(GetModuleHandleA("KERNEL32"), RT_STRINGA, - (LPCSTR)LOCALE_ILANGUAGE, NLS_FindLanguageID_ProcA, (LONG)&l_data); - } - } - - /* Re-evaluate lang_string */ - strcpy(lang_string, l_data.lang); - if(l_data.country && strlen(l_data.country) > 0) - { - strcat(lang_string, "_"); - strcat(lang_string, l_data.country); - } - - if(!l_data.n_found) - { - MESSAGE("Warning: Language '%s' was not recognized, defaulting to English\n", lang_string); - l_data.found_lang_id[0] = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); - } - else - { - if(l_data.n_found == 1) - TRACE("For language '%s' lang_id %04X was found\n", lang_string, l_data.found_lang_id[0]); - else /* l_data->n_found > 1 */ - { - int i; - MESSAGE("For language '%s' several language ids were found:\n", lang_string); - for(i = 0; i < l_data.n_found; i++) - MESSAGE("%s_%s - %04X; ", l_data.found_language[i], l_data.found_country[i], l_data.found_lang_id[i]); - - MESSAGE("\nInstead of using first in the list, suggest to define\n" - "your LANG environment variable like this: LANG=%s_%s\n", - l_data.found_language[0], l_data.found_country[0]); - } - } -END: - TRACE("Returning %04X\n", l_data.found_lang_id[0]); - return l_data.found_lang_id[0]; -} - -/*********************************************************************** - * GetUserDefaultLangID (KERNEL32.@) - */ -LANGID WINAPI GetUserDefaultLangID(void) -{ - /* caching result, if defined from environment, which should (?) not change during a WINE session */ - static LANGID userLCID = 0; - - if (userLCID == 0) - { - char buf[256]; - char *lang,*country,*charset,*dialect,*next; - - if (GetEnvironmentVariableA( "LANGUAGE", buf, sizeof(buf) )) goto ok; - if (GetEnvironmentVariableA( "LANG", buf, sizeof(buf) )) goto ok; - if (GetEnvironmentVariableA( "LC_ALL", buf, sizeof(buf) )) goto ok; - if (GetEnvironmentVariableA( "LC_MESSAGES", buf, sizeof(buf) )) goto ok; - if (GetEnvironmentVariableA( "LC_CTYPE", buf, sizeof(buf) )) goto ok; - - return userLCID = MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ); - - ok: - if (!strcmp(buf,"POSIX") || !strcmp(buf,"C")) - return userLCID = MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ); - - lang=buf; - - do { - next=strchr(lang,':'); if (next) *next++='\0'; - dialect=strchr(lang,'@'); if (dialect) *dialect++='\0'; - charset=strchr(lang,'.'); if (charset) *charset++='\0'; - country=strchr(lang,'_'); if (country) *country++='\0'; - - userLCID = NLS_GetLanguageID(lang, country, charset, dialect); - - lang=next; - } while (lang && !userLCID); - - if (!userLCID) - { - MESSAGE( "Warning: language '%s' not recognized, defaulting to English\n", - buf ); - userLCID = MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ); - } - } - return userLCID; -} - -/*********************************************************************** - * GetSystemDefaultLangID (KERNEL32.@) - */ -LANGID WINAPI GetSystemDefaultLangID(void) -{ - return GetUserDefaultLangID(); -} /****************************************************************************** * ConvertDefaultLocale (KERNEL32.@) @@ -415,357 +59,6 @@ LCID WINAPI ConvertDefaultLocale (LCID lcid) return MAKELANGID( PRIMARYLANGID(lcid), SUBLANG_NEUTRAL); } -/* Enhanced version of LoadStringW. - * It takes LanguageId to find and load language dependant resources. - * Resource is copied as is: "binary" strings are not truncated. - * Return: length of resource + 1 to distinguish absent resources - * from the resources with zero length. - */ -static INT NLS_LoadStringExW(HMODULE hModule, LANGID lang_id, UINT res_id, LPWSTR buffer, INT buflen) -{ - HRSRC hrsrc; - HGLOBAL hmem; - WCHAR *p; - int string_num; - int i; - - /* Replace SUBLANG_NEUTRAL by SUBLANG_DEFAULT */ - if(SUBLANGID(lang_id) == SUBLANG_NEUTRAL) - lang_id = MAKELANGID(PRIMARYLANGID(lang_id), SUBLANG_DEFAULT); - - hrsrc = FindResourceExW(hModule, RT_STRINGW, (LPCWSTR)((res_id >> 4) + 1), lang_id); - - if(!hrsrc) return 0; - hmem = LoadResource(hModule, hrsrc); - if(!hmem) return 0; - - p = LockResource(hmem); - string_num = res_id & 0x000f; - for(i = 0; i < string_num; i++) - p += *p + 1; - - TRACE("strlen = %d\n", (int)*p ); - - if (buffer == NULL) return *p; - i = min(buflen - 1, *p); - if (i > 0) { - memcpy(buffer, p + 1, i * sizeof (WCHAR)); - buffer[i] = (WCHAR) 0; - } else { - if (buflen > 1) - buffer[0] = (WCHAR) 0; - } - - FreeResource(hmem); - TRACE("%s loaded!\n", debugstr_w(buffer)); - return (i + 1); -} - -/****************************************************************************** - * GetLocaleInfoA (KERNEL32.@) - * - * NOTES - * LANG_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT - * - * MS online documentation states that the string returned is NULL terminated - * except for LOCALE_FONTSIGNATURE which "will return a non-NULL - * terminated string". - */ -INT WINAPI GetLocaleInfoA(LCID lcid,LCTYPE LCType,LPSTR buf,INT len) -{ - LPCSTR retString = NULL; - int found = 0, i; - char *pacKey; - char acBuffer[128]; - DWORD dwBufferSize=128; - BOOL NoUserOverride; - - TRACE("(lcid=0x%lx,lctype=0x%lx,%p,%x)\n",lcid,LCType,buf,len); - - if (len && (! buf) ) { - SetLastError(ERROR_INSUFFICIENT_BUFFER); - return 0; - } - - if (lcid == LOCALE_NEUTRAL || lcid == LANG_SYSTEM_DEFAULT) - { - lcid = GetSystemDefaultLCID(); - } - else if (lcid == LANG_USER_DEFAULT) /*0x800*/ - { - lcid = GetUserDefaultLCID(); - } - - /* LOCALE_NOUSEROVERRIDE means: do not get user redefined settings - from the registry. Instead, use system default values. */ - NoUserOverride = (LCType & LOCALE_NOUSEROVERRIDE) != 0; - - LCType &= ~(LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP); - - /* First, check if it's in the registry. */ - /* All user customized values are stored in the registry by SetLocaleInfo */ - if ( !NoUserOverride && (pacKey = GetLocaleSubkeyName(LCType)) ) - { - char acRealKey[128]; - HKEY hKey; - - sprintf( acRealKey, "Control Panel\\International\\%s", pacKey ); - - if ( RegOpenKeyExA( HKEY_CURRENT_USER, acRealKey, - 0, KEY_READ, &hKey) == ERROR_SUCCESS ) - { - if ( RegQueryValueExA( hKey, NULL, NULL, NULL, (LPBYTE)acBuffer, - &dwBufferSize ) == ERROR_SUCCESS ) - { - retString = acBuffer; - found = 1; - } - RegCloseKey(hKey); - } - } - - /* If not in the registry, get it from the NLS entries. */ - if(!found) { - WCHAR wcBuffer[128]; - int res_size; - - /* check if language is registered in the kernel32 resources */ - if((res_size = NLS_LoadStringExW(GetModuleHandleA("KERNEL32"), LANGIDFROMLCID(lcid), - LCType, wcBuffer, sizeof(wcBuffer)/sizeof(wcBuffer[0])))) { - WideCharToMultiByte(CP_ACP, 0, wcBuffer, res_size, acBuffer, dwBufferSize, NULL, NULL); - retString = acBuffer; - found = 1; - } - } - - /* if not found report a most descriptive error */ - if(!found) { - retString=0; - /* If we are through all of this, retLen should not be zero anymore. - If it is, the value is not supported */ - i=0; - while (locale_name2id[i].name!=NULL) { - if (LCType == locale_name2id[i].id) { - retString = locale_name2id[i].name; - break; - } - i++; - } - if(!retString) - FIXME("Unkown LC type %lX\n", LCType); - else - FIXME("'%s' is not defined for your language (%04X).\n" - "Please define it in dlls/kernel/nls/YourLanguage.nls\n" - "and submit patch for inclusion into the next Wine release.\n", - retString, LOWORD(lcid)); - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - - /* a FONTSIGNATURE is not a string, just 6 DWORDs */ - if (LCType == LOCALE_FONTSIGNATURE) { - if (len) { - len = (len < sizeof(FONTSIGNATURE)) ? len : sizeof(FONTSIGNATURE); - memcpy(buf, retString, len); - return len; - } - return sizeof(FONTSIGNATURE); - } - /* if len=0 return only the length, don't touch the buffer*/ - if (len) { - /* Like Windows we copy len bytes to buffer and we check len after */ - INT ret = strlen(retString) + 1; - memcpy( buf, retString, min(len, ret) ); - return (len < ret) ? 0 : ret; - } - return strlen(retString)+1; -} - -/****************************************************************************** - * GetLocaleInfoW (KERNEL32.@) - * - * NOTES - * MS documentation states that len "specifies the size, in bytes (ANSI version) - * or characters (Unicode version), of" wbuf. Thus the number returned is - * the same between GetLocaleInfoW and GetLocaleInfoA. - */ -INT WINAPI GetLocaleInfoW(LCID lcid,LCTYPE LCType,LPWSTR wbuf,INT len) -{ WORD wlen; - LPSTR abuf; - - if (len && (! wbuf) ) - { SetLastError(ERROR_INSUFFICIENT_BUFFER); - return 0; - } - - abuf = (LPSTR)HeapAlloc(GetProcessHeap(),0,len); - wlen = GetLocaleInfoA(lcid, LCType, abuf, len); - - if (wlen && len) /* if len=0 return only the length*/ - MultiByteToWideChar( CP_ACP, 0, abuf, -1, wbuf, len ); - - HeapFree(GetProcessHeap(),0,abuf); - return wlen; -} - -/****************************************************************************** - * - * GetLocaleSubkeyName [helper function] - * - * - For use with the registry. - * - Gets the registry subkey name for a given lctype. - */ -static char *GetLocaleSubkeyName( DWORD lctype ) -{ - char *pacKey=NULL; - - switch ( lctype ) - { - /* These values are used by SetLocaleInfo and GetLocaleInfo, and - * the values are stored in the registry, confirmed under Windows, - * for the ones that actually assign pacKey. Cases that aren't finished - * have not been confirmed, so that must be done before they can be - * added. - */ - case LOCALE_SDATE : /* The date separator. */ - pacKey = "sDate"; - break; - case LOCALE_ICURRDIGITS: - pacKey = "iCurrDigits"; - break; - case LOCALE_SDECIMAL : - pacKey = "sDecimal"; - break; - case LOCALE_ICURRENCY: - pacKey = "iCurrency"; - break; - case LOCALE_SGROUPING : - pacKey = "sGrouping"; - break; - case LOCALE_IDIGITS: - pacKey = "iDigits"; - break; - case LOCALE_SLIST : - pacKey = "sList"; - break; - /* case LOCALE_ICALENDARTYPE: */ - /* case LOCALE_IFIRSTDAYOFWEEK: */ - /* case LOCALE_IFIRSTWEEKOFYEAR: */ - /* case LOCALE_SYEARMONTH : */ - /* case LOCALE_SPOSITIVESIGN : */ - /* case LOCALE_IPAPERSIZE: */ - /* break; */ - case LOCALE_SLONGDATE : - pacKey = "sLongDate"; - break; - case LOCALE_SMONDECIMALSEP : - pacKey = "sMonDecimalSep"; - break; - case LOCALE_SMONGROUPING: - pacKey = "sMonGrouping"; - break; - case LOCALE_IMEASURE: - pacKey = "iMeasure"; - break; - case LOCALE_SMONTHOUSANDSEP : - pacKey = "sMonThousandSep"; - break; - case LOCALE_INEGCURR: - pacKey = "iNegCurr"; - break; - case LOCALE_SNEGATIVESIGN : - pacKey = "sNegativeSign"; - break; - case LOCALE_INEGNUMBER: - pacKey = "iNegNumber"; - break; - case LOCALE_SSHORTDATE : - pacKey = "sShortDate"; - break; - case LOCALE_ILDATE: /* Long Date format ordering specifier. */ - pacKey = "iLDate"; - break; - case LOCALE_ILZERO: - pacKey = "iLZero"; - break; - case LOCALE_ITLZERO: - pacKey = "iTLZero"; - break; - case LOCALE_ITIME: /* Time format specifier. */ - pacKey = "iTime"; - break; - case LOCALE_STHOUSAND : - pacKey = "sThousand"; - break; - case LOCALE_S1159: /* AM */ - pacKey = "s1159"; - break; - case LOCALE_STIME: - pacKey = "sTime"; - break; - case LOCALE_S2359: /* PM */ - pacKey = "s2359"; - break; - case LOCALE_STIMEFORMAT : - pacKey = "sTimeFormat"; - break; - case LOCALE_SCURRENCY: - pacKey = "sCurrency"; - break; - - /* The following are not listed under MSDN as supported, - * but seem to be used and also stored in the registry. - */ - - case LOCALE_IDATE: - pacKey = "iDate"; - break; - case LOCALE_SCOUNTRY: - pacKey = "sCountry"; - break; - case LOCALE_ICOUNTRY: - pacKey = "iCountry"; - break; - case LOCALE_SLANGUAGE: - pacKey = "sLanguage"; - break; - - default: - break; - } - - return( pacKey ); -} - -/****************************************************************************** - * SetLocaleInfoA [KERNEL32.@] - */ -BOOL WINAPI SetLocaleInfoA(LCID lcid, LCTYPE lctype, LPCSTR data) -{ - HKEY hKey; - char *pacKey; - char acRealKey[128]; - - if ( (pacKey = GetLocaleSubkeyName(lctype)) ) - { - sprintf( acRealKey, "Control Panel\\International\\%s", pacKey ); - if ( RegCreateKeyA( HKEY_CURRENT_USER, acRealKey, - &hKey ) == ERROR_SUCCESS ) - { - if ( RegSetValueExA( hKey, NULL, 0, REG_SZ, - data, strlen(data)+1 ) != ERROR_SUCCESS ) - { - ERR("SetLocaleInfoA: %s did not work\n", pacKey ); - } - RegCloseKey( hKey ); - } - } - else - { - FIXME("(%ld,%ld,%s): stub\n",lcid,lctype,data); - } - return TRUE; -} /****************************************************************************** * IsValidLocale [KERNEL32.@] @@ -785,7 +78,7 @@ static BOOL CALLBACK EnumResourceLanguagesProcW(HMODULE hModule, LPCWSTR type, CHAR bufA[20]; WCHAR bufW[20]; LOCALE_ENUMPROCW lpfnLocaleEnum = (LOCALE_ENUMPROCW)lParam; - sprintf(bufA, "%08X", (UINT)LangID); + sprintf(bufA, "%08x", (UINT)LangID); MultiByteToWideChar(CP_ACP, 0, bufA, -1, bufW, sizeof(bufW)/sizeof(bufW[0])); return lpfnLocaleEnum(bufW); } @@ -810,7 +103,7 @@ static BOOL CALLBACK EnumResourceLanguagesProcA(HMODULE hModule, LPCSTR type, { CHAR bufA[20]; LOCALE_ENUMPROCA lpfnLocaleEnum = (LOCALE_ENUMPROCA)lParam; - sprintf(bufA, "%08X", (UINT)LangID); + sprintf(bufA, "%08x", (UINT)LangID); return lpfnLocaleEnum(bufA); } @@ -1979,6 +1272,58 @@ int WINAPI CompareStringW(LCID lcid, DWORD fdwStyle, return (l1CurrentLocale; - if (!ret) NtCurrentTeb()->CurrentLocale = ret = GetUserDefaultLCID(); - return ret; -} - - -/********************************************************************** - * SetThreadLocale [KERNEL32.@] Sets the calling threads current locale. - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * FIXME - * check if lcid is a valid cp - */ -BOOL WINAPI SetThreadLocale( - LCID lcid) /* [in] Locale identifier */ -{ - switch (lcid) - { - case LOCALE_SYSTEM_DEFAULT: - lcid = GetSystemDefaultLCID(); - break; - case LOCALE_USER_DEFAULT: - case LOCALE_NEUTRAL: - lcid = GetUserDefaultLCID(); - break; - } - NtCurrentTeb()->CurrentLocale = lcid; - return TRUE; -} - - /*********************************************************************** * GetCurrentThread [KERNEL32.@] Gets pseudohandle for current thread *