From: "João Diogo Ferreira" Subject: [PATCH v3 1/3] kernel32: Handle GEO_ID and GEO_NAME in GetGeoInfoW(), fix UN format. Message-Id: Date: Sun, 24 Nov 2019 16:16:14 +0000 UN codes are always formatted in groups of three digits in Windows. Also added more geotypes to the list of known unhandled cases. Signed-off-by: João Diogo Craveiro Ferreira --- V3: Fix test failure on older Windows versions. V2: Don't use compound arguments in function call, and PROPERLY handle GEO_NATION. Supersedes: 174374 V3: Fix test failure on older Windows versions. Signed-off-by: João Diogo Craveiro Ferreira --- dlls/kernel32/locale.c | 48 ++++++++++++++++++++++++--- dlls/kernel32/tests/locale.c | 63 ++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 4 deletions(-) diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c index a5ec6593b0..4a2795cd1c 100644 --- a/dlls/kernel32/locale.c +++ b/dlls/kernel32/locale.c @@ -3130,6 +3130,33 @@ 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(). + * + * TODO + * Currently, we only handle the following geotypes: GEO_ID, GEO_NATION, GEO_ISO_UN_NUMBER, + * GEO_ISO2, GEO_ISO3, GEO_PARENT and GEO_NAME. */ INT WINAPI GetGeoInfoW(GEOID geoid, GEOTYPE geotype, LPWSTR data, int data_len, LANGID lang) { @@ -3137,7 +3164,9 @@ INT WINAPI GetGeoInfoW(GEOID geoid, GEOTYPE geotype, LPWSTR data, int data_len, WCHAR buffW[12]; const WCHAR *str = buffW; int len; - static const WCHAR fmtW[] = {'%','d',0}; + static const WCHAR xx[] = {'X','X',0}; + static const WCHAR id_fmtW[] = {'%','d',0}; + static const WCHAR un_fmtW[] = {'%','0','3','d',0}; TRACE("%d %d %p %d %d\n", geoid, geotype, data, data_len, lang); @@ -3148,13 +3177,15 @@ INT WINAPI GetGeoInfoW(GEOID geoid, GEOTYPE geotype, LPWSTR data, int data_len, switch (geotype) { case GEO_NATION: - sprintfW(buffW, fmtW, ptr->id); + if (ptr->kind != LOCATION_NATION) return 0; + case GEO_ID: + sprintfW(buffW, id_fmtW, ptr->id); break; case GEO_ISO_UN_NUMBER: - sprintfW(buffW, fmtW, ptr->uncode); + sprintfW(buffW, un_fmtW, ptr->uncode); break; case GEO_PARENT: - sprintfW(buffW, fmtW, ptr->parent); + sprintfW(buffW, id_fmtW, ptr->parent); break; case GEO_ISO2: str = ptr->iso2W; @@ -3162,6 +3193,12 @@ INT WINAPI GetGeoInfoW(GEOID geoid, GEOTYPE geotype, LPWSTR data, int data_len, case GEO_ISO3: str = ptr->iso3W; break; + case GEO_NAME: + if (ptr->uncode && !strcmpW(xx, ptr->iso2W)) + sprintfW(buffW, un_fmtW, ptr->uncode); + else + str = ptr->iso2W; + break; case GEO_RFC1766: case GEO_LCID: case GEO_FRIENDLYNAME: @@ -3170,6 +3207,9 @@ INT WINAPI GetGeoInfoW(GEOID geoid, GEOTYPE geotype, LPWSTR data, int data_len, case GEO_OFFICIALLANGUAGES: case GEO_LATITUDE: case GEO_LONGITUDE: + case GEO_DIALINGCODE: + case GEO_CURRENCYCODE: + case GEO_CURRENCYSYMBOL: FIXME("type %d is not supported\n", geotype); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c index 0e2c3496a9..b501976228 100644 --- a/dlls/kernel32/tests/locale.c +++ b/dlls/kernel32/tests/locale.c @@ -4892,6 +4892,31 @@ static void test_GetGeoInfo(void) ok(ret == 4, "got %d\n", ret); ok(!strcmp(buffA, "203"), "got %s\n", buffA); + /* GEO_NATION should fail when the location is of type LOCATION_REGION */ + buffA[0] = 0; + ret = pGetGeoInfoA(39070, GEO_NATION, buffA, 20, 0); + ok(ret == 0, "expected 0, got %d\n", ret); + ok(*buffA == 0, "expected empty string, got %s\n", buffA); + + /* GEO_ID should return an ID for all location types */ + buffA[0] = 0; + ret = pGetGeoInfoA(203, GEO_ID, buffA, 20, 0); + if (!ret) + win_skip("GEO_ID not supported.\n"); + else + { + ok(ret == 4, "got %d\n", ret); + ok(!strcmp(buffA, "203"), "got %s\n", buffA); /* LOCATION_NATION */ + + ret = pGetGeoInfoA(47610, GEO_ID, buffA, 20, 0); /* LOCATION_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 */ + ok(ret == 4, "got %d\n", ret); + ok(!strcmp(buffA, "333"), "got %s\n", buffA); + } + /* GEO_PARENT */ buffA[0] = 0; ret = pGetGeoInfoA(203, GEO_PARENT, buffA, 20, 0); @@ -4911,6 +4936,44 @@ static void test_GetGeoInfo(void) { ok(ret == 4, "got %d\n", ret); ok(!strcmp(buffA, "643"), "got %s\n", buffA); + + /* GEO_ISO_UN_NUMBER should always be zero-padded */ + buffA[0] = 0; + ret = pGetGeoInfoA(27114, GEO_ISO_UN_NUMBER, buffA, 20, 0); + ok(ret == 4, "got %d\n", ret); + ok(!strcmp(buffA, "009"), "got %s\n", buffA); + + /* We're on Windows 8 or newer. GEO_NATION should fail with LOCATION_BOTH IDs. */ + buffA[0] = 0; + ret = pGetGeoInfoA(333, GEO_NATION, buffA, 20, 0); + ok(ret == 0, "got %d\n", ret); + ok(*buffA == 0, "got %s\n", buffA); + } + + buffA[0] = 0; + ret = pGetGeoInfoA(193, GEO_NAME, buffA, 20, 0); /* LOCATION_NATION */ + if (ret == 0) + win_skip("GEO_NAME not supported.\n"); + else + { + ok(ret == 3, "expected ret == 3, got %d\n", ret); + ok(!strcmp(buffA, "PT"), "expected PT, got %s\n", buffA); + + buffA[0] = 0; + ret = pGetGeoInfoA(39070, GEO_NAME, buffA, 20, 0); /* LOCATION_REGION */ + ok(ret == 4, "expected ret == 4, got %d\n", ret); + ok(!strcmp(buffA, "001"), "expected 001, got %s\n", buffA); + + buffA[0] = 0; + ret = pGetGeoInfoA(333, GEO_NAME, buffA, 20, 0); /* LOCATION_BOTH */ + ok(ret == 3, "expected ret == 3, got %d\n", ret); + ok(!strcmp(buffA, "AN"), "expected AN, got %s\n", buffA); + + /* Special areas like Johnston Atoll should have geo name "XX" */ + buffA[0] = 0; + ret = pGetGeoInfoA(127, GEO_NAME, buffA, 20, 0); + ok(ret == 3, "expected ret == 3, got %d\n", ret); + ok(!strcmp(buffA, "XX"), "expected XX, got %s\n", buffA); } /* try invalid type value */ -- 2.24.0