From: "João Diogo Ferreira" Subject: [PATCH v3 3/3] kernel32: Implement SetUserGeoName(). Message-Id: Date: Sun, 24 Nov 2019 16:16:15 +0000 In-Reply-To: <20191124161458.158835-1-devilj@outlook.pt> References: <20191124161458.158835-1-devilj@outlook.pt> Signed-off-by: João Diogo Craveiro Ferreira --- Treat with low priority. This actually useful and urgent, rather I mistakingly wrote it for something else and now I might as well make it useful. --- dlls/kernel32/kernel32.spec | 1 + dlls/kernel32/locale.c | 124 +++++++++++++++++++++++++++++------- include/winnls.h | 1 + 3 files changed, 102 insertions(+), 24 deletions(-) diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 30b0b1de67..67fdcd0c3b 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -1471,6 +1471,7 @@ @ stdcall -arch=x86_64 SetUmsThreadInformation(ptr long ptr long) @ stdcall -import SetUnhandledExceptionFilter(ptr) @ stdcall SetUserGeoID(long) +@ stdcall SetUserGeoName(wstr) @ stub SetVDMCurrentDirectories @ stdcall SetVolumeLabelA(str str) @ stdcall SetVolumeLabelW(wstr wstr) diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c index 6031ddfd64..1f7c9a0eda 100644 --- a/dlls/kernel32/locale.c +++ b/dlls/kernel32/locale.c @@ -3109,7 +3109,6 @@ GEOID WINAPI GetUserGeoID(GEOCLASS geoclass) UNICODE_STRING keyW; const KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)bufferW; DWORD count = sizeof(bufferW); - RtlInitUnicodeString(&keyW, nationW); switch (geoclass) { @@ -3139,30 +3138,28 @@ GEOID WINAPI GetUserGeoID(GEOCLASS geoclass) } /****************************************************************************** - * SetUserGeoID (KERNEL32.@) - * - * Sets the ID of the user's geographic location. + * set_geo_reg * - * PARAMS - * geoid [I] The geographic ID to be set. + * Does the heavy lifting for SetUserGeoName() and SetUserGeoID(). * - * RETURNS - * SUCCESS: TRUE. - * FAILURE: FALSE. GetLastError() will return ERROR_INVALID_PARAMETER if the ID was invalid. + * The return value and last error set here can and should be + * returned to the callers of those two functions. */ -BOOL WINAPI SetUserGeoID(GEOID geoid) +static int WINAPI set_geo_reg(const struct geoinfo_t *geoptr) { - const struct geoinfo_t *geoinfo = get_geoinfoptr_by_id(geoid); static const WCHAR geoW[] = {'G','e','o',0}; static const WCHAR nationW[] = {'N','a','t','i','o','n',0}; static const WCHAR regionW[] = {'R','e','g','i','o','n',0}; - static const WCHAR formatW[] = {'%','i',0}; - UNICODE_STRING nameW, keyW; - WCHAR bufferW[10]; + static const WCHAR nameW[] = {'N','a','m','e',0}; + static const WCHAR id_fmtW[] = {'%','i',0}; + static const WCHAR un_fmtW[] = {'%','0','3','i',0}; + static const WCHAR xx[] = {'X','X',0}; + UNICODE_STRING keyname, id_valuename, name_valuename; + WCHAR id_buffer[10], name_buffer[4]; OBJECT_ATTRIBUTES attr; HANDLE hkey; - if (!geoinfo) + if (!geoptr) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; @@ -3172,16 +3169,11 @@ BOOL WINAPI SetUserGeoID(GEOID geoid) attr.Length = sizeof(attr); attr.RootDirectory = hkey; - attr.ObjectName = &nameW; + attr.ObjectName = &keyname; attr.Attributes = 0; attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; - RtlInitUnicodeString(&nameW, geoW); - - if (geoinfo->kind == LOCATION_NATION) - RtlInitUnicodeString(&keyW, nationW); - else - RtlInitUnicodeString(&keyW, regionW); + RtlInitUnicodeString(&keyname, geoW); if (NtCreateKey(&hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL) != STATUS_SUCCESS) { @@ -3189,13 +3181,97 @@ BOOL WINAPI SetUserGeoID(GEOID geoid) return FALSE; } - sprintfW(bufferW, formatW, geoinfo->id); - NtSetValueKey(hkey, &keyW, 0, REG_SZ, bufferW, (strlenW(bufferW) + 1) * sizeof(WCHAR)); + /* Prepare the GeoID */ + sprintfW(id_buffer, id_fmtW, geoptr->id); + + if (geoptr->kind == LOCATION_NATION) + RtlInitUnicodeString(&id_valuename, nationW); + else + RtlInitUnicodeString(&id_valuename, regionW); + + /* Now prepare geoname */ + RtlInitUnicodeString(&name_valuename, nameW); + + if (geoptr->uncode && !strcmpW(xx, geoptr->iso2W)) + sprintfW(name_buffer, un_fmtW, geoptr->uncode); + else + strcpyW(name_buffer, geoptr->iso2W); + + NtSetValueKey(hkey, &id_valuename, 0, REG_SZ, + id_buffer, (strlenW(id_buffer) + 1) * sizeof(WCHAR)); + NtSetValueKey(hkey, &name_valuename, 0, REG_SZ, + name_buffer, (strlenW(name_buffer) + 1) * sizeof(WCHAR)); + + TRACE("Set %s to ID %d; set Name to %s.\n", + wine_dbgstr_w(id_valuename.Buffer), geoptr->id, wine_dbgstr_w(name_buffer)); + NtClose(attr.RootDirectory); NtClose(hkey); return TRUE; } +/****************************************************************************** + * SetUserGeoID (KERNEL32.@) + * + * Sets the user's geographic location via a GeoID. + * + * PARAMS + * geoid [I] The GeoID of the location to be set. + * + * RETURNS + * SUCCESS: TRUE. + * FAILURE: FALSE. GetLastError() will return ERROR_INVALID_PARAMETER if the GeoID was invalid. + * + * NOTES + * On success, the geographic name be set to the location of the specified GeoID. + * + * SEE ALSO + * GetUserGeoID(), EnumSystemGeoID(), GetGeoInfoW(). + */ +BOOL WINAPI SetUserGeoID(GEOID geoid) +{ + TRACE("(%d)\n", geoid); + return set_geo_reg(get_geoinfoptr_by_id(geoid)); +} + +/****************************************************************************** + * SetUserGeoName (KERNEL32.@) + * + * Sets the user's geographic location via a GeoName. + * + * PARAMS + * geoname [I] The name of the location to be set. + * + * RETURNS + * SUCCESS: TRUE. + * FAILURE: GetLastError() will return ERROR_INVALID_PARAMETER if the name was invalid. + * + * NOTES + * On success, the geographic ID for the relevant class will be set to + * the location of the specified name. + * + * A GeoName is a two-letter ISO 3166 country code + * or a three-digit UN M.49 code for anything other than countries (e.g. continents). + * + * The name must be known to Wine, or this function will fail. + * Call EnumSystemGeoNames() to retrieve a list of valid names. + * + * SEE ALSO + * GetUserDefaultGeoName(), EnumSystemGeoNames(), GetGeoInfoEx(). + */ +BOOL WINAPI SetUserGeoName(WCHAR *geoname) +{ + TRACE("(%p = %s)\n", geoname, geoname ? wine_dbgstr_w(geoname) : "(nil)"); + + if (!geoname || !*geoname) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return set_geo_reg(get_geoinfoptr_by_name(geoname)); +} + /****************************************************************************** * get_geo_info * diff --git a/include/winnls.h b/include/winnls.h index 7f5a782815..11ec2f6236 100644 --- a/include/winnls.h +++ b/include/winnls.h @@ -966,6 +966,7 @@ WINBASEAPI BOOL WINAPI SetLocaleInfoW(LCID,LCTYPE,LPCWSTR); WINBASEAPI BOOL WINAPI SetThreadLocale(LCID); WINBASEAPI LANGID WINAPI SetThreadUILanguage(LANGID); WINBASEAPI BOOL WINAPI SetUserGeoID(GEOID); +WINBASEAPI BOOL WINAPI SetUserGeoName(WCHAR *); WINBASEAPI INT WINAPI WideCharToMultiByte(UINT,DWORD,LPCWSTR,INT,LPSTR,INT,LPCSTR,LPBOOL); WINBASEAPI INT WINAPI FindNLSStringEx(const WCHAR *,DWORD,const WCHAR *,INT,const WCHAR *,INT,INT *,NLSVERSIONINFO *,void *,LPARAM); -- 2.24.0