[PATCH v3 3/3] kernel32: Implement SetUserGeoName().

João Diogo Ferreira devilj at outlook.pt
Sun Nov 24 10:16:15 CST 2019


Signed-off-by: João Diogo Craveiro Ferreira <devilj at outlook.pt>
---
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



More information about the wine-devel mailing list