From fde00228545e7a28cf7fba0112df7c4a77db88b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20K=C3=B6hne?= Date: Mon, 10 Mar 2025 09:11:30 -0400 Subject: [PATCH] Fix 'ICU.dll is not available' on Windows 10 1809 The combined icu.dll was only made part of the OS in Windows 10 1903. Since we still support 1809, we cannot rely on it. The old API unfortunately also requires explicit initialization / deinitialization of COM with CoInitializeEx / CoUninitialize. Make sure that initialization happens in the current thread by calling the qt_win_ensureComInitializedOnThisThread() helper function in relevant code paths. Fixes: QTBUG-134540 Pick-to: 6.9 6.9.0 Change-Id: I01677ccc8bfd3780267e3c788295d4ac2b0ed93c Reviewed-by: Thiago Macieira --- src/corelib/CMakeLists.txt | 3 ++- src/corelib/text/qstringconverter.cpp | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index c18344cfc81..95fe57202a5 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -876,9 +876,10 @@ qt_internal_extend_target(Core CONDITION WIN32 text/qlocale_win.cpp ) +# Switch this to just 'icu' once we can expect Windows 10 version 1903 qt_internal_extend_target(Core CONDITION QT_FEATURE_winsdkicu LIBRARIES - icu + icuuc icuin ) qt_internal_extend_target(Core CONDITION WASM diff --git a/src/corelib/text/qstringconverter.cpp b/src/corelib/text/qstringconverter.cpp index 894e5608f28..74881f5986b 100644 --- a/src/corelib/text/qstringconverter.cpp +++ b/src/corelib/text/qstringconverter.cpp @@ -15,14 +15,21 @@ #include #if QT_CONFIG(icu) + #include #include #include #include #define QT_USE_ICU_CODECS +#define QT_COM_THREAD_INIT + #elif QT_CONFIG(winsdkicu) + #include +#include #define QT_USE_ICU_CODECS +#define QT_COM_THREAD_INIT qt_win_ensureComInitializedOnThisThread(); + #endif // QT_CONFIG(icu) || QT_CONFIG(winsdkicu) #ifdef Q_OS_WIN @@ -1841,6 +1848,7 @@ void QStringConverter::State::reset() noexcept { if (flags & Flag::UsesIcu) { #if defined(QT_USE_ICU_CODECS) + QT_COM_THREAD_INIT UConverter *converter = static_cast(d[0]); if (converter) ucnv_reset(converter); @@ -2162,6 +2170,7 @@ struct QStringConverterICU : QStringConverter { static void clear_function(QStringConverter::State *state) noexcept { + QT_COM_THREAD_INIT ucnv_close(static_cast(state->d[0])); state->d[0] = nullptr; } @@ -2176,6 +2185,7 @@ struct QStringConverterICU : QStringConverter static QChar *toUtf16(QChar *out, QByteArrayView in, QStringConverter::State *state) { + QT_COM_THREAD_INIT ensureConverter(state); auto icu_conv = static_cast(state->d[0]); @@ -2212,6 +2222,7 @@ struct QStringConverterICU : QStringConverter static char *fromUtf16(char *out, QStringView in, QStringConverter::State *state) { + QT_COM_THREAD_INIT ensureConverter(state); auto icu_conv = static_cast(state->d[0]); UErrorCode err = U_ZERO_ERROR; @@ -2277,6 +2288,7 @@ struct QStringConverterICU : QStringConverter { Q_ASSERT(name); Q_ASSERT(state); + QT_COM_THREAD_INIT UErrorCode status = U_ZERO_ERROR; UConverter *conv = ucnv_open(name, &status); if (status != U_ZERO_ERROR && status != U_AMBIGUOUS_ALIAS_WARNING) { @@ -2383,6 +2395,7 @@ struct QStringConverterICU : QStringConverter QStringConverter::State *state, const char *name) { + QT_COM_THREAD_INIT UErrorCode status = U_ZERO_ERROR; UConverter *conv = createConverterForName(name, state); if (!conv) @@ -2617,6 +2630,7 @@ static qsizetype availableCodecCount() #if !defined(QT_USE_ICU_CODECS) return QStringConverter::Encoding::LastEncoding; #else + QT_COM_THREAD_INIT /* icu contains also the names of what Qt provides except for the special Locale one (so add one for it) */ @@ -2647,6 +2661,7 @@ QStringList QStringConverter::availableCodecs() if (index == 0) // "Locale", not provided by icu return QString::fromLatin1( encodingInterfaces[QStringConverter::Encoding::System].name); + QT_COM_THREAD_INIT // this mirrors the setup we do to set a converters name UErrorCode status = U_ZERO_ERROR; auto icuName = ucnv_getAvailableName(int32_t(index - 1));