[PATCH] kernel32: Handle GEOCLASS_REGION in Get/SetUserGeoID.

João Diogo Ferreira jd.ferreira at outlook.com
Thu Sep 26 22:19:23 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