diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index d57b461954b05..e20a1b91d83d9 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -3230,8 +3230,6 @@ ORIGIN: ../../../flutter/shell/platform/windows/windows_lifecycle_manager.cc + . ORIGIN: ../../../flutter/shell/platform/windows/windows_lifecycle_manager.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/windows/windows_proc_table.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/windows/windows_proc_table.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/windows/windows_registry.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/windows/windows_registry.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/windows/windowsx_shim.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/profiling/sampling_profiler.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/profiling/sampling_profiler.h + ../../../flutter/LICENSE @@ -5928,8 +5926,6 @@ FILE: ../../../flutter/shell/platform/windows/windows_lifecycle_manager.cc FILE: ../../../flutter/shell/platform/windows/windows_lifecycle_manager.h FILE: ../../../flutter/shell/platform/windows/windows_proc_table.cc FILE: ../../../flutter/shell/platform/windows/windows_proc_table.h -FILE: ../../../flutter/shell/platform/windows/windows_registry.cc -FILE: ../../../flutter/shell/platform/windows/windows_registry.h FILE: ../../../flutter/shell/platform/windows/windowsx_shim.h FILE: ../../../flutter/shell/profiling/sampling_profiler.cc FILE: ../../../flutter/shell/profiling/sampling_profiler.h diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index 0effa94ed4dc8..5ee5b431991c8 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -107,8 +107,6 @@ source_set("flutter_windows_source") { "windows_lifecycle_manager.h", "windows_proc_table.cc", "windows_proc_table.h", - "windows_registry.cc", - "windows_registry.h", "windowsx_shim.h", ] diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index c6c46d7301776..3dd00d422ae0f 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -156,12 +156,9 @@ FlutterLocale CovertToFlutterLocale(const LanguageInfo& info) { } // namespace -FlutterWindowsEngine::FlutterWindowsEngine( - const FlutterProjectBundle& project, - std::unique_ptr registry) +FlutterWindowsEngine::FlutterWindowsEngine(const FlutterProjectBundle& project) : project_(std::make_unique(project)), aot_data_(nullptr, nullptr), - windows_registry_(std::move(registry)), lifecycle_manager_(std::make_unique(this)) { embedder_api_.struct_size = sizeof(FlutterEngineProcTable); FlutterEngineGetProcAddresses(&embedder_api_); @@ -572,7 +569,7 @@ void FlutterWindowsEngine::SetLifecycleState(flutter::AppLifecycleState state) { void FlutterWindowsEngine::SendSystemLocales() { std::vector languages = - GetPreferredLanguageInfo(*windows_registry_); + GetPreferredLanguageInfo(windows_proc_table_); std::vector flutter_locales; flutter_locales.reserve(languages.size()); for (const auto& info : languages) { diff --git a/shell/platform/windows/flutter_windows_engine.h b/shell/platform/windows/flutter_windows_engine.h index 9fd7df9f4985a..01f371d0a4fee 100644 --- a/shell/platform/windows/flutter_windows_engine.h +++ b/shell/platform/windows/flutter_windows_engine.h @@ -37,7 +37,7 @@ #include "flutter/shell/platform/windows/window_proc_delegate_manager.h" #include "flutter/shell/platform/windows/window_state.h" #include "flutter/shell/platform/windows/windows_lifecycle_manager.h" -#include "flutter/shell/platform/windows/windows_registry.h" +#include "flutter/shell/platform/windows/windows_proc_table.h" #include "third_party/rapidjson/include/rapidjson/document.h" namespace flutter { @@ -77,13 +77,8 @@ static void WindowsPlatformThreadPrioritySetter( // run in headless mode. class FlutterWindowsEngine { public: - // Creates a new Flutter engine with an injectible windows registry. - FlutterWindowsEngine(const FlutterProjectBundle& project, - std::unique_ptr windows_registry); - // Creates a new Flutter engine object configured to run |project|. - explicit FlutterWindowsEngine(const FlutterProjectBundle& project) - : FlutterWindowsEngine(project, std::make_unique()) {} + explicit FlutterWindowsEngine(const FlutterProjectBundle& project); virtual ~FlutterWindowsEngine(); @@ -405,12 +400,11 @@ class FlutterWindowsEngine { // The on frame drawn callback. fml::closure next_frame_callback_; - // Wrapper providing Windows registry access. - std::unique_ptr windows_registry_; - // Handler for top level window messages. std::unique_ptr lifecycle_manager_; + WindowsProcTable windows_proc_table_; + FML_DISALLOW_COPY_AND_ASSIGN(FlutterWindowsEngine); }; diff --git a/shell/platform/windows/system_utils.cc b/shell/platform/windows/system_utils.cc index 538330f5226cf..a858042aa3249 100644 --- a/shell/platform/windows/system_utils.cc +++ b/shell/platform/windows/system_utils.cc @@ -13,8 +13,9 @@ namespace flutter { std::vector GetPreferredLanguageInfo( - const WindowsRegistry& registry) { - std::vector languages = GetPreferredLanguages(registry); + const WindowsProcTable& windows_proc_table) { + std::vector languages = + GetPreferredLanguages(windows_proc_table); std::vector language_info; language_info.reserve(languages.size()); @@ -24,63 +25,29 @@ std::vector GetPreferredLanguageInfo( return language_info; } -std::wstring GetPreferredLanguagesFromRegistry(const WindowsRegistry& registry, - ULONG buffer_size) { - std::wstring buffer(buffer_size, '\0'); - if (registry.GetRegistryValue(HKEY_CURRENT_USER, kGetPreferredLanguageRegKey, - kGetPreferredLanguageRegValue, - RRF_RT_REG_MULTI_SZ, NULL, buffer.data(), - &buffer_size) != ERROR_SUCCESS) { - return std::wstring(); - } - return buffer; -} - -std::wstring GetPreferredLanguagesFromMUI() { - ULONG buffer_size; +std::wstring GetPreferredLanguagesFromMUI( + const WindowsProcTable& windows_proc_table) { + ULONG buffer_size = 0; ULONG count = 0; DWORD flags = MUI_LANGUAGE_NAME | MUI_UI_FALLBACK; - if (!GetThreadPreferredUILanguages(flags, &count, nullptr, &buffer_size)) { + if (!windows_proc_table.GetThreadPreferredUILanguages(flags, &count, nullptr, + &buffer_size)) { return std::wstring(); } std::wstring buffer(buffer_size, '\0'); - if (!GetThreadPreferredUILanguages(flags, &count, buffer.data(), - &buffer_size)) { + if (!windows_proc_table.GetThreadPreferredUILanguages( + flags, &count, buffer.data(), &buffer_size)) { return std::wstring(); } return buffer; } std::vector GetPreferredLanguages( - const WindowsRegistry& registry) { + const WindowsProcTable& windows_proc_table) { std::vector languages; - BOOL languages_from_registry = TRUE; - ULONG buffer_size = 0; - ULONG count = 0; - DWORD flags = MUI_LANGUAGE_NAME | MUI_UI_FALLBACK; - - // Determine where languages are defined and get buffer length - if (registry.GetRegistryValue(HKEY_CURRENT_USER, kGetPreferredLanguageRegKey, - kGetPreferredLanguageRegValue, - RRF_RT_REG_MULTI_SZ, NULL, NULL, - &buffer_size) != ERROR_SUCCESS) { - languages_from_registry = FALSE; - } - - // Multi-string must be at least 3-long if non-empty, - // as a multi-string is terminated with 2 nulls. - // - // See: - // https://learn.microsoft.com/windows/win32/sysinfo/registry-value-types - if (languages_from_registry && buffer_size < 3) { - languages_from_registry = FALSE; - } // Initialize the buffer - std::wstring buffer = - languages_from_registry - ? GetPreferredLanguagesFromRegistry(registry, buffer_size) - : GetPreferredLanguagesFromMUI(); + std::wstring buffer = GetPreferredLanguagesFromMUI(windows_proc_table); // Extract the individual languages from the buffer. size_t start = 0; diff --git a/shell/platform/windows/system_utils.h b/shell/platform/windows/system_utils.h index d4072912da2c1..9afa1b90ecc39 100644 --- a/shell/platform/windows/system_utils.h +++ b/shell/platform/windows/system_utils.h @@ -10,7 +10,7 @@ #include #include -#include "flutter/shell/platform/windows/windows_registry.h" +#include "flutter/shell/platform/windows/windows_proc_table.h" namespace flutter { @@ -29,20 +29,17 @@ struct LanguageInfo { // Returns the list of user-preferred languages, in preference order, // parsed into LanguageInfo structures. std::vector GetPreferredLanguageInfo( - const WindowsRegistry& registry); - -// Retrieve the preferred languages from the registry. -std::wstring GetPreferredLanguagesFromRegistry(const WindowsRegistry& registry, - ULONG buffer_size); + const WindowsProcTable& windows_proc_table); // Retrieve the preferred languages from the MUI API. -std::wstring GetPreferredLanguagesFromMUI(); +std::wstring GetPreferredLanguagesFromMUI( + const WindowsProcTable& windows_proc_table); // Returns the list of user-preferred languages, in preference order. // The language names are as described at: // https://docs.microsoft.com/en-us/windows/win32/intl/language-names std::vector GetPreferredLanguages( - const WindowsRegistry& registry); + const WindowsProcTable& windows_proc_table); // Parses a Windows language name into its components. LanguageInfo ParseLanguageName(std::wstring language_name); diff --git a/shell/platform/windows/system_utils_unittests.cc b/shell/platform/windows/system_utils_unittests.cc index ba24493ba16c7..a4a9bcda114b8 100644 --- a/shell/platform/windows/system_utils_unittests.cc +++ b/shell/platform/windows/system_utils_unittests.cc @@ -7,46 +7,16 @@ #include "flutter/fml/macros.h" #include "flutter/shell/platform/windows/system_utils.h" +#include "flutter/shell/platform/windows/testing/mock_windows_proc_table.h" #include "gtest/gtest.h" namespace flutter { namespace testing { -class MockWindowsRegistry : public WindowsRegistry { - public: - MockWindowsRegistry() = default; - virtual ~MockWindowsRegistry() = default; - - virtual LSTATUS GetRegistryValue(HKEY hkey, - LPCWSTR key, - LPCWSTR value, - DWORD flags, - LPDWORD type, - PVOID data, - LPDWORD data_size) const { - using namespace std::string_literals; - static const std::wstring locales = - L"en-US\0zh-Hans-CN\0ja\0zh-Hant-TW\0he\0\0"s; - static DWORD locales_len = locales.size() * sizeof(wchar_t); - if (data != nullptr) { - if (*data_size < locales_len) { - return ERROR_MORE_DATA; - } - std::memcpy(data, locales.data(), locales_len); - *data_size = locales_len; - } else if (data_size != NULL) { - *data_size = locales_len; - } - return ERROR_SUCCESS; - } - - private: - FML_DISALLOW_COPY_AND_ASSIGN(MockWindowsRegistry); -}; - TEST(SystemUtils, GetPreferredLanguageInfo) { - WindowsRegistry registry; - std::vector languages = GetPreferredLanguageInfo(registry); + WindowsProcTable proc_table; + std::vector languages = + GetPreferredLanguageInfo(WindowsProcTable()); // There should be at least one language. ASSERT_GE(languages.size(), 1); // The info should have a valid languge. @@ -54,24 +24,30 @@ TEST(SystemUtils, GetPreferredLanguageInfo) { } TEST(SystemUtils, GetPreferredLanguages) { - WindowsRegistry registry; - std::vector languages = GetPreferredLanguages(registry); + MockWindowsProcTable proc_table; + ON_CALL(proc_table, GetThreadPreferredUILanguages) + .WillByDefault( + [](DWORD flags, PULONG count, PZZWSTR languages, PULONG size) { + // Languages string ends in a double-null. + static const wchar_t lang[] = L"en-US\0"; + static const size_t lang_len = sizeof(lang) / sizeof(wchar_t); + static const int cnt = 1; + if (languages == nullptr) { + *size = lang_len; + *count = cnt; + } else if (*size >= lang_len) { + memcpy(languages, lang, lang_len * sizeof(wchar_t)); + } + return TRUE; + }); + std::vector languages = GetPreferredLanguages(proc_table); // There should be at least one language. ASSERT_GE(languages.size(), 1); // The language should be non-empty. EXPECT_FALSE(languages[0].empty()); // There should not be a trailing null from the parsing step. EXPECT_EQ(languages[0].size(), wcslen(languages[0].c_str())); - - // Test mock results - MockWindowsRegistry mock_registry; - languages = GetPreferredLanguages(mock_registry); - ASSERT_EQ(languages.size(), 5); - ASSERT_EQ(languages[0], std::wstring(L"en-US")); - ASSERT_EQ(languages[1], std::wstring(L"zh-Hans-CN")); - ASSERT_EQ(languages[2], std::wstring(L"ja")); - ASSERT_EQ(languages[3], std::wstring(L"zh-Hant-TW")); - ASSERT_EQ(languages[4], std::wstring(L"he")); + EXPECT_EQ(languages[0], L"en-US"); } TEST(SystemUtils, ParseLanguageNameGeneric) { diff --git a/shell/platform/windows/testing/mock_windows_proc_table.h b/shell/platform/windows/testing/mock_windows_proc_table.h index 2bc6103523659..d2bcea86cec8d 100644 --- a/shell/platform/windows/testing/mock_windows_proc_table.h +++ b/shell/platform/windows/testing/mock_windows_proc_table.h @@ -21,6 +21,9 @@ class MockWindowsProcTable : public WindowsProcTable { MOCK_METHOD2(GetPointerType, BOOL(UINT32 pointer_id, POINTER_INPUT_TYPE* pointer_type)); + MOCK_CONST_METHOD4(GetThreadPreferredUILanguages, + LRESULT(DWORD, PULONG, PZZWSTR, PULONG)); + private: FML_DISALLOW_COPY_AND_ASSIGN(MockWindowsProcTable); }; diff --git a/shell/platform/windows/windows_proc_table.cc b/shell/platform/windows/windows_proc_table.cc index d2b5bd99f4264..cc8319bb0684f 100644 --- a/shell/platform/windows/windows_proc_table.cc +++ b/shell/platform/windows/windows_proc_table.cc @@ -25,4 +25,11 @@ BOOL WindowsProcTable::GetPointerType(UINT32 pointer_id, return get_pointer_type_.value()(pointer_id, pointer_type); } +LRESULT WindowsProcTable::GetThreadPreferredUILanguages(DWORD flags, + PULONG count, + PZZWSTR languages, + PULONG length) const { + return ::GetThreadPreferredUILanguages(flags, count, languages, length); +} + } // namespace flutter diff --git a/shell/platform/windows/windows_proc_table.h b/shell/platform/windows/windows_proc_table.h index 23c9b777a03a7..f8f6a0c7c538d 100644 --- a/shell/platform/windows/windows_proc_table.h +++ b/shell/platform/windows/windows_proc_table.h @@ -13,7 +13,7 @@ namespace flutter { // Lookup table for Windows APIs that aren't available on all versions of -// Windows. +// Windows, or for mocking Windows API calls. class WindowsProcTable { public: WindowsProcTable(); @@ -26,6 +26,15 @@ class WindowsProcTable { virtual BOOL GetPointerType(UINT32 pointer_id, POINTER_INPUT_TYPE* pointer_type); + // Get the preferred languages for the thread, and optionally the process, + // and system, in that order, depending on the flags. + // See + // https://learn.microsoft.com/windows/win32/api/winnls/nf-winnls-getthreadpreferreduilanguages + virtual LRESULT GetThreadPreferredUILanguages(DWORD flags, + PULONG count, + PZZWSTR languages, + PULONG length) const; + private: using GetPointerType_ = BOOL __stdcall(UINT32 pointerId, POINTER_INPUT_TYPE* pointerType); diff --git a/shell/platform/windows/windows_registry.cc b/shell/platform/windows/windows_registry.cc deleted file mode 100644 index 0b929981f88b5..0000000000000 --- a/shell/platform/windows/windows_registry.cc +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "flutter/shell/platform/windows/windows_registry.h" - -namespace flutter { - -LSTATUS WindowsRegistry::GetRegistryValue(HKEY hkey, - LPCWSTR key, - LPCWSTR value, - DWORD flags, - LPDWORD type, - PVOID data, - LPDWORD data_size) const { - return RegGetValue(hkey, key, value, flags, type, data, data_size); -} - -} // namespace flutter diff --git a/shell/platform/windows/windows_registry.h b/shell/platform/windows/windows_registry.h deleted file mode 100644 index b46fbc2be6268..0000000000000 --- a/shell/platform/windows/windows_registry.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_WINDOWS_REGISTRY_H_ -#define FLUTTER_SHELL_PLATFORM_WINDOWS_WINDOWS_REGISTRY_H_ - -#include - -#include "flutter/fml/macros.h" - -namespace flutter { - -/// A utility class to encapsulate interaction with the Windows registry. -/// By encapsulating this in a class, we can mock out this functionality -/// for unit testing. -class WindowsRegistry { - public: - WindowsRegistry() = default; - virtual ~WindowsRegistry() = default; - - // Parameters and return values of this method match those of RegGetValue - // See: - // https://learn.microsoft.com/windows/win32/api/winreg/nf-winreg-reggetvaluew - virtual LSTATUS GetRegistryValue(HKEY hkey, - LPCWSTR key, - LPCWSTR value, - DWORD flags, - LPDWORD type, - PVOID data, - LPDWORD data_size) const; - - private: - FML_DISALLOW_COPY_AND_ASSIGN(WindowsRegistry); -}; - -} // namespace flutter - -#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_WINDOWS_REGISTRY_H_