[PATCH v11 0/1] MR6131: Extend bcp47langs.dll with GetUserLanguages
This is an undocumented API used by some programs to fetch the user's selected languages. Example is Fusion360 (during its login process). Signature currently taken from here: https://stackoverflow.com/questions/63877075/what-is-the-right-way-to-get-th... (Maybe that stackoverflow answer is also why Fusion has implemented this...) I'm a first-time contributor, please point out if I'm doing anything wrong -- v11: bcp47langs: Implement GetUserLanguages() https://gitlab.winehq.org/wine/wine/-/merge_requests/6131
From: Marius Schiffer <marius(a)mschiffer.de> Implement an undocumented API used by some programs to fetch the user's selected languages. Returns current locale. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56915 --- configure.ac | 1 + dlls/bcp47langs/Makefile.in | 4 +++ dlls/bcp47langs/bcp47langs.spec | 2 +- dlls/bcp47langs/main.c | 23 ++++++++++++++ dlls/bcp47langs/tests/Makefile.in | 6 ++++ dlls/bcp47langs/tests/bcp47langs.c | 50 ++++++++++++++++++++++++++++++ include/Makefile.in | 1 + include/bcp47langs.h | 35 +++++++++++++++++++++ 8 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 dlls/bcp47langs/main.c create mode 100644 dlls/bcp47langs/tests/Makefile.in create mode 100644 dlls/bcp47langs/tests/bcp47langs.c create mode 100644 include/bcp47langs.h diff --git a/configure.ac b/configure.ac index 6d093b52526..534ce5cb092 100644 --- a/configure.ac +++ b/configure.ac @@ -2467,6 +2467,7 @@ WINE_CONFIG_MAKEFILE(dlls/avifil32/tests) WINE_CONFIG_MAKEFILE(dlls/avifile.dll16) WINE_CONFIG_MAKEFILE(dlls/avrt) WINE_CONFIG_MAKEFILE(dlls/bcp47langs) +WINE_CONFIG_MAKEFILE(dlls/bcp47langs/tests) WINE_CONFIG_MAKEFILE(dlls/bcrypt) WINE_CONFIG_MAKEFILE(dlls/bcrypt/tests) WINE_CONFIG_MAKEFILE(dlls/bcryptprimitives) diff --git a/dlls/bcp47langs/Makefile.in b/dlls/bcp47langs/Makefile.in index 5eb4caaf0e7..dfe10916951 100644 --- a/dlls/bcp47langs/Makefile.in +++ b/dlls/bcp47langs/Makefile.in @@ -1,2 +1,6 @@ MODULE = bcp47langs.dll IMPORTLIB = bcp47langs +IMPORTS = combase + +SOURCES = \ + main.c diff --git a/dlls/bcp47langs/bcp47langs.spec b/dlls/bcp47langs/bcp47langs.spec index a054c1486a9..969f77b56b8 100644 --- a/dlls/bcp47langs/bcp47langs.spec +++ b/dlls/bcp47langs/bcp47langs.spec @@ -48,7 +48,7 @@ @ stub GetUserDisplayLanguageOverride @ stub GetUserLanguageInputMethods @ stub GetUserLanguageInputMethodsForUser -@ stub GetUserLanguages +@ stdcall GetUserLanguages(long ptr) @ stub GetUserLanguagesForAllUsers @ stub GetUserLanguagesForUser @ stub GetUserLocaleFromLanguageProfileOptOut diff --git a/dlls/bcp47langs/main.c b/dlls/bcp47langs/main.c new file mode 100644 index 00000000000..0732aeff581 --- /dev/null +++ b/dlls/bcp47langs/main.c @@ -0,0 +1,23 @@ +#include <winstring.h> +#include "winnls.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(bcp47langs); + +HRESULT WINAPI WINAPI GetUserLanguages(WCHAR delimiter, HSTRING *user_languages) +{ + HRESULT hr; + WCHAR locale[LOCALE_NAME_MAX_LENGTH]; + + if (!user_languages) + return E_INVALIDARG; + + if (!GetUserDefaultLocaleName(locale, LOCALE_NAME_MAX_LENGTH)) + return E_FAIL; + + if (FAILED(hr = WindowsCreateString(locale, wcslen(locale), user_languages))) + return hr; + + return S_OK; +} diff --git a/dlls/bcp47langs/tests/Makefile.in b/dlls/bcp47langs/tests/Makefile.in new file mode 100644 index 00000000000..498e1b34afe --- /dev/null +++ b/dlls/bcp47langs/tests/Makefile.in @@ -0,0 +1,6 @@ +TESTDLL = bcp47langs.dll +IMPORTS = bcp47langs msvcrt combase + +SOURCES = \ + bcp47langs.c + diff --git a/dlls/bcp47langs/tests/bcp47langs.c b/dlls/bcp47langs/tests/bcp47langs.c new file mode 100644 index 00000000000..a6bdf3ed9e4 --- /dev/null +++ b/dlls/bcp47langs/tests/bcp47langs.c @@ -0,0 +1,50 @@ +/* + * Copyright 2025 Marius Schiffer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <winbase.h> + +#include "winstring.h" +#include "msvcrt/locale.h" +#include "bcp47langs.h" + +#include "wine/test.h" + +static void test_GetUserLanguages(void) +{ + HSTRING result; + const WCHAR *user_languages; + + ok(GetUserLanguages(',', NULL) == E_INVALIDARG, "unknown return code\n"); + + setlocale(LC_ALL, "enu"); + ok(GetUserLanguages(',', &result) == 0, "unknown return code\n"); + user_languages = WindowsGetStringRawBuffer(result, NULL); + ok(!lstrcmpW(user_languages, L"en-US"), "languages=%s\n", debugstr_w(user_languages)); + + setlocale(LC_ALL, "deu"); + ok(GetUserLanguages(',', &result) == 0, "unknown return code\n"); + user_languages = WindowsGetStringRawBuffer(result, NULL); + ok(!lstrcmpW(user_languages, L"de-DE"), "languages=%s\n", debugstr_w(user_languages)); + + WindowsDeleteString(user_languages); +} + +START_TEST(bcp47langs) +{ + test_get_user_languages(); +} diff --git a/include/Makefile.in b/include/Makefile.in index 650d69815f8..694c6f78312 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -45,6 +45,7 @@ SOURCES = \ axextendenums.h \ basetsd.h \ basetyps.h \ + bcp47langs.h \ bcrypt.h \ bdaiface.idl \ bdaiface_enums.h \ diff --git a/include/bcp47langs.h b/include/bcp47langs.h new file mode 100644 index 00000000000..4aba6e6195c --- /dev/null +++ b/include/bcp47langs.h @@ -0,0 +1,35 @@ +/* + * bcp47langs definitions + * + * Copyright 2025 Marius Schiffer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#ifndef _BCP47LANGS_ +#define _BCP47LANGS_ + +#ifdef __cplusplus +extern "C" { +#endif + +DWORD WINAPI GetUserLanguages(char delimiter, HSTRING *user_languages); + +#ifdef __cplusplus +} +#endif + +#endif /* _BCP47LANGS_ */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6131
Let's rename the commit subject to "bcp47langs: Add GetUserLanguages() stub.
This hasn't been addressed. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/6131#note_109439
Zhiyi Zhang (@zhiyi) commented about dlls/bcp47langs/main.c:
+#include <winstring.h> +#include "winnls.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(bcp47langs); + +HRESULT WINAPI WINAPI GetUserLanguages(WCHAR delimiter, HSTRING *user_languages) There are two WINAPI here.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/6131#note_109436
Zhiyi Zhang (@zhiyi) commented about dlls/bcp47langs/tests/bcp47langs.c:
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <winbase.h> + +#include "winstring.h" +#include "msvcrt/locale.h" +#include "bcp47langs.h" + +#include "wine/test.h" + +static void test_GetUserLanguages(void) +{ + HSTRING result; + const WCHAR *user_languages; + Let's use a loop and static test data to test it. For example
static const struct
{
const char *locale;
const WCHAR *expected_languages;
}
tests[] =
{
{"enu", L"en-US"},
...
add usual locales, for example, English, Chinese, Japanese, Korean, Arabic, French, German.
}
for (int i =0; i < ARRAY_SIZE(tests); i++)
{
winetest_push_context("%d", i);
setlocale(LC_ALL, tests[i].locale);
ok(GetUserLanguages(',', &result) == 0, "unknown return code\n");
user_languages = WindowsGetStringRawBuffer(result, NULL);
ok(!lstrcmpW(user_languages, tests[i].expected_languages), "languages=%s\n", debugstr_w(user_languages));
winetest_pop_context();
}
And remember to restore the original locale when the test ends. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/6131#note_109441
Zhiyi Zhang (@zhiyi) commented about dlls/bcp47langs/tests/Makefile.in:
+TESTDLL = bcp47langs.dll +IMPORTS = bcp47langs msvcrt combase + +SOURCES = \ Please rebase this patch on top of master. The bcp47langs tests are added after MR8448
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/6131#note_109440
You need to fix those CI failures. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/6131#note_109438
Zhiyi Zhang (@zhiyi) commented about include/bcp47langs.h:
+/* + * bcp47langs definitions + * + * Copyright 2025 Marius Schiffer + * There is no bcp47langs.h in Windows SDK. Let's remove this file and declare the function in tests.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/6131#note_109435
Zhiyi Zhang (@zhiyi) commented about dlls/bcp47langs/main.c:
+#include <winstring.h> +#include "winnls.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(bcp47langs); + +HRESULT WINAPI WINAPI GetUserLanguages(WCHAR delimiter, HSTRING *user_languages) +{ Let's add a FIXME("... stub!\n", ...) here.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/6131#note_109437
This merge request was closed by Zhiyi Zhang. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/6131
participants (3)
-
Marius Schiffer -
Marius Schiffer (@MariusSchiffer) -
Zhiyi Zhang (@zhiyi)