[PATCH v2 4/7] kernel32: Implement GetUserDefaultGeoName().

João Diogo Ferreira devilj at outlook.pt
Tue Oct 29 23:30:56 CDT 2019


I wrote some documentation. This is my original work
and/or work copied from the Wine source itself
and does not include any other copyrighted material,
nor does it copy any content owned or written by Microsoft.

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

diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index 9898bdec6e..c2dd727135 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 5bb314b595..abb3ecd773 100644
--- a/dlls/kernel32/locale.c
+++ b/dlls/kernel32/locale.c
@@ -4130,13 +4130,134 @@ GEOID WINAPI GetUserGeoID(GEOCLASS geoclass)
 }
 
 /******************************************************************************
- *           set_geo_reg
+ *           GetUserDefaultGeoName (KERNEL32.@)
  *
- * Does the heavy lifting for SetUserGeoName() and SetUserGeoID().
+ * Retrieves the name of the user's geographic location.
  *
- * The return value and last error set here can (and probably should)
- * be returned to the callers of those two functions.
+ * 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 geoname_len is 0, this function will return the minimum length
+ * required for a buffer to hold the name.
+ *
+ * PARAMS
+ *   buffer     [O] Pointer to a buffer to hold the name.
+ *   buffer_len [I] Length of the buffer, including null terminator, measured in WCHARs.
+ *
+ * RETURNS
+ *   SUCCESS: Number of WCHARs written to the buffer -OR-
+ *            minimum length for the buffer, if buffer_len 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 Wine couldn't retrieve the name.
+ *     - ERROR_NOT_ENOUGH_MEMORY: (Wine implementation) could not allocate more memory.
  */
+int WINAPI GetUserDefaultGeoName(WCHAR *buffer, int buffer_len)
+{
+    int ret = 0, name_len;
+    WCHAR fallback[] = {'0','0','1',0}; /* World */
+    int fallback_len = ARRAY_SIZE(fallback);
+    int use_fallback = 0;
+    HANDLE hkey = create_geo_regkey();
+    KEY_VALUE_PARTIAL_INFORMATION kvi = {0};
+    WCHAR valuename[] = {'N','a','m','e',0};
+    UNICODE_STRING uvaluename;
+    DWORD reg_written_bytes;
+
+    TRACE("(%p, %d)\n", buffer, buffer_len);
+
+    if (buffer_len < 0 || (buffer_len && !buffer))
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        if (hkey) NtClose(hkey);
+        return 0;
+    }
+
+    RtlInitUnicodeString(&uvaluename, valuename);
+
+    /* If we don't get an overflow, it's the wrong value. */
+    if (hkey && NtQueryValueKey(hkey, &uvaluename, KeyValuePartialInformation,
+                                &kvi, sizeof(kvi), &reg_written_bytes) == STATUS_BUFFER_OVERFLOW)
+            name_len = kvi.DataLength / sizeof(WCHAR);
+    else
+    {
+        if (!hkey) ERR("Couldn't create geo regkey; please report.\n");
+        TRACE("We've fallen back to our hardcoded value.\n");
+        use_fallback = 1;
+    }
+
+    if (!use_fallback)
+    {
+        if (!buffer_len)
+            ret = name_len;
+        else if (buffer_len < name_len)
+        {
+            SetLastError(ERROR_INSUFFICIENT_BUFFER);
+            ret = 0;
+        }
+        else if (buffer_len >= name_len)
+        {
+            KEY_VALUE_PARTIAL_INFORMATION *kvi;
+            DWORD kvi_size = sizeof(*kvi) + (name_len * sizeof(WCHAR));
+
+            if ((kvi = HeapAlloc(GetProcessHeap(), 0, kvi_size)))
+            {
+                NTSTATUS status = NtQueryValueKey(hkey, &uvaluename, KeyValuePartialInformation,
+                                                  kvi, kvi_size, &reg_written_bytes);
+                if (status == STATUS_SUCCESS)
+                {
+                    memcpy(buffer, kvi->Data, name_len);
+                    ret = name_len;
+                }
+                else
+                {
+                    ERR("Failure: status=0x%x, kvi_size=%d, reg_written_bytes=%d, DataLength=%u\n",
+                        status, kvi_size, reg_written_bytes, kvi->DataLength);
+                    SetLastError(ERROR_BADDB);
+                    ret = 0;
+                }
+                HeapFree(GetProcessHeap(), 0, kvi);
+            }
+            else
+            {
+                ERR("We couldn't allocate memory somehow.\n");
+                SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                ret = 0;
+            }
+        }
+    }
+    else
+    {
+        if (!buffer_len)
+            ret = fallback_len;
+        else if (buffer_len < fallback_len)
+        {
+            SetLastError(ERROR_INSUFFICIENT_BUFFER);
+            ret = 0;
+        }
+        else if (buffer_len >= fallback_len)
+        {
+            strcpyW(buffer, fallback);
+            ret = fallback_len;
+        }
+    }
+
+    if (hkey) 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 a60dd1f1b0..798db570c5 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(WCHAR*,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