From: "João Diogo Ferreira" Subject: [PATCH 2/2] kernel32: Handle GEOCLASS_REGION in Get/SetUserGeoID. Message-Id: Date: Thu, 3 Oct 2019 05:45:19 +0000 In-Reply-To: <20191003054403.48309-1-devilj@outlook.pt> References: <20191003054403.48309-1-devilj@outlook.pt> This is laying the groundwork for implementing GeoID autodetection on behalf of the user. These functions should now be 100% compliant with Windows 7 behaviour. Only a few more ways to make it behave like Windows 10! Signed-off-by: João Diogo Craveiro Ferreira --- dlls/kernel32/locale.c | 77 ++++++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 18 deletions(-) diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c index d11d17eaa0..e017bb5472 100644 --- a/dlls/kernel32/locale.c +++ b/dlls/kernel32/locale.c @@ -4778,34 +4778,43 @@ static const struct geoinfo_t *get_geoinfo_dataptr(GEOID geoid) /****************************************************************************** * GetUserGeoID (KERNEL32.@) + * Fetches the user's geographic location ID for nation or region. + * + * PARAMS + * GeoClass [I] One of GEOCLASS_NATION or GEOCLASS_REGION. + * + * RETURNS + * Success: The GeoID for the requested class. + * Failure: GEOID_NOT_AVAILABLE, if the specified GeoClass is invalid or its GeoID had not yet been set. + * */ 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}; + static const WCHAR regionW[] = {'R','e','g','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; + if (GeoClass == GEOCLASS_NATION) + RtlInitUnicodeString( &keyW, nationW ); + else if (GeoClass == GEOCLASS_REGION) + RtlInitUnicodeString( &keyW, regionW ); + else + return ret; - switch( GeoClass ){ - case GEOCLASS_NATION: - if ((hSubkey = NLS_RegOpenKey(hkey, geoW))) - { - if((NtQueryValueKey(hSubkey, &keyW, KeyValuePartialInformation, - bufferW, count, &count) == STATUS_SUCCESS ) && info->DataLength) - ret = strtolW((LPCWSTR)info->Data, &end, 10); - } - break; - case GEOCLASS_REGION: - FIXME("GEOCLASS_REGION not handled yet\n"); - break; + if (!(hkey = create_registry_key())) return ret; + + if ((hSubkey = NLS_RegOpenKey(hkey, geoW))) + { + if((NtQueryValueKey(hSubkey, &keyW, KeyValuePartialInformation, + bufferW, count, &count) == STATUS_SUCCESS ) && info->DataLength) + ret = strtolW((LPCWSTR)info->Data, &end, 10); } NtClose(hkey); @@ -4815,18 +4824,46 @@ GEOID WINAPI GetUserGeoID( GEOCLASS GeoClass ) /****************************************************************************** * SetUserGeoID (KERNEL32.@) + * Sets the user's geographic location ID. + * + * PARAMS + * GeoID [I] The new GeoID. + * + * RETURNS + * Success: TRUE. + * Failure: FALSE, if the GeoID was invalid or an unexpected error occured. Call GetLastError() to learn the reason. + * + * NOTES + * GetLastError() will report the following possible error conditions: + * - ERROR_INVALID_PARAMETER: The GeoID was invalid. + * - ERROR_INTERNAL_ERROR: There was an unexpected error. + * + * GeoIDs may be internally classified as LOCATION_BOTH; these are functionally identical to GEOCLASS_REGION, + * and will be set as region ID only, not as a nation. + * */ BOOL WINAPI SetUserGeoID( GEOID GeoID ) { + const struct geoinfo_t *geoinfo = get_geoinfo_dataptr(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]; OBJECT_ATTRIBUTES attr; HANDLE hkey; - if(!(hkey = create_registry_key())) return FALSE; + if (!geoinfo) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if (!(hkey = create_registry_key())) + { + SetLastError(ERROR_INTERNAL_ERROR); + return FALSE; + } attr.Length = sizeof(attr); attr.RootDirectory = hkey; @@ -4835,16 +4872,20 @@ BOOL WINAPI SetUserGeoID( GEOID GeoID ) 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) + if (geoinfo->kind == LOCATION_NATION) + RtlInitUnicodeString( &keyW, nationW ); + else + RtlInitUnicodeString( &keyW, regionW ); + if (NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS) { NtClose(attr.RootDirectory); + SetLastError(ERROR_INTERNAL_ERROR); return FALSE; } - sprintfW(bufferW, formatW, GeoID); + sprintfW(bufferW, formatW, geoinfo->id); NtSetValueKey(hkey, &keyW, 0, REG_SZ, bufferW, (strlenW(bufferW) + 1) * sizeof(WCHAR)); NtClose(attr.RootDirectory); NtClose(hkey); -- 2.23.0