[PATCH] kernel32: Handle GEOCLASS_REGION in Get/SetUserGeoID.
João Diogo Ferreira
jd.ferreira at outlook.com
Thu Sep 26 22:40:29 CDT 2019
This patch lays the groundwork for autodetecting the user's GeoID
in the future, preventing many headaches with programs crashing.
See bug #46196: https://bugs.winehq.org/show_bug.cgi?id=46196
Also better error reporting brings these functions to
(almost) full conformity with Windows, which is also just nice :)
Signed-off-by: João Diogo Craveiro Ferreira <devilj at outlook.pt>
---
dlls/kernel32/locale.c | 191 +++++++++++++++++++++++++----------------
1 file changed, 116 insertions(+), 75 deletions(-)
diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c
index d44a2b0916..653cea000d 100644
--- a/dlls/kernel32/locale.c
+++ b/dlls/kernel32/locale.c
@@ -4347,81 +4347,6 @@ BOOL WINAPI InvalidateNLSCache(void)
return FALSE;
}
-/******************************************************************************
- * GetUserGeoID (KERNEL32.@)
- */
-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,
- 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;
- }
-
- NtClose(hkey);
- if (hSubkey) NtClose(hSubkey);
- return ret;
-}
-
-/******************************************************************************
- * SetUserGeoID (KERNEL32.@)
- */
-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;
- }
-
- sprintfW(bufferW, formatW, GeoID);
- NtSetValueKey(hkey, &keyW, 0, REG_SZ, bufferW, (strlenW(bufferW) + 1) * sizeof(WCHAR));
- NtClose(attr.RootDirectory);
- NtClose(hkey);
- return TRUE;
-}
-
typedef struct
{
union
@@ -4853,6 +4778,122 @@ static const struct geoinfo_t *get_geoinfo_dataptr(GEOID geoid)
return NULL;
}
+/******************************************************************************
+ * GetUserGeoID (KERNEL32.@)
+ * Fetches a user's geographic location ID.
+ *
+ * PARAMS
+ * GeoClass [I] One of GEOCLASS_NATION or GEOCLASS_REGION.
+ *
+ * RETURNS
+ * Success: The GeoID for the requested class.
+ * Failure: GEOID_NOT_AVAILABLE, likely because the GeoID for that class had not been set yet.
+ *
+ */
+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;
+ count = sizeof(bufferW);
+
+ if (GeoClass == GEOCLASS_NATION)
+ RtlInitUnicodeString( &keyW, nationW );
+ else if(GeoClass == GEOCLASS_REGION)
+ RtlInitUnicodeString( &keyW, regionW );
+ else
+ return ret;
+
+ 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);
+ if (hSubkey) NtClose(hSubkey);
+ return ret;
+}
+
+/******************************************************************************
+ * 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(!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;
+ attr.ObjectName = &nameW;
+ attr.Attributes = 0;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+ RtlInitUnicodeString( &nameW, geoW );
+
+ 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, geoinfo->id);
+ NtSetValueKey(hkey, &keyW, 0, REG_SZ, bufferW, (strlenW(bufferW) + 1) * sizeof(WCHAR));
+ NtClose(attr.RootDirectory);
+ NtClose(hkey);
+ return TRUE;
+}
+
/******************************************************************************
* GetGeoInfoW (KERNEL32.@)
*/
--
2.23.0
More information about the wine-devel
mailing list