[PATCH] kernel32: Implement EnumSystemGeoNames().
João Diogo Ferreira
devilj at outlook.pt
Sun Nov 24 08:09:39 CST 2019
Signed-off-by: João Diogo Craveiro Ferreira <devilj at outlook.pt>
---
Treat with low priority. This patch doesn't fix anything anymore,
and I'm only posting because I already spent time writing it.
---
dlls/kernel32/kernel32.spec | 1 +
dlls/kernel32/locale.c | 78 ++++++++++++++++++++++-
dlls/kernel32/tests/locale.c | 119 +++++++++++++++++++++++++++++++++++
include/winnls.h | 2 +
4 files changed, 199 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index a26d65edf7..07f8c1a93e 100644
--- a/dlls/kernel32/kernel32.spec
+++ b/dlls/kernel32/kernel32.spec
@@ -420,6 +420,7 @@
@ stdcall -import EnumSystemCodePagesW(ptr long)
@ stdcall -import EnumSystemFirmwareTables(long ptr long)
@ stdcall EnumSystemGeoID(long long ptr)
+@ stdcall EnumSystemGeoNames(long ptr long)
@ stdcall EnumSystemLanguageGroupsA(ptr long ptr)
@ stdcall -import EnumSystemLanguageGroupsW(ptr long ptr)
@ stdcall -import EnumSystemLocalesA(ptr long)
diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c
index a5ec6593b0..3a8dea294a 100644
--- a/dlls/kernel32/locale.c
+++ b/dlls/kernel32/locale.c
@@ -3244,9 +3244,11 @@ INT WINAPI GetGeoInfoA(GEOID geoid, GEOTYPE geotype, LPSTR data, int data_len, L
* - ERROR_INVALID_PARAMETER: no callback function was provided.
* - ERROR_INVALID_FLAGS: the location type was invalid.
*
+ * You can retrieve information about each location with GetGeoInfoW().
+ *
* TODO
* On Windows 10, this function filters out those locations which
- * simultaneously lack ISO and UN codes (e.g. Johnson Atoll).
+ * simultaneously lack ISO and UN codes (e.g. Johnston Atoll).
*/
BOOL WINAPI EnumSystemGeoID(GEOCLASS geoclass, GEOID parent, GEO_ENUMPROC enumproc)
{
@@ -3284,6 +3286,80 @@ BOOL WINAPI EnumSystemGeoID(GEOCLASS geoclass, GEOID parent, GEO_ENUMPROC enumpr
return TRUE;
}
+/******************************************************************************
+ * EnumSystemGeoNames (KERNEL32.@)
+ *
+ * Calls a user's function for every location available on the system.
+ *
+ * PARAMS
+ * geoclass [I] Type of location desired (SYSGEOTYPE enum from "winnls.h").
+ * enumproc [I] Callback function to call for each location (prototype in "winnls.h").
+ * data [I] Any user-defined data to be passed to the enumproc callback function.
+ *
+ * RETURNS
+ * Success: TRUE.
+ * Failure: FALSE. Use GetLastError() to determine the cause.
+ *
+ * NOTES
+ * The enumproc function returns TRUE to continue enumerating
+ * or FALSE to interrupt the enumeration.
+ *
+ * On failure, GetLastError() will return one of the following values:
+ * - ERROR_INVALID_PARAMETER: no callback function was provided;
+ * - ERROR_INVALID_FLAGS: the location type was invalid.
+ *
+ * You can retrieve information about each location with GetGeoInfoEx().
+ */
+BOOL WINAPI EnumSystemGeoNames(GEOCLASS geoclass, GEO_ENUMNAMEPROC enumproc, LONG_PTR data)
+{
+ int i;
+ static WCHAR xx[] = {'X','X',0};
+
+ TRACE("(%d, %p, %ld)\n", geoclass, enumproc, data);
+
+ if (!enumproc)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ if (geoclass != GEOCLASS_NATION && geoclass != GEOCLASS_REGION && geoclass != GEOCLASS_ALL)
+ {
+ SetLastError(ERROR_INVALID_FLAGS);
+ return FALSE;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(geoinfodata); i++)
+ {
+ const struct geoinfo_t *ptr = &geoinfodata[i];
+ static const WCHAR un_fmt[] = {'%','0','3','i',0};
+ WCHAR name[4];
+
+ if (geoclass == GEOCLASS_NATION && (ptr->kind != LOCATION_NATION))
+ continue;
+
+ /* LOCATION_BOTH counts as region. */
+ if (geoclass == GEOCLASS_REGION && (ptr->kind == LOCATION_NATION))
+ continue;
+
+ if (ptr->uncode && !strcmpW(xx, ptr->iso2W))
+ sprintfW(name, un_fmt, ptr->uncode);
+ else
+ strcpyW(name, ptr->iso2W);
+
+ /* Filter out locations without a geo name */
+ if (!strcmpW(name, xx))
+ continue;
+
+ if (!enumproc(name, data))
+ return TRUE;
+ }
+
+ /* Windows also enumerates a single XX, which maps to 001 (ID: 39070, World) */
+ if (geoclass != GEOCLASS_NATION)
+ enumproc(xx, data);
+ return TRUE;
+}
enum {
BASE = 36,
diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c
index 0e2c3496a9..48f20db981 100644
--- a/dlls/kernel32/tests/locale.c
+++ b/dlls/kernel32/tests/locale.c
@@ -75,6 +75,7 @@ static INT (WINAPI *pCompareStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPCWSTR, INT
static INT (WINAPI *pGetGeoInfoA)(GEOID, GEOTYPE, LPSTR, INT, LANGID);
static INT (WINAPI *pGetGeoInfoW)(GEOID, GEOTYPE, LPWSTR, INT, LANGID);
static BOOL (WINAPI *pEnumSystemGeoID)(GEOCLASS, GEOID, GEO_ENUMPROC);
+static BOOL (WINAPI *pEnumSystemGeoNames)(GEOCLASS, GEO_ENUMNAMEPROC, LONG_PTR);
static BOOL (WINAPI *pGetSystemPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
static BOOL (WINAPI *pGetThreadPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
static BOOL (WINAPI *pGetUserPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
@@ -115,6 +116,7 @@ static void InitFunctionPointers(void)
X(GetGeoInfoA);
X(GetGeoInfoW);
X(EnumSystemGeoID);
+ X(EnumSystemGeoNames);
X(GetSystemPreferredUILanguages);
X(GetThreadPreferredUILanguages);
X(GetUserPreferredUILanguages);
@@ -5000,6 +5002,122 @@ static void test_EnumSystemGeoID(void)
}
}
+static BOOL CALLBACK test_geoname_enumproc_deadbeef(WCHAR *name, LONG_PTR data)
+{
+ (void)name;
+ ok(data == 0xdeadbeef, "deadbeef: expected 0xdeadbeef, got 0x%lx", data);
+ return FALSE;
+}
+
+struct test_enum_geoname_count_types {
+ unsigned int total, nation, region, both, xx;
+};
+
+static BOOL CALLBACK test_geoname_enumproc_counts(WCHAR *name, LONG_PTR data)
+{
+ struct test_enum_geoname_count_types *ptr = (void*)data;
+
+ /* Known names */
+ static const WCHAR nation[] = {'A','U',0},
+ region[] = {'0','0','1',0},
+ both[] = {'A','N',0},
+ xx[] = {'X','X',0};
+
+ if (!ptr)
+ {
+ ok((INT_PTR)ptr, "geoname_enumproc_counts: expected some pointer, got %p\n", ptr);
+ return FALSE;
+ }
+
+ ptr->total++;
+
+ if (!winetest_strcmpW(name, nation))
+ ptr->nation++;
+ if (!winetest_strcmpW(name, region))
+ ptr->region++;
+ if (!winetest_strcmpW(name, both))
+ ptr->both++;
+ if (!winetest_strcmpW(name, xx))
+ ptr->xx++;
+
+ return TRUE;
+}
+
+static BOOL CALLBACK test_geoname_enumproc_dummy(WCHAR *name, LONG_PTR data)
+{
+ (void)name;
+ (void)data;
+ return FALSE;
+}
+
+static void test_EnumSystemGeoNames(void)
+{
+ struct test_enum_geoname_count_types counts;
+ unsigned int nations, regions, total;
+ BOOL ret;
+
+ if (!pEnumSystemGeoNames)
+ {
+ win_skip("unsupported platform.\n");
+ return;
+ }
+
+ ok(pEnumSystemGeoNames(GEOCLASS_ALL, test_geoname_enumproc_deadbeef, 0xdeadbeef),
+ "deadbeef: expected non-zero ret, got otherwise with error=%d.\n", GetLastError());
+
+ ZeroMemory(&counts, sizeof(counts));
+ ret = pEnumSystemGeoNames(GEOCLASS_NATION, test_geoname_enumproc_counts, (LONG_PTR)&counts);
+ if (ret)
+ {
+ ok(counts.total > 0 && counts.nation > 0 && counts.region == 0 && counts.xx == 0 && counts.both == 0,
+ "GEOCLASS_NATION: got total=%u, nation=%u, region=%u, xx=%u, both=%u (expected to find only nations).\n",
+ counts.total, counts.nation, counts.region, counts.xx, counts.both);
+ }
+ else
+ ok(ret, "GEONAME_NATION: expected non-zero, got otherwise.\n");
+
+ nations = counts.total;
+
+ ZeroMemory(&counts, sizeof(counts));
+ ret = pEnumSystemGeoNames(GEOCLASS_REGION, test_geoname_enumproc_counts, (LONG_PTR)&counts);
+ if (ret)
+ {
+ ok(counts.total > 0 && counts.nation == 0 && counts.region > 0 && counts.xx == 1 && counts.both > 0,
+ "GEOCLASS_REGION: got total=%u, nation=%u, region=%u, xx=%u, both=%u (expected nation==0, region>=1, xx==1, both>=1).\n",
+ counts.total, counts.nation, counts.region, counts.xx, counts.both);
+ }
+ else
+ ok(ret, "GEONAME_REGION: expected ret != 0, got otherwise.\n");
+
+ regions = counts.total;
+
+ ZeroMemory(&counts, sizeof(counts));
+ ret = pEnumSystemGeoNames(GEOCLASS_ALL, test_geoname_enumproc_counts, (LONG_PTR)&counts);
+ if (ret)
+ {
+ ok(counts.total > 0 && counts.nation > 0 && counts.region > 0 && counts.xx > 0 && counts.both > 0,
+ "GEOCLASS_ALL: got total=%u, nation=%u, region=%u, xx=%u, both=%u (expected at least 1 of each)\n",
+ counts.total, counts.nation, counts.region, counts.xx, counts.both);
+ }
+ else
+ ok(ret, "GEONAME_ALL: expected ret != 0, got otherwise.\n");
+
+ total = counts.total;
+ ok(total == nations + regions, "expected total count to match the amount of nations + regions (%u), got %u instead.\n",
+ nations + regions, total);
+
+ /* Try invalid values */
+ SetLastError(ERROR_SUCCESS);
+ ret = pEnumSystemGeoNames(GEOCLASS_ALL, NULL, 0xdeadbeef);
+ ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
+ "null enumproc: expected ret=0 and error=87, got ret=%d and error=%d\n", ret, GetLastError());
+
+ SetLastError(ERROR_SUCCESS);
+ ret = pEnumSystemGeoNames(-1, test_geoname_enumproc_dummy, 0xdeadbeef);
+ ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
+ "invalid geoclass: expected ret=0 and error=1004, got ret=%d and error=%d\n", ret, GetLastError());
+}
+
struct invariant_entry {
const char *name;
int id;
@@ -6171,6 +6289,7 @@ START_TEST(locale)
test_CompareStringOrdinal();
test_GetGeoInfo();
test_EnumSystemGeoID();
+ test_EnumSystemGeoNames();
test_invariant();
test_GetSystemPreferredUILanguages();
test_GetThreadPreferredUILanguages();
diff --git a/include/winnls.h b/include/winnls.h
index b233f7f917..aab6ec4398 100644
--- a/include/winnls.h
+++ b/include/winnls.h
@@ -760,6 +760,7 @@ typedef BOOL (CALLBACK *DATEFMT_ENUMPROCW)(LPWSTR);
typedef BOOL (CALLBACK *DATEFMT_ENUMPROCEXA)(LPSTR,CALID);
typedef BOOL (CALLBACK *DATEFMT_ENUMPROCEXW)(LPWSTR,CALID);
typedef BOOL (CALLBACK *GEO_ENUMPROC)(GEOID);
+typedef BOOL (CALLBACK *GEO_ENUMNAMEPROC)(WCHAR*,LONG_PTR);
typedef BOOL (CALLBACK *LANGGROUPLOCALE_ENUMPROCA)(LGRPID,LCID,LPSTR,LONG_PTR);
typedef BOOL (CALLBACK *LANGGROUPLOCALE_ENUMPROCW)(LGRPID,LCID,LPWSTR,LONG_PTR);
typedef BOOL (CALLBACK *LANGUAGEGROUP_ENUMPROCA)(LGRPID,LPSTR,LPSTR,DWORD,LONG_PTR);
@@ -866,6 +867,7 @@ WINBASEAPI BOOL WINAPI EnumSystemCodePagesA(CODEPAGE_ENUMPROCA,DWORD);
WINBASEAPI BOOL WINAPI EnumSystemCodePagesW(CODEPAGE_ENUMPROCW,DWORD);
#define EnumSystemCodePages WINELIB_NAME_AW(EnumSystemCodePages)
WINBASEAPI BOOL WINAPI EnumSystemGeoID(GEOCLASS,GEOID,GEO_ENUMPROC);
+WINBASEAPI BOOL WINAPI EnumSystemGeoNames(GEOCLASS,GEO_ENUMNAMEPROC,LONG_PTR);
WINBASEAPI BOOL WINAPI EnumSystemLocalesA(LOCALE_ENUMPROCA,DWORD);
WINBASEAPI BOOL WINAPI EnumSystemLocalesW(LOCALE_ENUMPROCW,DWORD);
#define EnumSystemLocales WINELIB_NAME_AW(EnumSystemLocales)
--
2.24.0
More information about the wine-devel
mailing list