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 <thiago.macieira@intel.com>
This commit is contained in:
Kai Köhne 2025-03-10 09:11:30 -04:00
parent f5ac4a7f14
commit fde0022854
2 changed files with 17 additions and 1 deletions

View File

@ -876,9 +876,10 @@ qt_internal_extend_target(Core CONDITION WIN32
text/qlocale_win.cpp 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 qt_internal_extend_target(Core CONDITION QT_FEATURE_winsdkicu
LIBRARIES LIBRARIES
icu icuuc icuin
) )
qt_internal_extend_target(Core CONDITION WASM qt_internal_extend_target(Core CONDITION WASM

View File

@ -15,14 +15,21 @@
#include <QtCore/qbytearraylist.h> #include <QtCore/qbytearraylist.h>
#if QT_CONFIG(icu) #if QT_CONFIG(icu)
#include <unicode/ucnv.h> #include <unicode/ucnv.h>
#include <unicode/ucnv_cb.h> #include <unicode/ucnv_cb.h>
#include <unicode/ucnv_err.h> #include <unicode/ucnv_err.h>
#include <unicode/ustring.h> #include <unicode/ustring.h>
#define QT_USE_ICU_CODECS #define QT_USE_ICU_CODECS
#define QT_COM_THREAD_INIT
#elif QT_CONFIG(winsdkicu) #elif QT_CONFIG(winsdkicu)
#include <icu.h> #include <icu.h>
#include <private/qfunctions_win_p.h>
#define QT_USE_ICU_CODECS #define QT_USE_ICU_CODECS
#define QT_COM_THREAD_INIT qt_win_ensureComInitializedOnThisThread();
#endif // QT_CONFIG(icu) || QT_CONFIG(winsdkicu) #endif // QT_CONFIG(icu) || QT_CONFIG(winsdkicu)
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
@ -1841,6 +1848,7 @@ void QStringConverter::State::reset() noexcept
{ {
if (flags & Flag::UsesIcu) { if (flags & Flag::UsesIcu) {
#if defined(QT_USE_ICU_CODECS) #if defined(QT_USE_ICU_CODECS)
QT_COM_THREAD_INIT
UConverter *converter = static_cast<UConverter *>(d[0]); UConverter *converter = static_cast<UConverter *>(d[0]);
if (converter) if (converter)
ucnv_reset(converter); ucnv_reset(converter);
@ -2162,6 +2170,7 @@ struct QStringConverterICU : QStringConverter
{ {
static void clear_function(QStringConverter::State *state) noexcept static void clear_function(QStringConverter::State *state) noexcept
{ {
QT_COM_THREAD_INIT
ucnv_close(static_cast<UConverter *>(state->d[0])); ucnv_close(static_cast<UConverter *>(state->d[0]));
state->d[0] = nullptr; state->d[0] = nullptr;
} }
@ -2176,6 +2185,7 @@ struct QStringConverterICU : QStringConverter
static QChar *toUtf16(QChar *out, QByteArrayView in, QStringConverter::State *state) static QChar *toUtf16(QChar *out, QByteArrayView in, QStringConverter::State *state)
{ {
QT_COM_THREAD_INIT
ensureConverter(state); ensureConverter(state);
auto icu_conv = static_cast<UConverter *>(state->d[0]); auto icu_conv = static_cast<UConverter *>(state->d[0]);
@ -2212,6 +2222,7 @@ struct QStringConverterICU : QStringConverter
static char *fromUtf16(char *out, QStringView in, QStringConverter::State *state) static char *fromUtf16(char *out, QStringView in, QStringConverter::State *state)
{ {
QT_COM_THREAD_INIT
ensureConverter(state); ensureConverter(state);
auto icu_conv = static_cast<UConverter *>(state->d[0]); auto icu_conv = static_cast<UConverter *>(state->d[0]);
UErrorCode err = U_ZERO_ERROR; UErrorCode err = U_ZERO_ERROR;
@ -2277,6 +2288,7 @@ struct QStringConverterICU : QStringConverter
{ {
Q_ASSERT(name); Q_ASSERT(name);
Q_ASSERT(state); Q_ASSERT(state);
QT_COM_THREAD_INIT
UErrorCode status = U_ZERO_ERROR; UErrorCode status = U_ZERO_ERROR;
UConverter *conv = ucnv_open(name, &status); UConverter *conv = ucnv_open(name, &status);
if (status != U_ZERO_ERROR && status != U_AMBIGUOUS_ALIAS_WARNING) { if (status != U_ZERO_ERROR && status != U_AMBIGUOUS_ALIAS_WARNING) {
@ -2383,6 +2395,7 @@ struct QStringConverterICU : QStringConverter
QStringConverter::State *state, QStringConverter::State *state,
const char *name) const char *name)
{ {
QT_COM_THREAD_INIT
UErrorCode status = U_ZERO_ERROR; UErrorCode status = U_ZERO_ERROR;
UConverter *conv = createConverterForName(name, state); UConverter *conv = createConverterForName(name, state);
if (!conv) if (!conv)
@ -2617,6 +2630,7 @@ static qsizetype availableCodecCount()
#if !defined(QT_USE_ICU_CODECS) #if !defined(QT_USE_ICU_CODECS)
return QStringConverter::Encoding::LastEncoding; return QStringConverter::Encoding::LastEncoding;
#else #else
QT_COM_THREAD_INIT
/* icu contains also the names of what Qt provides /* icu contains also the names of what Qt provides
except for the special Locale one (so add one for it) 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 if (index == 0) // "Locale", not provided by icu
return QString::fromLatin1( return QString::fromLatin1(
encodingInterfaces[QStringConverter::Encoding::System].name); encodingInterfaces[QStringConverter::Encoding::System].name);
QT_COM_THREAD_INIT
// this mirrors the setup we do to set a converters name // this mirrors the setup we do to set a converters name
UErrorCode status = U_ZERO_ERROR; UErrorCode status = U_ZERO_ERROR;
auto icuName = ucnv_getAvailableName(int32_t(index - 1)); auto icuName = ucnv_getAvailableName(int32_t(index - 1));