[PATCH v3 06/12] kernel32: Implement GetUserDefaultGeoName, make GetUserGeoID default to 39070.

João Diogo Ferreira devilj at outlook.pt
Tue Oct 22 21:32:37 CDT 2019


V3: Don't allocate more memory than necessary.
V2: Oops, previous version was in-dev. Changed order of operations
and removed one stray trace I forgot was there.

ORIGINAL PATCH NOTES:
I also changed the default return value of GetUserGeoID()
to make it more compliant with the new APIs.

Signed-off-by: João Diogo Craveiro Ferreira <devilj at outlook.pt>
---
 dlls/kernel32/kernel32.spec |   1 +
 dlls/kernel32/locale.c      | 138 +++++++++++++++++++++++++++++++++---
 include/winnls.h            |   1 +
 3 files changed, 131 insertions(+), 9 deletions(-)

diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index beebea9c1c..9a8e33eb9a 100644
--- a/dlls/kernel32/kernel32.spec
+++ b/dlls/kernel32/kernel32.spec
@@ -869,6 +869,7 @@
 # @ stub GetUILanguageInfo
 @ stdcall -arch=x86_64 GetUmsCompletionListEvent(ptr ptr)
 # @ stub -arch=x86_64 GetUmsSystemThreadInformation
+@ stdcall GetUserDefaultGeoName(ptr long)
 @ stdcall -import GetUserDefaultLCID()
 @ stdcall -import GetUserDefaultLangID()
 @ stdcall -import GetUserDefaultLocaleName(ptr long)
diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c
index 4957e8df5e..87b4cf16bd 100644
--- a/dlls/kernel32/locale.c
+++ b/dlls/kernel32/locale.c
@@ -4090,25 +4090,46 @@ static inline const struct geoinfo_t *get_geoinfoptr_by_name(const WCHAR *name)
 
 /******************************************************************************
  *           GetUserGeoID (KERNEL32.@)
+ *
+ * Retrieves the ID of the user's geographic nation or region.
+ *
+ * PARAMS
+ *   GeoClass [I] One of GEOCLASS_NATION or GEOCLASS_REGION (SYSGEOCLASS enum from "winnls.h").
+ *
+ * RETURNS
+ *   SUCCESS: The ID of the specified geographic class.
+ *   FAILURE: GEOID_NOT_AVAILABLE.
+ *
+ * NOTES
+ *   This function only fails if the geoclass specified is invalid;
+ *   otherwise, a valid GeoID is always returned.
  */
-GEOID WINAPI GetUserGeoID( GEOCLASS GeoClass )
+GEOID WINAPI GetUserGeoID(GEOCLASS GeoClass)
 {
-    GEOID ret = GEOID_NOT_AVAILABLE;
+    GEOID ret = 39070; /* World */
     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;
+    DWORD count = sizeof(bufferW);
     HANDLE hkey;
     UNICODE_STRING keyW;
     const KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)bufferW;
-    count = sizeof(bufferW);
 
     if (GeoClass == GEOCLASS_NATION)
+    {
+        TRACE("(GEOCLASS_NATION)\n");
         RtlInitUnicodeString( &keyW, nationW );
+    }
     else if (GeoClass == GEOCLASS_REGION)
+    {
+        TRACE("(GEOCLASS_REGION)\n");
         RtlInitUnicodeString( &keyW, regionW );
+    }
     else
-        return ret;
+    {
+        WARN("Unknown geoclass %d\n", GeoClass);
+        return GEOID_NOT_AVAILABLE;
+    }
 
     if (!(hkey = create_geo_regkey())) return ret;
 
@@ -4121,13 +4142,112 @@ GEOID WINAPI GetUserGeoID( GEOCLASS GeoClass )
 }
 
 /******************************************************************************
- *           set_geo_reg
+ *           GetUserDefaultGeoName (KERNEL32.@)
+ *
+ * Retrieves the name of the user's geographic location.
  *
- * Does the heavy lifting for SetUserGeoName() and SetUserGeoID().
+ * This name is a two-letter ISO 3166 country code
+ * or a three-digit UN M.49 code for anything other than countries (e.g. continents).
+ *
+ * If geoNameCount is 0, this function will return the minimum length
+ * required for a buffer to hold the name.
+ *
+ * PARAMS
+ *   geoName      [O] Pointer to a buffer to hold the name.
+ *   geoNameCount [I] Length of the buffer, including null, measured in WCHARs.
  *
- * The return value and last error set here can (and probably should)
- * be returned to the callers of those two functions.
+ * RETURNS
+ *   SUCCESS: Number of WCHARs written to the buffer -OR-
+ *            minimum length for the buffer, if geoNameCount was 0.
+ *   FAILURE: Zero. Call GetLastError() to determine the cause.
+ *
+ * NOTES:
+ *   On failure, GetLastError() will return one of the following values:
+ *     - ERROR_INVALID_PARAMETER: one of the parameters was invalid.
+ *     - ERROR_INSUFFICIENT_BUFFER: the specified buffer was too small to hold the name.
+ *     - ERROR_BADDB: an internal error occured and the name could not be read.
+ *     - ERROR_NOT_ENOUGH_MEMORY: (Wine implementation) not enough memory to execute successfuly.
  */
+int WINAPI GetUserDefaultGeoName(LPWSTR geoName, int geoNameCount)
+{
+    int ret = 0, size = 0;
+    DWORD count;
+    static const WCHAR nameW[] = {'N','a','m','e',0};
+    KEY_VALUE_PARTIAL_INFORMATION kvi;
+    UNICODE_STRING keyname;
+    HANDLE hkey;
+
+    TRACE("(%p, %d)\n", geoName, geoNameCount);
+
+    if (geoNameCount < 0 || (!geoName && geoNameCount))
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+
+    if (!(hkey = create_geo_regkey()))
+    {
+        SetLastError(ERROR_BADDB);
+        return 0;
+    }
+
+    RtlInitUnicodeString(&keyname, nameW);
+
+    if (NtQueryValueKey(hkey, &keyname, KeyValuePartialInformation, &kvi, sizeof(kvi), &count)
+        == STATUS_BUFFER_OVERFLOW && kvi.DataLength)
+        size = kvi.DataLength / sizeof(WCHAR);
+    else
+        SetLastError(ERROR_BADDB);
+
+    if (size)
+    {
+        if (!geoNameCount)
+            ret = size;
+        else if (geoNameCount < size)
+            SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        else if (geoNameCount >= size)
+        {
+            size_t kvi_size = 0;
+            KEY_VALUE_PARTIAL_INFORMATION *kvi = NULL;
+
+            kvi_size = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + (size * sizeof(WCHAR));
+            if (!(kvi = HeapAlloc(GetProcessHeap(), 0, kvi_size)))
+            {
+                ERR("Couldn't allocate memory for KeyValuePartialInformation. Bailing.\n");
+                SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            }
+            else
+            {
+                NTSTATUS status = NtQueryValueKey(hkey, &keyname, KeyValuePartialInformation,
+                                                kvi, kvi_size, &count);
+                if (status == STATUS_SUCCESS)
+                {
+                    ret = size;
+                    memcpy(geoName, kvi->Data, kvi->DataLength);
+                }
+                else
+                {
+                    ERR("Unexpected error retrieving geoname: status=0x%x, kvi->DataLength=%u, kvi->Data=%s\n",
+                        status, kvi->DataLength, wine_dbgstr_w((WCHAR*)kvi->Data));
+                    SetLastError(ERROR_BADDB);
+                }
+                HeapFree(GetProcessHeap(), 0, kvi);
+            }
+        }
+    }
+
+    NtClose(hkey);
+    return ret;
+}
+
+/******************************************************************************
+*           set_geo_reg
+*
+* Does the heavy lifting for SetUserGeoName() and SetUserGeoID().
+*
+* The return value and last error set here can (and probably should)
+* be returned to the callers of those two functions.
+*/
 static int set_geo_reg(const struct geoinfo_t *geoinfo)
 {
     static const WCHAR nationW[] = {'N','a','t','i','o','n',0};
diff --git a/include/winnls.h b/include/winnls.h
index 3aeb47c9e4..059a459153 100644
--- a/include/winnls.h
+++ b/include/winnls.h
@@ -935,6 +935,7 @@ WINBASEAPI INT         WINAPI GetTimeFormatA(LCID,DWORD,const SYSTEMTIME*,LPCSTR
 WINBASEAPI INT         WINAPI GetTimeFormatEx(LPCWSTR,DWORD,const SYSTEMTIME*,LPCWSTR,LPWSTR,INT);
 WINBASEAPI INT         WINAPI GetTimeFormatW(LCID,DWORD,const SYSTEMTIME*,LPCWSTR,LPWSTR,INT);
 #define                       GetTimeFormat WINELIB_NAME_AW(GetTimeFormat)
+WINBASEAPI int         WINAPI GetUserDefaultGeoName(LPWSTR,int);
 WINBASEAPI LANGID      WINAPI GetUserDefaultLangID(void);
 WINBASEAPI LCID        WINAPI GetUserDefaultLCID(void);
 WINBASEAPI INT         WINAPI GetUserDefaultLocaleName(LPWSTR,int);
-- 
2.23.0



More information about the wine-devel mailing list