[PATCH v2 1/3] kernel32: Properly handle GEO_NATION in GetGeoInfoW(), handle GEO_ID.

João Diogo Ferreira devilj at outlook.pt
Mon Dec 2 15:39:44 CST 2019


GEO_NATION only returns positive if the location itself is of type
GEOCLASS_NATION. This seems to be true for every Windows version.

GEO_ID, which was added in Windows 10, does return positive for all
location types.

Signed-off-by: João Diogo Craveiro Ferreira <devilj at outlook.pt>
---
Supersedes: 174379
(This one's not as thorough, but it's the minimum necessary for now.)

How complicated and nuanced can one make an API comprised entirely of
four functions and two variables?
---
 dlls/kernel32/locale.c       | 31 ++++++++++++++++++++++++++++
 dlls/kernel32/tests/locale.c | 40 ++++++++++++++++++++++++++++++++----
 2 files changed, 67 insertions(+), 4 deletions(-)

diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c
index b062d7ef73..7d79cee0c3 100644
--- a/dlls/kernel32/locale.c
+++ b/dlls/kernel32/locale.c
@@ -2910,6 +2910,34 @@ BOOL WINAPI SetUserGeoID(GEOID geoid)
 
 /******************************************************************************
  *           GetGeoInfoW (KERNEL32.@)
+ *
+ * Retrieves information about a geographic location by its GeoID.
+ *
+ * PARAMS
+ *   geoid    [I] The GeoID of the location of interest.
+ *   geotype  [I] The type of information to be retrieved (SYSGEOTYPE enum from "winnls.h").
+ *   data     [O] The output buffer to store the information.
+ *   data_len [I] The length of the buffer, measured in WCHARs and including the null terminator.
+ *   lang     [I] Language identifier. Must be 0 unless geotype is GEO_RFC1766 or GEO_LCID.
+ *
+ * RETURNS
+ *   Success: The number of WCHARs (including null) written to the buffer -or-
+ *            if no buffer was provided, the minimum length required to hold the full data.
+ *   Failure: Zero. Call GetLastError() to determine the cause.
+ *
+ * NOTES
+ *   On failure, GetLastError() will return one of the following values:
+ *     - ERROR_INVALID_PARAMETER: the GeoID provided was invalid.
+ *     - ERROR_INVALID_FLAGS: the specified geotype was invalid.
+ *     - ERROR_INSUFFICIENT_BUFFER: the provided buffer was too small to hold the full data.
+ *     - ERROR_CALL_NOT_IMPLEMENTED: (Wine implementation) we don't handle that geotype yet.
+ *
+ *   The list of available GeoIDs can be retrieved with EnumSystemGeoID(),
+ *   or call GetUserGeoID() to retrieve the user's current location.
+ *
+ * TODO
+ *   Currently, we only handle the following geotypes: GEO_ID, GEO_ISO2, GEO_ISO3,
+ *   GEO_ISO_UN_NUMBER, GEO_PARENT and GEO_NATION.
  */
 INT WINAPI GetGeoInfoW(GEOID geoid, GEOTYPE geotype, LPWSTR data, int data_len, LANGID lang)
 {
@@ -2928,6 +2956,9 @@ INT WINAPI GetGeoInfoW(GEOID geoid, GEOTYPE geotype, LPWSTR data, int data_len,
 
     switch (geotype) {
     case GEO_NATION:
+        if (ptr->kind != LOCATION_NATION) return 0;
+        /* fall through */
+    case GEO_ID:
         sprintfW(buffW, fmtW, ptr->id);
         break;
     case GEO_ISO_UN_NUMBER:
diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c
index ee38dc36ac..de1d4fca22 100644
--- a/dlls/kernel32/tests/locale.c
+++ b/dlls/kernel32/tests/locale.c
@@ -4984,11 +4984,43 @@ static void test_GetGeoInfo(void)
     ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError());
 
-    /* GEO_NATION returns GEOID in a string form */
+    /* GEO_NATION returns GEOID in a string form, but only for GEOCLASS_NATION-type IDs */
+    ret = pGetGeoInfoA(203, GEO_NATION, buffA, 20, 0); /* GEOCLASS_NATION */
+    ok(ret == 4, "GEO_NATION of nation: expected 4, got %d\n", ret);
+    ok(!strcmp(buffA, "203"), "GEO_NATION of nation: expected 203, got %s\n", buffA);
+
     buffA[0] = 0;
-    ret = pGetGeoInfoA(203, GEO_NATION, buffA, 20, 0);
-    ok(ret == 4, "got %d\n", ret);
-    ok(!strcmp(buffA, "203"), "got %s\n", buffA);
+    ret = pGetGeoInfoA(39070, GEO_NATION, buffA, 20, 0); /* GEOCLASS_REGION */
+    ok(ret == 0, "GEO_NATION of region: expected 0, got %d\n", ret);
+    ok(*buffA == 0, "GEO_NATION of region: expected empty string, got %s\n", buffA);
+
+    buffA[0] = 0;
+    ret = pGetGeoInfoA(333, GEO_NATION, buffA, 20, 0); /* LOCATION_BOTH internal Wine type */
+    ok(ret == 0 ||
+       broken(ret == 4) /* Win7 and older */,
+       "GEO_NATION of LOCATION_BOTH: expected 0, got %d\n", ret);
+    ok(*buffA == 0 ||
+       broken(!strcmp(buffA, "333")) /* Win7 and older */,
+       "GEO_NATION of LOCATION_BOTH: expected empty string, got %s\n", buffA);
+
+    /* GEO_ID is like GEO_NATION but works for any ID */
+    buffA[0] = 0;
+    ret = pGetGeoInfoA(203, GEO_ID, buffA, 20, 0); /* GEOCLASS_NATION */
+    if (ret == 0)
+        win_skip("GEO_ID not supported.\n");
+    else
+    {
+        ok(ret == 4, "GEO_ID: expected 4, got %d\n", ret);
+        ok(!strcmp(buffA, "203"), "GEO_ID: expected 203, got %s\n", buffA);
+
+        ret = pGetGeoInfoA(47610, GEO_ID, buffA, 20, 0); /* GEOCLASS_REGION */
+        ok(ret == 6, "got %d\n", ret);
+        ok(!strcmp(buffA, "47610"), "got %s\n", buffA);
+
+        ret = pGetGeoInfoA(333, GEO_ID, buffA, 20, 0); /* LOCATION_BOTH internal Wine type */
+        ok(ret == 4, "got %d\n", ret);
+        ok(!strcmp(buffA, "333"), "got %s\n", buffA);
+    }
 
     /* GEO_PARENT */
     buffA[0] = 0;
-- 
2.24.0



More information about the wine-devel mailing list