diff --git a/extlib/qt-patches/qtbase-6.8.3-win7.patch b/extlib/qt-patches/qtbase-6.8.3-win7.patch new file mode 100644 index 0000000..6549bef --- /dev/null +++ b/extlib/qt-patches/qtbase-6.8.3-win7.patch @@ -0,0 +1,2629 @@ +Source: https://github.com/crystalidea/qt6windows7 +Release 6.8.3 + +diff --git a/src/corelib/io/qstandardpaths_win.cpp b/src/corelib/io/qstandardpaths_win.cpp +index 805ce65a5ac..6ed351d2e82 100644 +--- a/src/corelib/io/qstandardpaths_win.cpp ++++ b/src/corelib/io/qstandardpaths_win.cpp +@@ -12,6 +12,7 @@ + + #include + #include ++#include + #include + #include + +@@ -60,20 +61,26 @@ static inline void appendTestMode(QString &path) + + static bool isProcessLowIntegrity() + { ++ if (!IsWindows8OrGreater()) ++ return false; ++ + // same as GetCurrentProcessToken() + const auto process_token = HANDLE(quintptr(-4)); + + QVarLengthArray token_info_buf(256); + auto* token_info = reinterpret_cast(token_info_buf.data()); + DWORD token_info_length = token_info_buf.size(); +- if (!GetTokenInformation(process_token, TokenIntegrityLevel, token_info, token_info_length, &token_info_length)) { ++ if (!GetTokenInformation(process_token, TokenIntegrityLevel, token_info, token_info_length, &token_info_length) ++ && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // grow buffer and retry GetTokenInformation + token_info_buf.resize(token_info_length); + token_info = reinterpret_cast(token_info_buf.data()); + if (!GetTokenInformation(process_token, TokenIntegrityLevel, token_info, token_info_length, &token_info_length)) + return false; // assume "normal" process + } +- ++ else ++ return false; ++ + // The GetSidSubAuthorityCount return-code is undefined on failure, so + // there's no point in checking before dereferencing + DWORD integrity_level = *GetSidSubAuthority(token_info->Label.Sid, *GetSidSubAuthorityCount(token_info->Label.Sid) - 1); +diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp +index a7663b24813..8459cd5cad0 100644 +--- a/src/corelib/kernel/qeventdispatcher_win.cpp ++++ b/src/corelib/kernel/qeventdispatcher_win.cpp +@@ -360,10 +360,15 @@ void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t) + ok = t->fastTimerId; + } + +- if (!ok) { ++ typedef BOOL (WINAPI *SetCoalescableTimerFunc) (HWND, UINT_PTR, UINT, TIMERPROC, ULONG); ++ static SetCoalescableTimerFunc mySetCoalescableTimerFunc = ++ (SetCoalescableTimerFunc)::GetProcAddress(::GetModuleHandle(L"User32"), "SetCoalescableTimer"); ++ ++ if (!ok && mySetCoalescableTimerFunc) { + // user normal timers for (Very)CoarseTimers, or if no more multimedia timers available +- ok = SetCoalescableTimer(internalHwnd, t->timerId, interval, nullptr, tolerance); ++ ok = mySetCoalescableTimerFunc(internalHwnd, t->timerId, interval, nullptr, tolerance); + } ++ + if (!ok) + ok = SetTimer(internalHwnd, t->timerId, interval, nullptr); + +diff --git a/src/corelib/kernel/qfunctions_win.cpp b/src/corelib/kernel/qfunctions_win.cpp +index 048fdbc934c..e715093d27b 100644 +--- a/src/corelib/kernel/qfunctions_win.cpp ++++ b/src/corelib/kernel/qfunctions_win.cpp +@@ -44,10 +44,17 @@ QComHelper::~QComHelper() + */ + bool qt_win_hasPackageIdentity() + { ++ typedef BOOL (WINAPI *GetCurrentPackageFullNameFunc) (UINT32 *, PWSTR); ++ static GetCurrentPackageFullNameFunc myGetCurrentPackageFullName = ++ (GetCurrentPackageFullNameFunc)::GetProcAddress(::GetModuleHandle(L"kernel32"), "GetCurrentPackageFullName"); ++ ++ if (myGetCurrentPackageFullName) ++ { + #if defined(HAS_APPMODEL) ++ + static const bool hasPackageIdentity = []() { + UINT32 length = 0; +- switch (const auto result = GetCurrentPackageFullName(&length, nullptr)) { ++ switch (const auto result = myGetCurrentPackageFullName(&length, nullptr)) { + case ERROR_INSUFFICIENT_BUFFER: + return true; + case APPMODEL_ERROR_NO_PACKAGE: +@@ -61,6 +68,9 @@ bool qt_win_hasPackageIdentity() + #else + return false; + #endif ++ } ++ ++ return false; + } + + QT_END_NAMESPACE +diff --git a/src/corelib/thread/qfutex_p.h b/src/corelib/thread/qfutex_p.h +index 8ba798f9209..f6a8dda6b81 100644 +--- a/src/corelib/thread/qfutex_p.h ++++ b/src/corelib/thread/qfutex_p.h +@@ -40,8 +40,8 @@ QT_END_NAMESPACE + #elif defined(Q_OS_LINUX) && !defined(QT_LINUXBASE) + // use Linux mutexes everywhere except for LSB builds + # include "qfutex_linux_p.h" +-#elif defined(Q_OS_WIN) +-# include "qfutex_win_p.h" ++//#elif defined(Q_OS_WIN) ++//# include "qfutex_win_p.h" + #else + QT_BEGIN_NAMESPACE + namespace QtFutex = QtDummyFutex; +diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp +index 1b8f76f1230..9e2fe83968c 100644 +--- a/src/corelib/thread/qmutex.cpp ++++ b/src/corelib/thread/qmutex.cpp +@@ -915,6 +915,8 @@ QT_END_NAMESPACE + // nothing + #elif defined(Q_OS_DARWIN) + # include "qmutex_mac.cpp" ++#elif defined(Q_OS_WIN) ++# include "qmutex_win.cpp" + #else + # include "qmutex_unix.cpp" + #endif +diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h +index aabb66fa550..a16d5082154 100644 +--- a/src/corelib/thread/qmutex_p.h ++++ b/src/corelib/thread/qmutex_p.h +@@ -86,6 +86,8 @@ public: + semaphore_t mach_semaphore; + #elif defined(Q_OS_UNIX) + sem_t semaphore; ++#elif defined(Q_OS_WIN) ++ Qt::HANDLE event; + #endif + }; + +diff --git a/src/corelib/thread/qmutex_win.cpp b/src/corelib/thread/qmutex_win.cpp +new file mode 100644 +index 00000000000..9186f89a341 +--- /dev/null ++++ b/src/corelib/thread/qmutex_win.cpp +@@ -0,0 +1,30 @@ ++// Copyright (C) 2016 The Qt Company Ltd. ++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only ++ ++#include "qmutex.h" ++#include ++#include "qmutex_p.h" ++#include ++ ++QT_BEGIN_NAMESPACE ++ ++QMutexPrivate::QMutexPrivate() ++{ ++ event = CreateEvent(0, FALSE, FALSE, 0); ++ ++ if (!event) ++ qWarning("QMutexPrivate::QMutexPrivate: Cannot create event"); ++} ++ ++QMutexPrivate::~QMutexPrivate() ++{ CloseHandle(event); } ++ ++bool QMutexPrivate::wait(QDeadlineTimer timeout) ++{ ++ return (WaitForSingleObjectEx(event, timeout.isForever() ? INFINITE : timeout.remainingTime(), FALSE) == WAIT_OBJECT_0); ++} ++ ++void QMutexPrivate::wakeUp() noexcept ++{ SetEvent(event); } ++ ++QT_END_NAMESPACE +\ No newline at end of file +diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp +index 88ba6dc8f62..c544d972f68 100644 +--- a/src/corelib/thread/qthread_win.cpp ++++ b/src/corelib/thread/qthread_win.cpp +@@ -227,6 +227,62 @@ DWORD WINAPI qt_adopted_thread_watcher_function(LPVOID) + return 0; + } + ++#ifndef Q_OS_WIN64 ++# define ULONG_PTR DWORD ++#endif ++ ++typedef struct tagTHREADNAME_INFO ++{ ++ DWORD dwType; // must be 0x1000 ++ LPCSTR szName; // pointer to name (in user addr space) ++ HANDLE dwThreadID; // thread ID (-1=caller thread) ++ DWORD dwFlags; // reserved for future use, must be zero ++} THREADNAME_INFO; ++ ++typedef HRESULT(WINAPI* SetThreadDescriptionFunc)(HANDLE, PCWSTR); ++ ++#if defined(Q_CC_MSVC) ++ ++// Helper function to set the thread name using RaiseException and __try ++static void setThreadNameUsingException(HANDLE threadId, LPCSTR threadName) { ++ THREADNAME_INFO info; ++ info.dwType = 0x1000; ++ info.szName = threadName; ++ info.dwThreadID = threadId; ++ info.dwFlags = 0; ++ ++ __try { ++ RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), ++ reinterpret_cast(&info)); ++ } ++ __except (EXCEPTION_CONTINUE_EXECUTION) { ++ } ++} ++ ++#endif // Q_CC_MSVC ++ ++void qt_set_thread_name(HANDLE threadId, const QString &name) ++{ ++ HMODULE hKernel32 = GetModuleHandleW(L"Kernel32.dll"); ++ ++ SetThreadDescriptionFunc pSetThreadDescription = ++ reinterpret_cast(GetProcAddress(hKernel32, "SetThreadDescription")); ++ ++ if (pSetThreadDescription) { ++ pSetThreadDescription(threadId, reinterpret_cast(name.utf16()) ); ++ } ++ else { ++ ++ #if defined(Q_CC_MSVC) ++ ++ std::string stdStr = name.toStdString(); ++ LPCSTR threadName = stdStr.c_str(); ++ setThreadNameUsingException(threadId, threadName); ++ ++ #endif // Q_CC_MSVC ++ } ++} ++ + /************************************************************************** + ** QThreadPrivate + *************************************************************************/ +@@ -264,7 +320,7 @@ unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(voi + QString threadName = std::exchange(thr->d_func()->objectName, {}); + if (Q_LIKELY(threadName.isEmpty())) + threadName = QString::fromUtf8(thr->metaObject()->className()); +- SetThreadDescription(GetCurrentThread(), reinterpret_cast(threadName.utf16())); ++ qt_set_thread_name(GetCurrentThread(), threadName); + + emit thr->started(QThread::QPrivateSignal()); + QThread::setTerminationEnabled(true); +diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp +index 9e2e0c4e81c..eae05a0e61a 100644 +--- a/src/gui/rhi/qrhid3d11.cpp ++++ b/src/gui/rhi/qrhid3d11.cpp +@@ -12,6 +12,8 @@ + + #include + ++#include ++ + QT_BEGIN_NAMESPACE + + using namespace Qt::StringLiterals; +@@ -184,13 +186,22 @@ inline Int aligned(Int v, Int byteAlign) + + static IDXGIFactory1 *createDXGIFactory2() + { ++ typedef HRESULT(WINAPI* CreateDXGIFactory2Func) (UINT flags, REFIID riid, void** factory); ++ static CreateDXGIFactory2Func myCreateDXGIFactory2 = ++ (CreateDXGIFactory2Func)::GetProcAddress(::GetModuleHandle(L"dxgi"), "CreateDXGIFactory2"); ++ + IDXGIFactory1 *result = nullptr; +- const HRESULT hr = CreateDXGIFactory2(0, __uuidof(IDXGIFactory2), reinterpret_cast(&result)); +- if (FAILED(hr)) { +- qWarning("CreateDXGIFactory2() failed to create DXGI factory: %s", +- qPrintable(QSystemError::windowsComString(hr))); +- result = nullptr; ++ ++ if (myCreateDXGIFactory2) ++ { ++ const HRESULT hr = myCreateDXGIFactory2(0, __uuidof(IDXGIFactory2), reinterpret_cast(&result)); ++ if (FAILED(hr)) { ++ qWarning("CreateDXGIFactory2() failed to create DXGI factory: %s", ++ qPrintable(QSystemError::windowsComString(hr))); ++ result = nullptr; ++ } + } ++ + return result; + } + +@@ -5103,6 +5114,15 @@ static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + + bool QD3D11SwapChain::createOrResize() + { ++ if (IsWindows10OrGreater()) ++ { ++ // continue ++ } ++ else ++ { ++ return createOrResizeWin7(); ++ } ++ + // Can be called multiple times due to window resizes - that is not the + // same as a simple destroy+create (as with other resources). Just need to + // resize the buffers then. +@@ -5427,4 +5447,9 @@ bool QD3D11SwapChain::createOrResize() + return true; + } + ++bool QD3D11SwapChain::createOrResizeWin7() ++{ ++ return false; // not implemented yet ;( ++} ++ + QT_END_NAMESPACE +diff --git a/src/gui/rhi/qrhid3d11_p.h b/src/gui/rhi/qrhid3d11_p.h +index 44ad7017d9f..7f232f1ae9c 100644 +--- a/src/gui/rhi/qrhid3d11_p.h ++++ b/src/gui/rhi/qrhid3d11_p.h +@@ -596,6 +596,7 @@ struct QD3D11SwapChain : public QRhiSwapChain + + QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override; + bool createOrResize() override; ++ bool createOrResizeWin7(); + + void releaseBuffers(); + bool newColorBuffer(const QSize &size, DXGI_FORMAT format, DXGI_SAMPLE_DESC sampleDesc, +diff --git a/src/gui/rhi/qrhid3d12.cpp b/src/gui/rhi/qrhid3d12.cpp +index 0662c53ed65..1039914d57f 100644 +--- a/src/gui/rhi/qrhid3d12.cpp ++++ b/src/gui/rhi/qrhid3d12.cpp +@@ -203,19 +203,35 @@ static inline QD3D12RenderTargetData *rtData(QRhiRenderTarget *rt) + + bool QRhiD3D12::create(QRhi::Flags flags) + { ++ typedef HRESULT(WINAPI* CreateDXGIFactory2Func) (UINT flags, REFIID riid, void** factory); ++ typedef HRESULT(WINAPI* D3D12CreateDeviceFunc) (IUnknown *, D3D_FEATURE_LEVEL, REFIID, void **); ++ typedef HRESULT(WINAPI* D3D12GetDebugInterfaceFunc) (REFIID, void **); ++ ++ static CreateDXGIFactory2Func myCreateDXGIFactory2 = ++ (CreateDXGIFactory2Func)::GetProcAddress(::GetModuleHandle(L"dxgi"), "CreateDXGIFactory2"); ++ ++ static D3D12CreateDeviceFunc myD3D12CreateDevice = ++ (D3D12CreateDeviceFunc)::GetProcAddress(::GetModuleHandle(L"D3d12"), "D3D12CreateDevice"); ++ ++ static D3D12GetDebugInterfaceFunc myD3D12GetDebugInterface = ++ (D3D12GetDebugInterfaceFunc)::GetProcAddress(::GetModuleHandle(L"D3d12"), "D3D12GetDebugInterface"); ++ ++ if (!myCreateDXGIFactory2 || !myD3D12CreateDevice || !myD3D12GetDebugInterface) ++ return false; ++ + rhiFlags = flags; + + UINT factoryFlags = 0; + if (debugLayer) + factoryFlags |= DXGI_CREATE_FACTORY_DEBUG; +- HRESULT hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2), reinterpret_cast(&dxgiFactory)); ++ HRESULT hr = myCreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2), reinterpret_cast(&dxgiFactory)); + if (FAILED(hr)) { + // retry without debug, if it was requested (to match D3D11 backend behavior) + if (debugLayer) { + qCDebug(QRHI_LOG_INFO, "Debug layer was requested but is not available. " + "Attempting to create DXGIFactory2 without it."); + factoryFlags &= ~DXGI_CREATE_FACTORY_DEBUG; +- hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2), reinterpret_cast(&dxgiFactory)); ++ hr = myCreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2), reinterpret_cast(&dxgiFactory)); + } + if (SUCCEEDED(hr)) { + debugLayer = false; +@@ -242,7 +258,7 @@ bool QRhiD3D12::create(QRhi::Flags flags) + + if (debugLayer) { + ID3D12Debug1 *debug = nullptr; +- if (SUCCEEDED(D3D12GetDebugInterface(__uuidof(ID3D12Debug1), reinterpret_cast(&debug)))) { ++ if (SUCCEEDED(myD3D12GetDebugInterface(__uuidof(ID3D12Debug1), reinterpret_cast(&debug)))) { + qCDebug(QRHI_LOG_INFO, "Enabling D3D12 debug layer"); + debug->EnableDebugLayer(); + debug->Release(); +@@ -310,7 +326,7 @@ bool QRhiD3D12::create(QRhi::Flags flags) + if (minimumFeatureLevel == 0) + minimumFeatureLevel = MIN_FEATURE_LEVEL; + +- hr = D3D12CreateDevice(activeAdapter, ++ hr = myD3D12CreateDevice(activeAdapter, + minimumFeatureLevel, + __uuidof(ID3D12Device2), + reinterpret_cast(&dev)); +@@ -2762,6 +2778,9 @@ QD3D12Descriptor QD3D12SamplerManager::getShaderVisibleDescriptor(const D3D12_SA + return descriptor; + } + ++typedef HRESULT(WINAPI* D3D12SerializeVersionedRootSignatureFunc) (const D3D12_VERSIONED_ROOT_SIGNATURE_DESC *, ID3DBlob **, ID3DBlob **); ++D3D12SerializeVersionedRootSignatureFunc myD3D12SerializeVersionedRootSignature = nullptr; ++ + bool QD3D12MipmapGenerator::create(QRhiD3D12 *rhiD) + { + this->rhiD = rhiD; +@@ -2807,8 +2826,15 @@ bool QD3D12MipmapGenerator::create(QRhiD3D12 *rhiD) + rsDesc.Desc_1_1.NumStaticSamplers = 1; + rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc; + ++ if (!myD3D12SerializeVersionedRootSignature) ++ myD3D12SerializeVersionedRootSignature = ++ (D3D12SerializeVersionedRootSignatureFunc)::GetProcAddress(::GetModuleHandle(L"D3d12"), "D3D12SerializeVersionedRootSignature"); ++ ++ if (!myD3D12SerializeVersionedRootSignature) ++ return false; ++ + ID3DBlob *signature = nullptr; +- HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature, nullptr); ++ HRESULT hr = myD3D12SerializeVersionedRootSignature(&rsDesc, &signature, nullptr); + if (FAILED(hr)) { + qWarning("Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr))); + return false; +@@ -4219,7 +4245,7 @@ bool QD3D12Texture::prepareCreate(QSize *adjustedSize) + else + srvFormat = toD3DTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags()); + } +- ++ + mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1); + sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat); + if (sampleDesc.Count > 1) { +@@ -5001,6 +5027,9 @@ QD3D12ObjectHandle QD3D12ShaderResourceBindings::createRootSignature(const QD3D1 + { + QRHI_RES_RHI(QRhiD3D12); + ++ if (!myD3D12SerializeVersionedRootSignature) ++ return {}; ++ + // It's not just that the root signature has to be tied to the pipeline + // (cannot just freely create it like e.g. with Vulkan where one just + // creates a descriptor layout 1:1 with the QRhiShaderResourceBindings' +@@ -5085,7 +5114,7 @@ QD3D12ObjectHandle QD3D12ShaderResourceBindings::createRootSignature(const QD3D1 + rsDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAGS(rsFlags); + + ID3DBlob *signature = nullptr; +- HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature, nullptr); ++ HRESULT hr = myD3D12SerializeVersionedRootSignature(&rsDesc, &signature, nullptr); + if (FAILED(hr)) { + qWarning("Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr))); + return {}; +diff --git a/src/gui/text/windows/qwindowsfontdatabasebase.cpp b/src/gui/text/windows/qwindowsfontdatabasebase.cpp +index 84e619b0d93..e751d4b1fb7 100644 +--- a/src/gui/text/windows/qwindowsfontdatabasebase.cpp ++++ b/src/gui/text/windows/qwindowsfontdatabasebase.cpp +@@ -715,7 +715,16 @@ QFont QWindowsFontDatabaseBase::systemDefaultFont() + // Qt 6: Obtain default GUI font (typically "Segoe UI, 9pt", see QTBUG-58610) + NONCLIENTMETRICS ncm = {}; + ncm.cbSize = sizeof(ncm); +- SystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0, defaultVerticalDPI()); ++ ++ typedef BOOL (WINAPI *SystemParametersInfoForDpiFunc) (UINT, UINT, PVOID, UINT, UINT); ++ static SystemParametersInfoForDpiFunc mySystemParametersInfoForDpi = ++ (SystemParametersInfoForDpiFunc)::GetProcAddress(::GetModuleHandle(L"user32"), "SystemParametersInfoForDpi"); ++ ++ if (mySystemParametersInfoForDpi) ++ mySystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0, defaultVerticalDPI()); ++ else ++ SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0); ++ + const QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont); + qCDebug(lcQpaFonts) << __FUNCTION__ << systemFont; + return systemFont; +diff --git a/src/network/kernel/qdnslookup_win.cpp b/src/network/kernel/qdnslookup_win.cpp +index 1b07776db9d..5410edab880 100644 +--- a/src/network/kernel/qdnslookup_win.cpp ++++ b/src/network/kernel/qdnslookup_win.cpp +@@ -5,11 +5,9 @@ + #include + #include "qdnslookup_p.h" + +-#include ++#include + #include + #include +-#include +-#include + + #include + #include +@@ -65,100 +63,103 @@ DNS_STATUS WINAPI DnsQueryEx(PDNS_QUERY_REQUEST pQueryRequest, + + QT_BEGIN_NAMESPACE + +-static DNS_STATUS sendAlternate(QDnsLookupRunnable *self, QDnsLookupReply *reply, +- PDNS_QUERY_REQUEST request, PDNS_QUERY_RESULT results) +-{ +- // WinDNS wants MTU - IP Header - UDP header for some reason, in spite +- // of never needing that much +- QVarLengthArray query(1472); +- +- auto dnsBuffer = new (query.data()) DNS_MESSAGE_BUFFER; +- DWORD dnsBufferSize = query.size(); +- WORD xid = 0; +- bool recursionDesired = true; +- +- SetLastError(ERROR_SUCCESS); +- +- // MinGW winheaders incorrectly declare the third parameter as LPWSTR +- if (!DnsWriteQuestionToBuffer_W(dnsBuffer, &dnsBufferSize, +- const_cast(request->QueryName), request->QueryType, +- xid, recursionDesired)) { +- // let's try reallocating +- query.resize(dnsBufferSize); +- if (!DnsWriteQuestionToBuffer_W(dnsBuffer, &dnsBufferSize, +- const_cast(request->QueryName), request->QueryType, +- xid, recursionDesired)) { +- return GetLastError(); +- } +- } +- +- // set AD bit: we want to trust this server +- dnsBuffer->MessageHead.AuthenticatedData = true; +- +- QDnsLookupRunnable::ReplyBuffer replyBuffer; +- if (!self->sendDnsOverTls(reply, { query.data(), qsizetype(dnsBufferSize) }, replyBuffer)) +- return DNS_STATUS(-1); // error set in reply +- +- // interpret the RCODE in the reply +- auto response = reinterpret_cast(replyBuffer.data()); +- DNS_HEADER *header = &response->MessageHead; +- if (!header->IsResponse) +- return DNS_ERROR_BAD_PACKET; // not a reply +- +- // Convert the byte order for the 16-bit quantities in the header, so +- // DnsExtractRecordsFromMessage can parse the contents. +- //header->Xid = qFromBigEndian(header->Xid); +- header->QuestionCount = qFromBigEndian(header->QuestionCount); +- header->AnswerCount = qFromBigEndian(header->AnswerCount); +- header->NameServerCount = qFromBigEndian(header->NameServerCount); +- header->AdditionalCount = qFromBigEndian(header->AdditionalCount); +- +- results->QueryOptions = request->QueryOptions; +- return DnsExtractRecordsFromMessage_W(response, replyBuffer.size(), &results->pQueryRecords); +-} +- + void QDnsLookupRunnable::query(QDnsLookupReply *reply) + { +- // Perform DNS query. +- alignas(DNS_ADDR_ARRAY) uchar dnsAddresses[sizeof(DNS_ADDR_ARRAY) + sizeof(DNS_ADDR)]; +- DNS_QUERY_REQUEST request = {}; +- request.Version = 1; +- request.QueryName = reinterpret_cast(requestName.constData()); +- request.QueryType = requestType; +- request.QueryOptions = DNS_QUERY_STANDARD | DNS_QUERY_TREAT_AS_FQDN; ++ typedef BOOL (WINAPI *DnsQueryExFunc) (PDNS_QUERY_REQUEST, PDNS_QUERY_RESULT, PDNS_QUERY_CANCEL); ++ static DnsQueryExFunc myDnsQueryEx = ++ (DnsQueryExFunc)::GetProcAddress(::GetModuleHandle(L"Dnsapi"), "DnsQueryEx"); ++ ++ PDNS_RECORD ptrStart = nullptr; ++ ++ if (myDnsQueryEx) ++ { ++ // Perform DNS query. ++ alignas(DNS_ADDR_ARRAY) uchar dnsAddresses[sizeof(DNS_ADDR_ARRAY) + sizeof(DNS_ADDR)]; ++ DNS_QUERY_REQUEST request = {}; ++ request.Version = 1; ++ request.QueryName = reinterpret_cast(requestName.constData()); ++ request.QueryType = requestType; ++ request.QueryOptions = DNS_QUERY_STANDARD | DNS_QUERY_TREAT_AS_FQDN; ++ ++ if (!nameserver.isNull()) { ++ memset(dnsAddresses, 0, sizeof(dnsAddresses)); ++ request.pDnsServerList = new (dnsAddresses) DNS_ADDR_ARRAY; ++ auto addr = new (request.pDnsServerList->AddrArray) DNS_ADDR[1]; ++ auto sa = new (addr[0].MaxSa) sockaddr; ++ request.pDnsServerList->MaxCount = sizeof(dnsAddresses); ++ request.pDnsServerList->AddrCount = 1; ++ // ### setting port 53 seems to cause some systems to fail ++ setSockaddr(sa, nameserver, port == DnsPort ? 0 : port); ++ request.pDnsServerList->Family = sa->sa_family; ++ } + +- if (protocol == QDnsLookup::Standard && !nameserver.isNull()) { +- memset(dnsAddresses, 0, sizeof(dnsAddresses)); +- request.pDnsServerList = new (dnsAddresses) DNS_ADDR_ARRAY; +- auto addr = new (request.pDnsServerList->AddrArray) DNS_ADDR[1]; +- auto sa = new (addr[0].MaxSa) sockaddr; +- request.pDnsServerList->MaxCount = sizeof(dnsAddresses); +- request.pDnsServerList->AddrCount = 1; +- // ### setting port 53 seems to cause some systems to fail +- setSockaddr(sa, nameserver, port == DnsPort ? 0 : port); +- request.pDnsServerList->Family = sa->sa_family; ++ DNS_QUERY_RESULT results = {}; ++ results.Version = 1; ++ const DNS_STATUS status = myDnsQueryEx(&request, &results, nullptr); ++ if (status >= DNS_ERROR_RCODE_FORMAT_ERROR && status <= DNS_ERROR_RCODE_LAST) ++ return reply->makeDnsRcodeError(status - DNS_ERROR_RCODE_FORMAT_ERROR + 1); ++ else if (status == ERROR_TIMEOUT) ++ return reply->makeTimeoutError(); ++ else if (status != ERROR_SUCCESS) ++ return reply->makeResolverSystemError(status); ++ ++ ptrStart = results.pQueryRecords; + } ++ else ++ { ++ // Perform DNS query. ++ PDNS_RECORD dns_records = 0; ++ QByteArray requestNameUTF8 = requestName.toUtf8(); ++ const QString requestNameUtf16 = QString::fromUtf8(requestNameUTF8.data(), requestNameUTF8.size()); ++ IP4_ARRAY srvList; ++ memset(&srvList, 0, sizeof(IP4_ARRAY)); ++ if (!nameserver.isNull()) { ++ if (nameserver.protocol() == QAbstractSocket::IPv4Protocol) { ++ // The below code is referenced from: http://support.microsoft.com/kb/831226 ++ srvList.AddrCount = 1; ++ srvList.AddrArray[0] = htonl(nameserver.toIPv4Address()); ++ } else if (nameserver.protocol() == QAbstractSocket::IPv6Protocol) { ++ // For supporting IPv6 nameserver addresses, we'll need to switch ++ // from DnsQuey() to DnsQueryEx() as it supports passing an IPv6 ++ // address in the nameserver list ++ qWarning("%s", "IPv6 addresses for nameservers are currently not supported"); ++ reply->error = QDnsLookup::ResolverError; ++ reply->errorString = tr("IPv6 addresses for nameservers are currently not supported"); ++ return; ++ } ++ } ++ const DNS_STATUS status = DnsQuery_W(reinterpret_cast(requestNameUtf16.utf16()), requestType, DNS_QUERY_STANDARD, &srvList, &dns_records, NULL); ++ switch (status) { ++ case ERROR_SUCCESS: ++ break; ++ case DNS_ERROR_RCODE_FORMAT_ERROR: ++ reply->error = QDnsLookup::InvalidRequestError; ++ reply->errorString = tr("Server could not process query"); ++ return; ++ case DNS_ERROR_RCODE_SERVER_FAILURE: ++ case DNS_ERROR_RCODE_NOT_IMPLEMENTED: ++ reply->error = QDnsLookup::ServerFailureError; ++ reply->errorString = tr("Server failure"); ++ return; ++ case DNS_ERROR_RCODE_NAME_ERROR: ++ reply->error = QDnsLookup::NotFoundError; ++ reply->errorString = tr("Non existent domain"); ++ return; ++ case DNS_ERROR_RCODE_REFUSED: ++ reply->error = QDnsLookup::ServerRefusedError; ++ reply->errorString = tr("Server refused to answer"); ++ return; ++ default: ++ reply->error = QDnsLookup::InvalidReplyError; ++ reply->errorString = QSystemError(status, QSystemError::NativeError).toString(); ++ return; ++ } + +- DNS_QUERY_RESULT results = {}; +- results.Version = 1; +- DNS_STATUS status = ERROR_INVALID_PARAMETER; +- switch (protocol) { +- case QDnsLookup::Standard: +- status = DnsQueryEx(&request, &results, nullptr); +- break; +- case QDnsLookup::DnsOverTls: +- status = sendAlternate(this, reply, &request, &results); +- break; ++ ptrStart = dns_records; + } + +- if (status == DNS_STATUS(-1)) +- return; // error already set in reply +- if (status >= DNS_ERROR_RCODE_FORMAT_ERROR && status <= DNS_ERROR_RCODE_LAST) +- return reply->makeDnsRcodeError(status - DNS_ERROR_RCODE_FORMAT_ERROR + 1); +- else if (status == ERROR_TIMEOUT) +- return reply->makeTimeoutError(); +- else if (status != ERROR_SUCCESS) +- return reply->makeResolverSystemError(status); ++ if (!ptrStart) ++ return; + + QStringView lastEncodedName; + QString cachedDecodedName; +@@ -170,9 +171,9 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply) + auto extractMaybeCachedHost = [&](QStringView name) -> const QString & { + return lastEncodedName == name ? cachedDecodedName : extractAndCacheHost(name); + }; +- ++ + // Extract results. +- for (PDNS_RECORD ptr = results.pQueryRecords; ptr != NULL; ptr = ptr->pNext) { ++ for (PDNS_RECORD ptr = ptrStart; ptr != NULL; ptr = ptr->pNext) { + // warning: always assign name to the record before calling extractXxxHost() again + const QString &name = extractMaybeCachedHost(ptr->pName); + if (ptr->wType == QDnsLookup::A) { +@@ -224,25 +225,6 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply) + record.d->timeToLive = ptr->dwTtl; + record.d->weight = ptr->Data.Srv.wWeight; + reply->serviceRecords.append(record); +- } else if (ptr->wType == QDnsLookup::TLSA) { +- // Note: untested, because the DNS_RECORD reply appears to contain +- // no records relating to TLSA. Maybe WinDNS filters them out of +- // zones without DNSSEC. +- QDnsTlsAssociationRecord record; +- record.d->name = name; +- record.d->timeToLive = ptr->dwTtl; +- +- const auto &tlsa = ptr->Data.Tlsa; +- const quint8 usage = tlsa.bCertUsage; +- const quint8 selector = tlsa.bSelector; +- const quint8 matchType = tlsa.bMatchingType; +- +- record.d->usage = QDnsTlsAssociationRecord::CertificateUsage(usage); +- record.d->selector = QDnsTlsAssociationRecord::Selector(selector); +- record.d->matchType = QDnsTlsAssociationRecord::MatchingType(matchType); +- record.d->value.assign(tlsa.bCertificateAssociationData, +- tlsa.bCertificateAssociationData + tlsa.bCertificateAssociationDataLength); +- reply->tlsAssociationRecords.append(std::move(record)); + } else if (ptr->wType == QDnsLookup::TXT) { + QDnsTextRecord record; + record.d->name = name; +@@ -254,7 +236,7 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply) + } + } + +- DnsRecordListFree(results.pQueryRecords, DnsFreeRecordList); ++ DnsRecordListFree(ptrStart, DnsFreeRecordList); + } + + QT_END_NAMESPACE +diff --git a/src/plugins/platforms/windows/qwin10helpers.cpp b/src/plugins/platforms/windows/qwin10helpers.cpp +index 026e81cb0c7..3bbc974b744 100644 +--- a/src/plugins/platforms/windows/qwin10helpers.cpp ++++ b/src/plugins/platforms/windows/qwin10helpers.cpp +@@ -58,43 +58,73 @@ public: + } // namespace ABI + #endif // HAS_UI_VIEW_SETTINGS + ++// based on SDL approach ++// see SDL_windows_gaming_input.c, SDL_windows.c ++ ++void * WIN_LoadComBaseFunction(const char *name) ++{ ++ static bool s_bLoaded = false; ++ static HMODULE s_hComBase = NULL; ++ ++ if (!s_bLoaded) { ++ s_hComBase = ::LoadLibraryEx(L"combase.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); ++ s_bLoaded = true; ++ } ++ if (s_hComBase) { ++ return (void *) ::GetProcAddress(s_hComBase, name); ++ } else { ++ return NULL; ++ } ++} ++ + QT_BEGIN_NAMESPACE + + // Return tablet mode, note: Does not work for GetDesktopWindow(). + bool qt_windowsIsTabletMode(HWND hwnd) + { +- bool result = false; +- +- const wchar_t uiViewSettingsId[] = L"Windows.UI.ViewManagement.UIViewSettings"; +- HSTRING_HEADER uiViewSettingsIdRefHeader; +- HSTRING uiViewSettingsIdHs = nullptr; +- const auto uiViewSettingsIdLen = UINT32(sizeof(uiViewSettingsId) / sizeof(uiViewSettingsId[0]) - 1); +- if (FAILED(WindowsCreateStringReference(uiViewSettingsId, uiViewSettingsIdLen, &uiViewSettingsIdRefHeader, &uiViewSettingsIdHs))) +- return false; +- +- IUIViewSettingsInterop *uiViewSettingsInterop = nullptr; +- // __uuidof(IUIViewSettingsInterop); +- const GUID uiViewSettingsInteropRefId = {0x3694dbf9, 0x8f68, 0x44be,{0x8f, 0xf5, 0x19, 0x5c, 0x98, 0xed, 0xe8, 0xa6}}; +- +- HRESULT hr = RoGetActivationFactory(uiViewSettingsIdHs, uiViewSettingsInteropRefId, +- reinterpret_cast(&uiViewSettingsInterop)); +- if (FAILED(hr)) +- return false; +- +- // __uuidof(ABI::Windows::UI::ViewManagement::IUIViewSettings); +- const GUID uiViewSettingsRefId = {0xc63657f6, 0x8850, 0x470d,{0x88, 0xf8, 0x45, 0x5e, 0x16, 0xea, 0x2c, 0x26}}; +- ABI::Windows::UI::ViewManagement::IUIViewSettings *viewSettings = nullptr; +- hr = uiViewSettingsInterop->GetForWindow(hwnd, uiViewSettingsRefId, +- reinterpret_cast(&viewSettings)); +- if (SUCCEEDED(hr)) { +- ABI::Windows::UI::ViewManagement::UserInteractionMode currentMode; +- hr = viewSettings->get_UserInteractionMode(¤tMode); +- if (SUCCEEDED(hr)) +- result = currentMode == 1; // Touch, 1 +- viewSettings->Release(); ++ typedef HRESULT (WINAPI *WindowsCreateStringReference_t)(PCWSTR sourceString, UINT32 length, HSTRING_HEADER *hstringHeader, HSTRING* string); ++ typedef HRESULT (WINAPI *RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void** factory); ++ ++ WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)WIN_LoadComBaseFunction("WindowsCreateStringReference"); ++ RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)WIN_LoadComBaseFunction("RoGetActivationFactory"); ++ ++ if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) ++ { ++ bool result = false; ++ ++ const wchar_t uiViewSettingsId[] = L"Windows.UI.ViewManagement.UIViewSettings"; ++ HSTRING_HEADER uiViewSettingsIdRefHeader; ++ HSTRING uiViewSettingsIdHs = nullptr; ++ const auto uiViewSettingsIdLen = UINT32(sizeof(uiViewSettingsId) / sizeof(uiViewSettingsId[0]) - 1); ++ if (FAILED(WindowsCreateStringReferenceFunc(uiViewSettingsId, uiViewSettingsIdLen, &uiViewSettingsIdRefHeader, &uiViewSettingsIdHs))) ++ return false; ++ ++ IUIViewSettingsInterop *uiViewSettingsInterop = nullptr; ++ // __uuidof(IUIViewSettingsInterop); ++ const GUID uiViewSettingsInteropRefId = {0x3694dbf9, 0x8f68, 0x44be,{0x8f, 0xf5, 0x19, 0x5c, 0x98, 0xed, 0xe8, 0xa6}}; ++ ++ HRESULT hr = RoGetActivationFactoryFunc(uiViewSettingsIdHs, uiViewSettingsInteropRefId, ++ reinterpret_cast(&uiViewSettingsInterop)); ++ if (FAILED(hr)) ++ return false; ++ ++ // __uuidof(ABI::Windows::UI::ViewManagement::IUIViewSettings); ++ const GUID uiViewSettingsRefId = {0xc63657f6, 0x8850, 0x470d,{0x88, 0xf8, 0x45, 0x5e, 0x16, 0xea, 0x2c, 0x26}}; ++ ABI::Windows::UI::ViewManagement::IUIViewSettings *viewSettings = nullptr; ++ hr = uiViewSettingsInterop->GetForWindow(hwnd, uiViewSettingsRefId, ++ reinterpret_cast(&viewSettings)); ++ if (SUCCEEDED(hr)) { ++ ABI::Windows::UI::ViewManagement::UserInteractionMode currentMode; ++ hr = viewSettings->get_UserInteractionMode(¤tMode); ++ if (SUCCEEDED(hr)) ++ result = currentMode == 1; // Touch, 1 ++ viewSettings->Release(); ++ } ++ uiViewSettingsInterop->Release(); ++ return result; + } +- uiViewSettingsInterop->Release(); +- return result; ++ ++ return false; + } + +-QT_END_NAMESPACE ++QT_END_NAMESPACE +\ No newline at end of file +diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp +index 88e9da5557c..7df58793707 100644 +--- a/src/plugins/platforms/windows/qwindowscontext.cpp ++++ b/src/plugins/platforms/windows/qwindowscontext.cpp +@@ -43,6 +43,7 @@ + #include + #include + #include ++#include + #include + #if QT_CONFIG(cpp_winrt) + # include +@@ -59,6 +60,8 @@ + #include + #include + ++#include "vxkex.h" ++ + QT_BEGIN_NAMESPACE + + using namespace Qt::StringLiterals; +@@ -120,6 +123,77 @@ static inline bool sessionManagerInteractionBlocked() + static inline bool sessionManagerInteractionBlocked() { return false; } + #endif + ++/*! ++ \class QWindowsUser32DLL ++ \brief Struct that contains dynamically resolved symbols of User32.dll. ++ The stub libraries shipped with the MinGW compiler miss some of the ++ functions. They need to be retrieved dynamically. ++ In addition, touch-related functions are available only from Windows onwards. ++ These need to resolved dynamically for Q_CC_MSVC as well. ++ \sa QWindowsShell32DLL ++ \internal ++*/ ++ ++void QWindowsUser32DLL::init() ++{ ++ QSystemLibrary library(QStringLiteral("user32")); ++ setProcessDPIAware = (SetProcessDPIAware)library.resolve("SetProcessDPIAware"); ++ setProcessDpiAwarenessContext = (SetProcessDpiAwarenessContext)library.resolve("SetProcessDpiAwarenessContext"); ++ getThreadDpiAwarenessContext = (GetThreadDpiAwarenessContext)library.resolve("GetThreadDpiAwarenessContext"); ++ isValidDpiAwarenessContext = (IsValidDpiAwarenessContext)library.resolve("IsValidDpiAwarenessContext"); ++ areDpiAwarenessContextsEqual = (AreDpiAwarenessContextsEqual)library.resolve("AreDpiAwarenessContextsEqual"); ++ ++ addClipboardFormatListener = (AddClipboardFormatListener)library.resolve("AddClipboardFormatListener"); ++ removeClipboardFormatListener = (RemoveClipboardFormatListener)library.resolve("RemoveClipboardFormatListener"); ++ ++ getDisplayAutoRotationPreferences = (GetDisplayAutoRotationPreferences)library.resolve("GetDisplayAutoRotationPreferences"); ++ setDisplayAutoRotationPreferences = (SetDisplayAutoRotationPreferences)library.resolve("SetDisplayAutoRotationPreferences"); ++ ++ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8) { ++ enableMouseInPointer = (EnableMouseInPointer)library.resolve("EnableMouseInPointer"); ++ getPointerType = (GetPointerType)library.resolve("GetPointerType"); ++ getPointerInfo = (GetPointerInfo)library.resolve("GetPointerInfo"); ++ getPointerDeviceRects = (GetPointerDeviceRects)library.resolve("GetPointerDeviceRects"); ++ getPointerTouchInfo = (GetPointerTouchInfo)library.resolve("GetPointerTouchInfo"); ++ getPointerFrameTouchInfo = (GetPointerFrameTouchInfo)library.resolve("GetPointerFrameTouchInfo"); ++ getPointerFrameTouchInfoHistory = (GetPointerFrameTouchInfoHistory)library.resolve("GetPointerFrameTouchInfoHistory"); ++ getPointerPenInfo = (GetPointerPenInfo)library.resolve("GetPointerPenInfo"); ++ getPointerPenInfoHistory = (GetPointerPenInfoHistory)library.resolve("GetPointerPenInfoHistory"); ++ skipPointerFrameMessages = (SkipPointerFrameMessages)library.resolve("SkipPointerFrameMessages"); ++ } ++ ++ if (QOperatingSystemVersion::current() ++ >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 14393)) { ++ adjustWindowRectExForDpi = (AdjustWindowRectExForDpi)library.resolve("AdjustWindowRectExForDpi"); ++ enableNonClientDpiScaling = (EnableNonClientDpiScaling)library.resolve("EnableNonClientDpiScaling"); ++ getWindowDpiAwarenessContext = (GetWindowDpiAwarenessContext)library.resolve("GetWindowDpiAwarenessContext"); ++ getAwarenessFromDpiAwarenessContext = (GetAwarenessFromDpiAwarenessContext)library.resolve("GetAwarenessFromDpiAwarenessContext"); ++ systemParametersInfoForDpi = (SystemParametersInfoForDpi)library.resolve("SystemParametersInfoForDpi"); ++ getDpiForWindow = (GetDpiForWindow)library.resolve("GetDpiForWindow"); ++ getSystemMetricsForDpi = (GetSystemMetricsForDpi)library.resolve("GetSystemMetricsForDpi"); ++ } ++} ++ ++bool QWindowsUser32DLL::supportsPointerApi() ++{ ++ return enableMouseInPointer && getPointerType && getPointerInfo && getPointerDeviceRects ++ && getPointerTouchInfo && getPointerFrameTouchInfo && getPointerFrameTouchInfoHistory ++ && getPointerPenInfo && getPointerPenInfoHistory && skipPointerFrameMessages; ++} ++ ++void QWindowsShcoreDLL::init() ++{ ++ if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8_1) ++ return; ++ QSystemLibrary library(QStringLiteral("SHCore")); ++ getProcessDpiAwareness = (GetProcessDpiAwareness)library.resolve("GetProcessDpiAwareness"); ++ setProcessDpiAwareness = (SetProcessDpiAwareness)library.resolve("SetProcessDpiAwareness"); ++ getDpiForMonitor = (GetDpiForMonitor)library.resolve("GetDpiForMonitor"); ++} ++ ++QWindowsUser32DLL QWindowsContext::user32dll; ++QWindowsShcoreDLL QWindowsContext::shcoredll; ++ + QWindowsContext *QWindowsContext::m_instance = nullptr; + + /*! +@@ -160,6 +234,9 @@ bool QWindowsContextPrivate::m_v2DpiAware = false; + QWindowsContextPrivate::QWindowsContextPrivate() + : m_oleInitializeResult(OleInitialize(nullptr)) + { ++ QWindowsContext::user32dll.init(); ++ QWindowsContext::shcoredll.init(); ++ + if (m_pointerHandler.touchDevice()) + m_systemInfo |= QWindowsContext::SI_SupportsTouch; + m_displayContext = GetDC(nullptr); +@@ -338,19 +415,39 @@ void QWindowsContext::setDetectAltGrModifier(bool a) + [[nodiscard]] static inline QtWindows::DpiAwareness + dpiAwarenessContextToQtDpiAwareness(DPI_AWARENESS_CONTEXT context) + { +- // IsValidDpiAwarenessContext() will handle the NULL pointer case. +- if (!IsValidDpiAwarenessContext(context)) +- return QtWindows::DpiAwareness::Invalid; +- if (AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED)) +- return QtWindows::DpiAwareness::Unaware_GdiScaled; +- if (AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) +- return QtWindows::DpiAwareness::PerMonitorVersion2; +- if (AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE)) +- return QtWindows::DpiAwareness::PerMonitor; +- if (AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_SYSTEM_AWARE)) +- return QtWindows::DpiAwareness::System; +- if (AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE)) +- return QtWindows::DpiAwareness::Unaware; ++ if (QWindowsContext::user32dll.isValidDpiAwarenessContext && QWindowsContext::user32dll.areDpiAwarenessContextsEqual) ++ { ++ // IsValidDpiAwarenessContext() will handle the NULL pointer case. ++ if (!QWindowsContext::user32dll.isValidDpiAwarenessContext(context)) ++ return QtWindows::DpiAwareness::Invalid; ++ if (QWindowsContext::user32dll.areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED)) ++ return QtWindows::DpiAwareness::Unaware_GdiScaled; ++ if (QWindowsContext::user32dll.areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) ++ return QtWindows::DpiAwareness::PerMonitorVersion2; ++ if (QWindowsContext::user32dll.areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE)) ++ return QtWindows::DpiAwareness::PerMonitor; ++ if (QWindowsContext::user32dll.areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_SYSTEM_AWARE)) ++ return QtWindows::DpiAwareness::System; ++ if (QWindowsContext::user32dll.areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE)) ++ return QtWindows::DpiAwareness::Unaware; ++ } ++ else ++ { ++ // IsValidDpiAwarenessContext() will handle the NULL pointer case. ++ if (!vxkex::IsValidDpiAwarenessContext(context)) ++ return QtWindows::DpiAwareness::Invalid; ++ if (vxkex::AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED)) ++ return QtWindows::DpiAwareness::Unaware_GdiScaled; ++ if (vxkex::AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) ++ return QtWindows::DpiAwareness::PerMonitorVersion2; ++ if (vxkex::AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE)) ++ return QtWindows::DpiAwareness::PerMonitor; ++ if (vxkex::AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_SYSTEM_AWARE)) ++ return QtWindows::DpiAwareness::System; ++ if (vxkex::AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE)) ++ return QtWindows::DpiAwareness::Unaware; ++ } ++ + return QtWindows::DpiAwareness::Invalid; + } + +@@ -358,7 +455,11 @@ QtWindows::DpiAwareness QWindowsContext::windowDpiAwareness(HWND hwnd) + { + if (!hwnd) + return QtWindows::DpiAwareness::Invalid; +- const auto context = GetWindowDpiAwarenessContext(hwnd); ++ ++ const auto context = QWindowsContext::user32dll.getWindowDpiAwarenessContext ? ++ QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd) : ++ vxkex::GetWindowDpiAwarenessContext(hwnd); ++ + return dpiAwarenessContextToQtDpiAwareness(context); + } + +@@ -371,7 +472,9 @@ QtWindows::DpiAwareness QWindowsContext::processDpiAwareness() + // return the default DPI_AWARENESS_CONTEXT for the process if + // SetThreadDpiAwarenessContext() was never called. So we can use + // it as an equivalent. +- const auto context = GetThreadDpiAwarenessContext(); ++ const DPI_AWARENESS_CONTEXT context = QWindowsContext::user32dll.getThreadDpiAwarenessContext ? ++ QWindowsContext::user32dll.getThreadDpiAwarenessContext() : ++ vxkex::GetThreadDpiAwarenessContext(); + return dpiAwarenessContextToQtDpiAwareness(context); + } + +@@ -431,11 +534,21 @@ bool QWindowsContext::setProcessDpiAwareness(QtWindows::DpiAwareness dpiAwarenes + if (processDpiAwareness() == dpiAwareness) + return true; + const auto context = qtDpiAwarenessToDpiAwarenessContext(dpiAwareness); +- if (!IsValidDpiAwarenessContext(context)) { ++ ++ BOOL bResultIsValid = QWindowsContext::user32dll.isValidDpiAwarenessContext ? ++ QWindowsContext::user32dll.isValidDpiAwarenessContext(context) : ++ vxkex::IsValidDpiAwarenessContext(context); ++ ++ if (!bResultIsValid) { + qCWarning(lcQpaWindow) << dpiAwareness << "is not supported by current system."; + return false; + } +- if (!SetProcessDpiAwarenessContext(context)) { ++ ++ BOOL bResultSet = QWindowsContext::user32dll.setProcessDpiAwarenessContext ? ++ QWindowsContext::user32dll.setProcessDpiAwarenessContext(context) : ++ vxkex::SetProcessDpiAwarenessContext(context); ++ ++ if (!bResultSet) { + qCWarning(lcQpaWindow).noquote().nospace() + << "SetProcessDpiAwarenessContext() failed: " + << QSystemError::windowsString() +@@ -868,9 +981,9 @@ void QWindowsContext::forceNcCalcSize(HWND hwnd) + bool QWindowsContext::systemParametersInfo(unsigned action, unsigned param, void *out, + unsigned dpi) + { +- const BOOL result = dpi != 0 +- ? SystemParametersInfoForDpi(action, param, out, 0, dpi) +- : SystemParametersInfo(action, param, out, 0); ++ const BOOL result = (QWindowsContext::user32dll.systemParametersInfoForDpi != nullptr && dpi != 0) ++ ? QWindowsContext::user32dll.systemParametersInfoForDpi(action, param, out, 0, dpi) ++ : vxkex::SystemParametersInfoForDpi(action, param, out, 0, dpi); + return result == TRUE; + } + +@@ -957,7 +1070,10 @@ static bool enableNonClientDpiScaling(HWND hwnd) + { + bool result = false; + if (QWindowsContext::windowDpiAwareness(hwnd) == QtWindows::DpiAwareness::PerMonitor) { +- result = EnableNonClientDpiScaling(hwnd) != FALSE; ++ result = QWindowsContext::user32dll.enableNonClientDpiScaling ? ++ (QWindowsContext::user32dll.enableNonClientDpiScaling(hwnd) != FALSE) : ++ (vxkex::EnableNonClientDpiScaling(hwnd) != FALSE); ++ + if (!result) { + const DWORD errorCode = GetLastError(); + qErrnoWarning(int(errorCode), "EnableNonClientDpiScaling() failed for HWND %p (%lu)", +diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h +index 4e9be1af967..357f7839353 100644 +--- a/src/plugins/platforms/windows/qwindowscontext.h ++++ b/src/plugins/platforms/windows/qwindowscontext.h +@@ -14,6 +14,7 @@ + #define STRICT_TYPED_ITEMIDS + #include + #include ++#include + + QT_BEGIN_NAMESPACE + +@@ -44,6 +45,95 @@ struct QWindowsContextPrivate; + class QPoint; + class QKeyEvent; + class QPointingDevice; ++ ++struct QWindowsUser32DLL ++{ ++ inline void init(); ++ inline bool supportsPointerApi(); ++ ++ typedef BOOL (WINAPI *EnableMouseInPointer)(BOOL); ++ typedef BOOL (WINAPI *GetPointerType)(UINT32, PVOID); ++ typedef BOOL (WINAPI *GetPointerInfo)(UINT32, PVOID); ++ typedef BOOL (WINAPI *GetPointerDeviceRects)(HANDLE, RECT *, RECT *); ++ typedef BOOL (WINAPI *GetPointerTouchInfo)(UINT32, PVOID); ++ typedef BOOL (WINAPI *GetPointerFrameTouchInfo)(UINT32, UINT32 *, PVOID); ++ typedef BOOL (WINAPI *GetPointerFrameTouchInfoHistory)(UINT32, UINT32 *, UINT32 *, PVOID); ++ typedef BOOL (WINAPI *GetPointerPenInfo)(UINT32, PVOID); ++ typedef BOOL (WINAPI *GetPointerPenInfoHistory)(UINT32, UINT32 *, PVOID); ++ typedef BOOL (WINAPI *SkipPointerFrameMessages)(UINT32); ++ typedef BOOL (WINAPI *SetProcessDPIAware)(); ++ typedef BOOL (WINAPI *SetProcessDpiAwarenessContext)(HANDLE); ++ typedef BOOL (WINAPI *AddClipboardFormatListener)(HWND); ++ typedef BOOL (WINAPI *RemoveClipboardFormatListener)(HWND); ++ typedef BOOL (WINAPI *GetDisplayAutoRotationPreferences)(DWORD *); ++ typedef BOOL (WINAPI *SetDisplayAutoRotationPreferences)(DWORD); ++ typedef BOOL (WINAPI *AdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT); ++ typedef BOOL (WINAPI *EnableNonClientDpiScaling)(HWND); ++ typedef DPI_AWARENESS_CONTEXT (WINAPI *GetWindowDpiAwarenessContext)(HWND); ++ typedef DPI_AWARENESS (WINAPI *GetAwarenessFromDpiAwarenessContext)(int); ++ typedef BOOL (WINAPI *SystemParametersInfoForDpi)(UINT, UINT, PVOID, UINT, UINT); ++ typedef int (WINAPI *GetDpiForWindow)(HWND); ++ typedef BOOL (WINAPI *GetSystemMetricsForDpi)(INT, UINT); ++ typedef BOOL (WINAPI *AreDpiAwarenessContextsEqual)(DPI_AWARENESS_CONTEXT, DPI_AWARENESS_CONTEXT); ++ typedef DPI_AWARENESS_CONTEXT (WINAPI *GetThreadDpiAwarenessContext)(); ++ typedef BOOL (WINAPI *IsValidDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); ++ ++ // Windows pointer functions (Windows 8 or later). ++ EnableMouseInPointer enableMouseInPointer = nullptr; ++ GetPointerType getPointerType = nullptr; ++ GetPointerInfo getPointerInfo = nullptr; ++ GetPointerDeviceRects getPointerDeviceRects = nullptr; ++ GetPointerTouchInfo getPointerTouchInfo = nullptr; ++ GetPointerFrameTouchInfo getPointerFrameTouchInfo = nullptr; ++ GetPointerFrameTouchInfoHistory getPointerFrameTouchInfoHistory = nullptr; ++ GetPointerPenInfo getPointerPenInfo = nullptr; ++ GetPointerPenInfoHistory getPointerPenInfoHistory = nullptr; ++ SkipPointerFrameMessages skipPointerFrameMessages = nullptr; ++ ++ // Windows Vista onwards ++ SetProcessDPIAware setProcessDPIAware = nullptr; ++ ++ // Windows 10 version 1607 onwards ++ GetDpiForWindow getDpiForWindow = nullptr; ++ GetThreadDpiAwarenessContext getThreadDpiAwarenessContext = nullptr; ++ IsValidDpiAwarenessContext isValidDpiAwarenessContext = nullptr; ++ ++ // Windows 10 version 1703 onwards ++ SetProcessDpiAwarenessContext setProcessDpiAwarenessContext = nullptr; ++ AreDpiAwarenessContextsEqual areDpiAwarenessContextsEqual = nullptr; ++ ++ // Clipboard listeners are present on Windows Vista onwards ++ // but missing in MinGW 4.9 stub libs. Can be removed in MinGW 5. ++ AddClipboardFormatListener addClipboardFormatListener = nullptr; ++ RemoveClipboardFormatListener removeClipboardFormatListener = nullptr; ++ ++ // Rotation API ++ GetDisplayAutoRotationPreferences getDisplayAutoRotationPreferences = nullptr; ++ SetDisplayAutoRotationPreferences setDisplayAutoRotationPreferences = nullptr; ++ ++ AdjustWindowRectExForDpi adjustWindowRectExForDpi = nullptr; ++ EnableNonClientDpiScaling enableNonClientDpiScaling = nullptr; ++ GetWindowDpiAwarenessContext getWindowDpiAwarenessContext = nullptr; ++ GetAwarenessFromDpiAwarenessContext getAwarenessFromDpiAwarenessContext = nullptr; ++ SystemParametersInfoForDpi systemParametersInfoForDpi = nullptr; ++ GetSystemMetricsForDpi getSystemMetricsForDpi = nullptr; ++}; ++ ++// Shell scaling library (Windows 8.1 onwards) ++struct QWindowsShcoreDLL ++{ ++ void init(); ++ inline bool isValid() const { return getProcessDpiAwareness && setProcessDpiAwareness && getDpiForMonitor; } ++ ++ typedef HRESULT (WINAPI *GetProcessDpiAwareness)(HANDLE,PROCESS_DPI_AWARENESS *); ++ typedef HRESULT (WINAPI *SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); ++ typedef HRESULT (WINAPI *GetDpiForMonitor)(HMONITOR,int,UINT *,UINT *); ++ ++ GetProcessDpiAwareness getProcessDpiAwareness = nullptr; ++ SetProcessDpiAwareness setProcessDpiAwareness = nullptr; ++ GetDpiForMonitor getDpiForMonitor = nullptr; ++}; ++ + class QWindowsContext + { + Q_DISABLE_COPY_MOVE(QWindowsContext) +@@ -134,6 +224,9 @@ public: + QWindowsScreenManager &screenManager(); + QWindowsTabletSupport *tabletSupport() const; + ++ static QWindowsUser32DLL user32dll; ++ static QWindowsShcoreDLL shcoredll; ++ + bool asyncExpose() const; + void setAsyncExpose(bool value); + +diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp +index 5d3a47c22fd..563b22a831f 100644 +--- a/src/plugins/platforms/windows/qwindowsdrag.cpp ++++ b/src/plugins/platforms/windows/qwindowsdrag.cpp +@@ -33,6 +33,8 @@ + + #include + ++#include "vxkex.h" ++ + QT_BEGIN_NAMESPACE + + /*! +@@ -674,7 +676,11 @@ static HRESULT startDoDragDrop(LPDATAOBJECT pDataObj, LPDROPSOURCE pDropSource, + const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam); + + POINTER_INFO pointerInfo{}; +- if (!GetPointerInfo(pointerId, &pointerInfo)) ++ BOOL bResultPointerInfo = QWindowsContext::user32dll.getPointerInfo ? ++ QWindowsContext::user32dll.getPointerInfo(pointerId, &pointerInfo) : ++ vxkex::GetPointerInfo(pointerId, &pointerInfo); ++ ++ if (!bResultPointerInfo) + return E_FAIL; + + if (pointerInfo.pointerFlags & POINTER_FLAG_PRIMARY) { +diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp +index a9fcf711edd..3a08bd35363 100644 +--- a/src/plugins/platforms/windows/qwindowsintegration.cpp ++++ b/src/plugins/platforms/windows/qwindowsintegration.cpp +@@ -140,6 +140,7 @@ static inline unsigned parseOptions(const QStringList ¶mList, + DarkModeHandling *darkModeHandling) + { + unsigned options = 0; ++ + for (const QString ¶m : paramList) { + if (param.startsWith(u"fontengine=")) { + if (param.endsWith(u"gdi")) { +@@ -485,7 +486,14 @@ QPlatformFontDatabase *QWindowsIntegration::fontDatabase() const + else + #endif // QT_NO_FREETYPE + #if QT_CONFIG(directwrite3) +- if (!(d->m_options & (QWindowsIntegration::FontDatabaseGDI | QWindowsIntegration::DontUseDirectWriteFonts))) ++ ++ /* IDWriteFontFace3 is only reportedly available starting with Windows 10. This change is necessary starting ++ with Qt 6.8, where DirectWrite is used by default to populate the font database. ++ More info: https://github.com/videolan/vlc/blob/master/contrib/src/qt/0001-Use-DirectWrite-font-database-only-with-Windows-10-a.patch ++ */ ++ ++ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10 && ++ !(d->m_options & (QWindowsIntegration::FontDatabaseGDI | QWindowsIntegration::DontUseDirectWriteFonts))) + d->m_fontDatabase = new QWindowsDirectWriteFontDatabase; + else + #endif +diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp +index 5b8e4e58ffe..5c84b47794e 100644 +--- a/src/plugins/platforms/windows/qwindowskeymapper.cpp ++++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp +@@ -17,6 +17,8 @@ + #include + #include + ++#include "vxkex.h" ++ + #if defined(WM_APPCOMMAND) + # ifndef FAPPCOMMAND_MOUSE + # define FAPPCOMMAND_MOUSE 0x8000 +@@ -732,14 +734,17 @@ static inline QString messageKeyText(const MSG &msg) + + [[nodiscard]] static inline int getTitleBarHeight(const HWND hwnd) + { +- const UINT dpi = GetDpiForWindow(hwnd); +- const int captionHeight = GetSystemMetricsForDpi(SM_CYCAPTION, dpi); ++ const BOOL bNewAPI = (QWindowsContext::user32dll.getSystemMetricsForDpi != nullptr); ++ const UINT dpi = bNewAPI ? QWindowsContext::user32dll.getDpiForWindow(hwnd) : vxkex::GetDpiForWindow(hwnd); ++ const int captionHeight = bNewAPI ? QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CYCAPTION, dpi) : vxkex::GetSystemMetricsForDpi(SM_CYCAPTION, dpi); + if (IsZoomed(hwnd)) + return captionHeight; + // The frame height should also be taken into account if the window + // is not maximized. +- const int frameHeight = GetSystemMetricsForDpi(SM_CYSIZEFRAME, dpi) +- + GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi); ++ const int frameHeight = bNewAPI ? ++ (QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CYSIZEFRAME, dpi) + QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi)) ++ : (vxkex::GetSystemMetricsForDpi(SM_CYSIZEFRAME, dpi) + vxkex::GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi)); ++ + return captionHeight + frameHeight; + } + +diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp +index 7995716444a..fab22b394ab 100644 +--- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp ++++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp +@@ -26,6 +26,8 @@ + + #include + ++#include "vxkex.h" ++ + QT_BEGIN_NAMESPACE + + enum { +@@ -55,7 +57,11 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q + *result = 0; + const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam); + +- if (!GetPointerType(pointerId, &m_pointerType)) { ++ BOOL bResultPt = QWindowsContext::user32dll.getPointerType ? ++ QWindowsContext::user32dll.getPointerType(pointerId, &m_pointerType) : ++ vxkex::GetPointerType(pointerId, &m_pointerType); ++ ++ if (!bResultPt) { + qWarning() << "GetPointerType() failed:" << qt_error_string(); + return false; + } +@@ -69,12 +75,21 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q + } + case QT_PT_TOUCH: { + quint32 pointerCount = 0; +- if (!GetPointerFrameTouchInfo(pointerId, &pointerCount, nullptr)) { ++ BOOL bResultPointerTouchInfo = QWindowsContext::user32dll.getPointerFrameTouchInfo ? ++ QWindowsContext::user32dll.getPointerFrameTouchInfo(pointerId, &pointerCount, nullptr) : ++ vxkex::GetPointerFrameTouchInfo(pointerId, &pointerCount, nullptr); ++ ++ if (!bResultPointerTouchInfo) { + qWarning() << "GetPointerFrameTouchInfo() failed:" << qt_error_string(); + return false; + } + QVarLengthArray touchInfo(pointerCount); +- if (!GetPointerFrameTouchInfo(pointerId, &pointerCount, touchInfo.data())) { ++ ++ bResultPointerTouchInfo = QWindowsContext::user32dll.getPointerFrameTouchInfo ? ++ QWindowsContext::user32dll.getPointerFrameTouchInfo(pointerId, &pointerCount, touchInfo.data()) : ++ vxkex::GetPointerFrameTouchInfo(pointerId, &pointerCount, touchInfo.data()); ++ ++ if (!bResultPointerTouchInfo) { + qWarning() << "GetPointerFrameTouchInfo() failed:" << qt_error_string(); + return false; + } +@@ -87,10 +102,12 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q + // dispatch any skipped frames if event compression is disabled by the app + if (historyCount > 1 && !QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents)) { + touchInfo.resize(pointerCount * historyCount); +- if (!GetPointerFrameTouchInfoHistory(pointerId, +- &historyCount, +- &pointerCount, +- touchInfo.data())) { ++ ++ BOOL bResultTouchHistory = QWindowsContext::user32dll.getPointerFrameTouchInfoHistory ? ++ QWindowsContext::user32dll.getPointerFrameTouchInfoHistory(pointerId, &historyCount, &pointerCount, touchInfo.data()) : ++ vxkex::GetPointerFrameTouchInfoHistory(pointerId, &historyCount, &pointerCount, touchInfo.data()); ++ ++ if (!bResultTouchHistory) { + qWarning() << "GetPointerFrameTouchInfoHistory() failed:" << qt_error_string(); + return false; + } +@@ -108,7 +125,11 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q + } + case QT_PT_PEN: { + POINTER_PEN_INFO penInfo; +- if (!GetPointerPenInfo(pointerId, &penInfo)) { ++ ++ BOOL bResultPenInfo = QWindowsContext::user32dll.getPointerPenInfo ? ++ QWindowsContext::user32dll.getPointerPenInfo(pointerId, &penInfo) : vxkex::GetPointerPenInfo(pointerId, &penInfo); ++ ++ if (!bResultPenInfo) { + qWarning() << "GetPointerPenInfo() failed:" << qt_error_string(); + return false; + } +@@ -120,7 +141,11 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q + || !QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents))) { + QVarLengthArray penInfoHistory(historyCount); + +- if (!GetPointerPenInfoHistory(pointerId, &historyCount, penInfoHistory.data())) { ++ BOOL bResultPenInfoHistory = QWindowsContext::user32dll.getPointerPenInfoHistory ? ++ QWindowsContext::user32dll.getPointerPenInfoHistory(pointerId, &historyCount, penInfoHistory.data()) : ++ vxkex::GetPointerPenInfoHistory(pointerId, &historyCount, penInfoHistory.data()); ++ ++ if (!bResultPenInfoHistory) { + qWarning() << "GetPointerPenInfoHistory() failed:" << qt_error_string(); + return false; + } +@@ -527,7 +552,10 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, + inputIds.insert(touchPoint.id); + + // Avoid getting repeated messages for this frame if there are multiple pointerIds +- SkipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId); ++ if (QWindowsContext::user32dll.skipPointerFrameMessages) ++ QWindowsContext::user32dll.skipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId); ++ else ++ vxkex::SkipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId); + } + + // Some devices send touches for each finger in a different message/frame, instead of consolidating +@@ -574,7 +602,12 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin + auto *penInfo = static_cast(vPenInfo); + + RECT pRect, dRect; +- if (!GetPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect)) ++ ++ BOOL bResultDeviceRects = QWindowsContext::user32dll.getPointerDeviceRects ? ++ QWindowsContext::user32dll.getPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect) : ++ vxkex::GetPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect); ++ ++ if (!bResultDeviceRects) + return false; + + const auto systemId = (qint64)penInfo->pointerInfo.sourceDevice; +diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp +index 6c86c47caac..24588473185 100644 +--- a/src/plugins/platforms/windows/qwindowsscreen.cpp ++++ b/src/plugins/platforms/windows/qwindowsscreen.cpp +@@ -32,6 +32,8 @@ + #include + #include + ++#include "vxkex.h" ++ + QT_BEGIN_NAMESPACE + + using namespace Qt::StringLiterals; +@@ -45,7 +47,15 @@ static inline QDpi monitorDPI(HMONITOR hMonitor) + { + UINT dpiX; + UINT dpiY; +- if (SUCCEEDED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY))) ++ ++ HRESULT hr = S_OK; ++ ++ if (QWindowsContext::shcoredll.isValid()) ++ hr = QWindowsContext::shcoredll.getDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); ++ else ++ hr = vxkex::GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); ++ ++ if (SUCCEEDED(hr)) + return QDpi(dpiX, dpiY); + return {0, 0}; + } +@@ -609,7 +619,10 @@ bool QWindowsScreen::setOrientationPreference(Qt::ScreenOrientation o) + orientationPreference = ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED; + break; + } +- result = SetDisplayAutoRotationPreferences(orientationPreference); ++ if (QWindowsContext::user32dll.setDisplayAutoRotationPreferences) ++ result = QWindowsContext::user32dll.setDisplayAutoRotationPreferences(orientationPreference); ++ else ++ result = vxkex::SetDisplayAutoRotationPreferences(orientationPreference); + return result; + } + +@@ -617,7 +630,15 @@ Qt::ScreenOrientation QWindowsScreen::orientationPreference() + { + Qt::ScreenOrientation result = Qt::PrimaryOrientation; + ORIENTATION_PREFERENCE orientationPreference = ORIENTATION_PREFERENCE_NONE; +- if (GetDisplayAutoRotationPreferences(&orientationPreference)) { ++ ++ BOOL bResult = TRUE; ++ ++ if (QWindowsContext::user32dll.getDisplayAutoRotationPreferences) ++ bResult = QWindowsContext::user32dll.getDisplayAutoRotationPreferences((DWORD *)&orientationPreference); ++ else ++ bResult = vxkex::GetDisplayAutoRotationPreferences(&orientationPreference); ++ ++ if (bResult) { + switch (orientationPreference) { + case ORIENTATION_PREFERENCE_NONE: + break; +diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp +index 97b2dd339be..2d6dbf36adc 100644 +--- a/src/plugins/platforms/windows/qwindowstheme.cpp ++++ b/src/plugins/platforms/windows/qwindowstheme.cpp +@@ -45,6 +45,8 @@ + + #include + ++#include "vxkex.h" ++ + #if QT_CONFIG(cpp_winrt) + # include + +@@ -97,36 +99,52 @@ static constexpr QColor getSysColor(winrt::Windows::UI::Color &&color) + + [[maybe_unused]] [[nodiscard]] static inline QColor qt_accentColor(AccentColorLevel level) + { ++ QColor accent; ++ QColor accentLight; ++ QColor accentLighter; ++ QColor accentLightest; ++ QColor accentDark; ++ QColor accentDarker; ++ QColor accentDarkest; ++ + #if QT_CONFIG(cpp_winrt) +- using namespace winrt::Windows::UI::ViewManagement; +- const auto settings = UISettings(); +- const QColor accent = getSysColor(settings.GetColorValue(UIColorType::Accent)); +- const QColor accentLight = getSysColor(settings.GetColorValue(UIColorType::AccentLight1)); +- const QColor accentLighter = getSysColor(settings.GetColorValue(UIColorType::AccentLight2)); +- const QColor accentLightest = getSysColor(settings.GetColorValue(UIColorType::AccentLight3)); +- const QColor accentDark = getSysColor(settings.GetColorValue(UIColorType::AccentDark1)); +- const QColor accentDarker = getSysColor(settings.GetColorValue(UIColorType::AccentDark2)); +- const QColor accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3)); +-#else +- const QWinRegistryKey registry(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\DWM)"); +- if (!registry.isValid()) +- return {}; +- const QVariant value = registry.value(L"AccentColor"); +- if (!value.isValid()) +- return {}; +- // The retrieved value is in the #AABBGGRR format, we need to +- // convert it to the #AARRGGBB format which Qt expects. +- const QColor abgr = QColor::fromRgba(qvariant_cast(value)); +- if (!abgr.isValid()) +- return {}; +- const QColor accent = QColor::fromRgb(abgr.blue(), abgr.green(), abgr.red(), abgr.alpha()); +- const QColor accentLight = accent.lighter(120); +- const QColor accentLighter = accentLight.lighter(120); +- const QColor accentLightest = accentLighter.lighter(120); +- const QColor accentDark = accent.darker(120); +- const QColor accentDarker = accentDark.darker(120); +- const QColor accentDarkest = accentDarker.darker(120); ++ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10) ++ { ++ using namespace winrt::Windows::UI::ViewManagement; ++ const auto settings = UISettings(); ++ accent = getSysColor(settings.GetColorValue(UIColorType::Accent)); ++ accentLight = getSysColor(settings.GetColorValue(UIColorType::AccentLight1)); ++ accentLighter = getSysColor(settings.GetColorValue(UIColorType::AccentLight2)); ++ accentLightest = getSysColor(settings.GetColorValue(UIColorType::AccentLight3)); ++ accentDark = getSysColor(settings.GetColorValue(UIColorType::AccentDark1)); ++ accentDarker = getSysColor(settings.GetColorValue(UIColorType::AccentDark2)); ++ accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3)); ++ } + #endif ++ ++ if (!accent.isValid()) ++ { ++ const QWinRegistryKey registry(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\DWM)"); ++ if (!registry.isValid()) ++ return {}; ++ const QVariant value = registry.value(L"AccentColor"); ++ if (!value.isValid()) ++ return {}; ++ // The retrieved value is in the #AABBGGRR format, we need to ++ // convert it to the #AARRGGBB format which Qt expects. ++ const QColor abgr = QColor::fromRgba(qvariant_cast(value)); ++ if (!abgr.isValid()) ++ return {}; ++ accent = QColor::fromRgb(abgr.blue(), abgr.green(), abgr.red(), abgr.alpha()); ++ accentLight = accent.lighter(120); ++ accentLighter = accentLight.lighter(120); ++ accentLightest = accentLighter.lighter(120); ++ accentDarkest = accent.darker(120 * 120 * 120); ++ accentDark = accent.darker(120); ++ accentDarker = accentDark.darker(120); ++ accentDarkest = accentDarker.darker(120); ++ } ++ + switch (level) { + case AccentColorDarkest: + return accentDarkest; +@@ -154,6 +172,7 @@ static inline QColor getSysColor(int index) + // QTBUG-48823/Windows 10: SHGetFileInfo() (as called by item views on file system + // models has been observed to trigger a WM_PAINT on the mainwindow. Suppress the + // behavior by running it in a thread. ++ + class QShGetFileInfoThread : public QThread + { + public: +@@ -326,46 +345,45 @@ void QWindowsTheme::populateLightSystemBasePalette(QPalette &result) + + void QWindowsTheme::populateDarkSystemBasePalette(QPalette &result) + { +- QColor foreground, background, +- accent, accentDark, accentDarker, accentDarkest, +- accentLight, accentLighter, accentLightest; ++ QColor foreground = Qt::white; ++ QColor background = QColor(0x1E, 0x1E, 0x1E); ++ QColor accent = qt_accentColor(AccentColorNormal); ++ QColor accentDark = accent.darker(120); ++ QColor accentDarker = accentDark.darker(120); ++ QColor accentDarkest = accentDarker.darker(120); ++ QColor accentLight = accent.lighter(120); ++ QColor accentLighter = accentLight.lighter(120); ++ QColor accentLightest = accentLighter.lighter(120); ++ + #if QT_CONFIG(cpp_winrt) +- using namespace winrt::Windows::UI::ViewManagement; +- const auto settings = UISettings(); +- +- // We have to craft a palette from these colors. The settings.UIElementColor(UIElementType) API +- // returns the old system colors, not the dark mode colors. If the background is black (which it +- // usually), then override it with a dark gray instead so that we can go up and down the lightness. +- if (QWindowsTheme::queryColorScheme() == Qt::ColorScheme::Dark) { +- // the system is actually running in dark mode, so UISettings will give us dark colors +- foreground = getSysColor(settings.GetColorValue(UIColorType::Foreground)); +- background = [&settings]() -> QColor { +- auto systemBackground = getSysColor(settings.GetColorValue(UIColorType::Background)); +- if (systemBackground == Qt::black) +- systemBackground = QColor(0x1E, 0x1E, 0x1E); +- return systemBackground; +- }(); +- accent = qt_accentColor(AccentColorNormal); +- accentDark = qt_accentColor(AccentColorDark); +- accentDarker = qt_accentColor(AccentColorDarker); +- accentDarkest = qt_accentColor(AccentColorDarkest); +- accentLight = qt_accentColor(AccentColorLight); +- accentLighter = qt_accentColor(AccentColorLighter); +- accentLightest = qt_accentColor(AccentColorLightest); +- } else +-#endif ++ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10) + { +- // If the system is running in light mode, then we need to make up our own dark palette +- foreground = Qt::white; +- background = QColor(0x1E, 0x1E, 0x1E); +- accent = qt_accentColor(AccentColorNormal); +- accentDark = accent.darker(120); +- accentDarker = accentDark.darker(120); +- accentDarkest = accentDarker.darker(120); +- accentLight = accent.lighter(120); +- accentLighter = accentLight.lighter(120); +- accentLightest = accentLighter.lighter(120); ++ using namespace winrt::Windows::UI::ViewManagement; ++ const auto settings = UISettings(); ++ ++ // We have to craft a palette from these colors. The settings.UIElementColor(UIElementType) API ++ // returns the old system colors, not the dark mode colors. If the background is black (which it ++ // usually), then override it with a dark gray instead so that we can go up and down the lightness. ++ if (QWindowsTheme::queryColorScheme() == Qt::ColorScheme::Dark) { ++ // the system is actually running in dark mode, so UISettings will give us dark colors ++ foreground = getSysColor(settings.GetColorValue(UIColorType::Foreground)); ++ background = [&settings]() -> QColor { ++ auto systemBackground = getSysColor(settings.GetColorValue(UIColorType::Background)); ++ if (systemBackground == Qt::black) ++ systemBackground = QColor(0x1E, 0x1E, 0x1E); ++ return systemBackground; ++ }(); ++ accent = qt_accentColor(AccentColorNormal); ++ accentDark = qt_accentColor(AccentColorDark); ++ accentDarker = qt_accentColor(AccentColorDarker); ++ accentDarkest = qt_accentColor(AccentColorDarkest); ++ accentLight = qt_accentColor(AccentColorLight); ++ accentLighter = qt_accentColor(AccentColorLighter); ++ accentLightest = qt_accentColor(AccentColorLightest); ++ } + } ++#endif ++ + const QColor linkColor = accentLightest; + const QColor buttonColor = background.lighter(200); + +@@ -738,7 +756,10 @@ void QWindowsTheme::refreshFonts() + fixedFont.setStyleHint(QFont::TypeWriter); + + LOGFONT lfIconTitleFont; +- SystemParametersInfoForDpi(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0, dpi); ++ if (QWindowsContext::user32dll.systemParametersInfoForDpi) ++ QWindowsContext::user32dll.systemParametersInfoForDpi(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0, dpi); ++ else ++ vxkex::SystemParametersInfoForDpi(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0, dpi); + const QFont iconTitleFont = QWindowsFontDatabase::LOGFONT_to_QFont(lfIconTitleFont, dpi); + + m_fonts[SystemFont] = new QFont(QWindowsFontDatabase::systemDefaultFont()); +@@ -1001,6 +1022,7 @@ public: + static QPixmap pixmapFromShellImageList(int iImageList, int iIcon) + { + QPixmap result; ++ + // For MinGW: + static const IID iID_IImageList = {0x46eb5926, 0x582e, 0x4017, {0x9f, 0xdf, 0xe8, 0x99, 0x8d, 0xaa, 0x9, 0x50}}; + +@@ -1015,6 +1037,7 @@ static QPixmap pixmapFromShellImageList(int iImageList, int iIcon) + DestroyIcon(hIcon); + } + imageList->Release(); ++ + return result; + } + +diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp +index f44a28f5636..6d6409c7878 100644 +--- a/src/plugins/platforms/windows/qwindowswindow.cpp ++++ b/src/plugins/platforms/windows/qwindowswindow.cpp +@@ -46,6 +46,8 @@ + + #include + ++#include "vxkex.h" ++ + QT_BEGIN_NAMESPACE + + using QWindowCreationContextPtr = QSharedPointer; +@@ -522,11 +524,15 @@ static inline void updateGLWindowSettings(const QWindow *w, HWND hwnd, Qt::Windo + + [[nodiscard]] static inline int getResizeBorderThickness(const UINT dpi) + { +- // The width of the padded border will always be 0 if DWM composition is +- // disabled, but since it will always be enabled and can't be programtically +- // disabled from Windows 8, we are safe to go. +- return GetSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) +- + GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi); ++ if (QWindowsContext::user32dll.getSystemMetricsForDpi) { ++ // The width of the padded border will always be 0 if DWM composition is ++ // disabled, but since it will always be enabled and can't be programtically ++ // disabled from Windows 8, we are safe to go. ++ return QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) ++ + QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi); ++ } ++ else ++ return vxkex::GetSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) + vxkex::GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi); + } + + /*! +@@ -538,11 +544,21 @@ static QMargins invisibleMargins(QPoint screenPoint) + { + POINT pt = {screenPoint.x(), screenPoint.y()}; + if (HMONITOR hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) { +- UINT dpiX; +- UINT dpiY; +- if (SUCCEEDED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY))) { +- const int gap = getResizeBorderThickness(dpiX); +- return QMargins(gap, 0, gap, gap); ++ if (QWindowsContext::shcoredll.isValid()) { ++ UINT dpiX; ++ UINT dpiY; ++ ++ HRESULT hr = S_OK; ++ ++ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10) ++ hr = QWindowsContext::shcoredll.getDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); ++ else ++ hr = vxkex::GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); ++ ++ if (SUCCEEDED(hr)) { ++ const int gap = getResizeBorderThickness(dpiX); ++ return QMargins(gap, 0, gap, gap); ++ } + } + } + return QMargins(); +@@ -550,7 +566,8 @@ static QMargins invisibleMargins(QPoint screenPoint) + + [[nodiscard]] static inline QMargins invisibleMargins(const HWND hwnd) + { +- const UINT dpi = GetDpiForWindow(hwnd); ++ const UINT dpi = (QWindowsContext::user32dll.getDpiForWindow) ? QWindowsContext::user32dll.getDpiForWindow(hwnd) : vxkex::GetDpiForWindow(hwnd); ++ + const int gap = getResizeBorderThickness(dpi); + return QMargins(gap, 0, gap, gap); + } +@@ -851,7 +868,7 @@ static inline bool shouldApplyDarkFrame(const QWindow *w) + { + if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint)) + return false; +- ++ + // the user of the application has explicitly opted out of dark frames + if (!QWindowsIntegration::instance()->darkModeHandling().testFlag(QWindowsApplication::DarkModeWindowFrames)) + return false; +@@ -1071,9 +1088,17 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, DWORD style, DWORD exStyl + return {}; + RECT rect = {0,0,0,0}; + style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs. +- if (AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, unsigned(qRound(dpi))) == FALSE) { +- qErrnoWarning("%s: AdjustWindowRectExForDpi failed", __FUNCTION__); ++ if (QWindowsContext::user32dll.adjustWindowRectExForDpi) ++ { ++ if (QWindowsContext::user32dll.adjustWindowRectExForDpi(&rect, style, FALSE, exStyle, unsigned(qRound(dpi))) == FALSE) ++ qErrnoWarning("%s: AdjustWindowRectExForDpi failed", __FUNCTION__); ++ } ++ else ++ { ++ if (vxkex::AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, unsigned(qRound(dpi))) == FALSE) ++ qErrnoWarning("%s: vxkex::AdjustWindowRectExForDpi failed", __FUNCTION__); + } ++ + const QMargins result(qAbs(rect.left), qAbs(rect.top), + qAbs(rect.right), qAbs(rect.bottom)); + qCDebug(lcQpaWindow).nospace() << __FUNCTION__ << " style=" +@@ -1380,7 +1405,7 @@ void QWindowsForeignWindow::setParent(const QPlatformWindow *newParentWindow) + qCDebug(lcQpaWindow) << __FUNCTION__ << window() << "newParent=" + << newParentWindow << newParent << "oldStyle=" << debugWinStyle(oldStyle); + +- auto updateWindowFlags = [&] { ++ auto updateWindowFlags = [&]{ + // Top level window flags need to be set/cleared manually. + DWORD newStyle = oldStyle; + if (isTopLevel) { +@@ -1588,7 +1613,8 @@ void QWindowsWindow::initialize() + QWindowSystemInterface::handleGeometryChange(w, obtainedGeometry); + } + } +- QWindowsWindow::setSavedDpi(GetDpiForWindow(handle())); ++ QWindowsWindow::setSavedDpi(QWindowsContext::user32dll.getDpiForWindow ? ++ QWindowsContext::user32dll.getDpiForWindow(handle()) : vxkex::GetDpiForWindow(handle())); + } + + QSurfaceFormat QWindowsWindow::format() const +@@ -2083,7 +2109,7 @@ void QWindowsWindow::handleDpiChanged(HWND hwnd, WPARAM wParam, LPARAM lParam) + + void QWindowsWindow::handleDpiChangedAfterParent(HWND hwnd) + { +- const UINT dpi = GetDpiForWindow(hwnd); ++ const UINT dpi = QWindowsContext::user32dll.getDpiForWindow ? QWindowsContext::user32dll.getDpiForWindow(hwnd) : vxkex::GetDpiForWindow(hwnd); + const qreal scale = dpiRelativeScale(dpi); + setSavedDpi(dpi); + +@@ -2177,6 +2203,7 @@ void QWindowsWindow::setGeometry(const QRect &rectIn) + } + if (m_windowState & Qt::WindowMinimized) + m_data.geometry = rect; // Otherwise set by handleGeometryChange() triggered by event. ++ + if (m_data.hwnd) { + // A ResizeEvent with resulting geometry will be sent. If we cannot + // achieve that size (for example, window title minimal constraint), +diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp +index 638d684ce4f..1c89fd87ede 100644 +--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp ++++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp +@@ -15,6 +15,8 @@ + #include + #include + #include ++#include "qwindowsuiawrapper_p.h" ++#include "qwindowsuiawrapper.cpp" + + #include + +@@ -47,7 +49,7 @@ bool QWindowsUiaAccessibility::handleWmGetObject(HWND hwnd, WPARAM wParam, LPARA + if (QWindow *window = QWindowsContext::instance()->findWindow(hwnd)) { + if (QAccessibleInterface *accessible = window->accessibleRoot()) { + auto provider = QWindowsUiaMainProvider::providerForAccessible(accessible); +- *lResult = UiaReturnRawElementProvider(hwnd, wParam, lParam, provider.Get()); ++ *lResult = QWindowsUiaWrapper::instance()->returnRawElementProvider(hwnd, wParam, lParam, provider.Get()); + return true; + } + } +@@ -122,8 +124,12 @@ void QWindowsUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event + if (!isActive() || !accessible || !accessible->isValid()) + return; + ++ // Ensures QWindowsUiaWrapper is properly initialized. ++ if (!QWindowsUiaWrapper::instance()->ready()) ++ return; ++ + // No need to do anything when nobody is listening. +- if (!UiaClientsAreListening()) ++ if (!QWindowsUiaWrapper::instance()->clientsAreListening()) + return; + + switch (event->type()) { +diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +index f01c594b6cd..02e853da78b 100644 +--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp ++++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +@@ -21,6 +21,7 @@ + #include "qwindowscontext.h" + #include "qwindowsuiautils.h" + #include "qwindowsuiaprovidercache.h" ++#include "qwindowsuiawrapper_p.h" + + #include + #include +@@ -75,7 +76,7 @@ void QWindowsUiaMainProvider::notifyFocusChange(QAccessibleEvent *event) + accessible = child; + } + if (auto provider = providerForAccessible(accessible)) +- UiaRaiseAutomationEvent(provider.Get(), UIA_AutomationFocusChangedEventId); ++ QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider.Get(), UIA_AutomationFocusChangedEventId); + } + } + +@@ -92,7 +93,7 @@ void QWindowsUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *eve + + QComVariant oldVal; + QComVariant newVal{toggleState}; +- UiaRaiseAutomationPropertyChangedEvent( ++ QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent( + provider.Get(), UIA_ToggleToggleStatePropertyId, oldVal.get(), newVal.get()); + } + } +@@ -102,15 +103,15 @@ void QWindowsUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *eve + // Notifies window opened/closed. + if (auto provider = providerForAccessible(accessible)) { + if (accessible->state().active) { +- UiaRaiseAutomationEvent(provider.Get(), UIA_Window_WindowOpenedEventId); ++ QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider.Get(), UIA_Window_WindowOpenedEventId); + if (QAccessibleInterface *focused = accessible->focusChild()) { + if (auto focusedProvider = providerForAccessible(focused)) { +- UiaRaiseAutomationEvent(focusedProvider.Get(), ++ QWindowsUiaWrapper::instance()->raiseAutomationEvent(focusedProvider.Get(), + UIA_AutomationFocusChangedEventId); + } + } + } else { +- UiaRaiseAutomationEvent(provider.Get(), UIA_Window_WindowClosedEventId); ++ QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider.Get(), UIA_Window_WindowClosedEventId); + } + } + } +@@ -142,7 +143,7 @@ void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *eve + // Notifies changes in string values. + const QComVariant oldVal; + const QComVariant newVal{ event->value().toString() }; +- UiaRaiseAutomationPropertyChangedEvent(provider.Get(), UIA_ValueValuePropertyId, ++ QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider.Get(), UIA_ValueValuePropertyId, + oldVal.get(), newVal.get()); + } + } else if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) { +@@ -150,7 +151,7 @@ void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *eve + // Notifies changes in values of controls supporting the value interface. + const QComVariant oldVal; + const QComVariant newVal{ valueInterface->currentValue().toDouble() }; +- UiaRaiseAutomationPropertyChangedEvent( ++ QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent( + provider.Get(), UIA_RangeValueValuePropertyId, oldVal.get(), newVal.get()); + } + } +@@ -166,7 +167,7 @@ void QWindowsUiaMainProvider::notifyNameChange(QAccessibleEvent *event) + if (auto provider = providerForAccessible(accessible)) { + QComVariant oldVal; + QComVariant newVal{ accessible->text(QAccessible::Name) }; +- UiaRaiseAutomationPropertyChangedEvent(provider.Get(), UIA_NamePropertyId, ++ QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider.Get(), UIA_NamePropertyId, + oldVal.get(), newVal.get()); + } + } +@@ -177,7 +178,7 @@ void QWindowsUiaMainProvider::notifySelectionChange(QAccessibleEvent *event) + { + if (QAccessibleInterface *accessible = event->accessibleInterface()) { + if (auto provider = providerForAccessible(accessible)) +- UiaRaiseAutomationEvent(provider.Get(), UIA_SelectionItem_ElementSelectedEventId); ++ QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider.Get(), UIA_SelectionItem_ElementSelectedEventId); + } + } + +@@ -188,14 +189,14 @@ void QWindowsUiaMainProvider::notifyTextChange(QAccessibleEvent *event) + if (accessible->textInterface()) { + if (auto provider = providerForAccessible(accessible)) { + if (event->type() == QAccessible::TextSelectionChanged) { +- UiaRaiseAutomationEvent(provider.Get(), UIA_Text_TextSelectionChangedEventId); ++ QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider.Get(), UIA_Text_TextSelectionChangedEventId); + } else if (event->type() == QAccessible::TextCaretMoved) { + if (!accessible->state().readOnly) { +- UiaRaiseAutomationEvent(provider.Get(), ++ QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider.Get(), + UIA_Text_TextSelectionChangedEventId); + } + } else { +- UiaRaiseAutomationEvent(provider.Get(), UIA_Text_TextChangedEventId); ++ QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider.Get(), UIA_Text_TextChangedEventId); + } + } + } +@@ -212,7 +213,7 @@ void QWindowsUiaMainProvider::raiseNotification(QAccessibleAnnouncementEvent *ev + ? NotificationProcessing_ImportantAll + : NotificationProcessing_All; + QBStr activityId{ QString::fromLatin1("") }; +- UiaRaiseNotificationEvent(provider.Get(), NotificationKind_Other, processing, message.bstr(), ++ QWindowsUiaWrapper::instance()->raiseNotificationEvent(provider.Get(), NotificationKind_Other, processing, message.bstr(), + activityId.bstr()); + + } +@@ -615,7 +616,7 @@ HRESULT QWindowsUiaMainProvider::get_HostRawElementProvider(IRawElementProviderS + // Returns a host provider only for controls associated with a native window handle. Others should return NULL. + if (QAccessibleInterface *accessible = accessibleInterface()) { + if (HWND hwnd = hwndForAccessible(accessible)) { +- return UiaHostProviderFromHwnd(hwnd, pRetVal); ++ return QWindowsUiaWrapper::instance()->hostProviderFromHwnd(hwnd, pRetVal); + } + } + return S_OK; +diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiawrapper.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiawrapper.cpp +new file mode 100644 +index 00000000000..caeb8e1da48 +--- /dev/null ++++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiawrapper.cpp +@@ -0,0 +1,89 @@ ++// Copyright (C) 2017 The Qt Company Ltd. ++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only ++ ++#include ++ ++#include "qwindowsuiawrapper_p.h" ++#include ++ ++QT_BEGIN_NAMESPACE ++ ++// private constructor ++QWindowsUiaWrapper::QWindowsUiaWrapper() ++{ ++ QSystemLibrary uiaLib(QStringLiteral("UIAutomationCore")); ++ if (uiaLib.load()) { ++ m_pUiaReturnRawElementProvider = reinterpret_cast(uiaLib.resolve("UiaReturnRawElementProvider")); ++ m_pUiaHostProviderFromHwnd = reinterpret_cast(uiaLib.resolve("UiaHostProviderFromHwnd")); ++ m_pUiaRaiseAutomationPropertyChangedEvent = reinterpret_cast(uiaLib.resolve("UiaRaiseAutomationPropertyChangedEvent")); ++ m_pUiaRaiseAutomationEvent = reinterpret_cast(uiaLib.resolve("UiaRaiseAutomationEvent")); ++ m_pUiaRaiseNotificationEvent = reinterpret_cast(uiaLib.resolve("UiaRaiseNotificationEvent")); ++ m_pUiaClientsAreListening = reinterpret_cast(uiaLib.resolve("UiaClientsAreListening")); ++ } ++} ++ ++QWindowsUiaWrapper::~QWindowsUiaWrapper() ++{ ++} ++ ++// shared instance ++QWindowsUiaWrapper *QWindowsUiaWrapper::instance() ++{ ++ static QWindowsUiaWrapper wrapper; ++ return &wrapper; ++} ++ ++// True if all symbols resolved. ++BOOL QWindowsUiaWrapper::ready() ++{ ++ return m_pUiaReturnRawElementProvider ++ && m_pUiaHostProviderFromHwnd ++ && m_pUiaRaiseAutomationPropertyChangedEvent ++ && m_pUiaRaiseAutomationEvent ++ && m_pUiaClientsAreListening; ++} ++ ++BOOL QWindowsUiaWrapper::clientsAreListening() ++{ ++ if (!m_pUiaClientsAreListening) ++ return FALSE; ++ return m_pUiaClientsAreListening(); ++} ++ ++LRESULT QWindowsUiaWrapper::returnRawElementProvider(HWND hwnd, WPARAM wParam, LPARAM lParam, IRawElementProviderSimple *el) ++{ ++ if (!m_pUiaReturnRawElementProvider) ++ return static_cast(NULL); ++ return m_pUiaReturnRawElementProvider(hwnd, wParam, lParam, el); ++} ++ ++HRESULT QWindowsUiaWrapper::hostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **ppProvider) ++{ ++ if (!m_pUiaHostProviderFromHwnd) ++ return UIA_E_NOTSUPPORTED; ++ return m_pUiaHostProviderFromHwnd(hwnd, ppProvider); ++} ++ ++HRESULT QWindowsUiaWrapper::raiseAutomationPropertyChangedEvent(IRawElementProviderSimple *pProvider, PROPERTYID id, VARIANT oldValue, VARIANT newValue) ++{ ++ if (!m_pUiaRaiseAutomationPropertyChangedEvent) ++ return UIA_E_NOTSUPPORTED; ++ return m_pUiaRaiseAutomationPropertyChangedEvent(pProvider, id, oldValue, newValue); ++} ++ ++HRESULT QWindowsUiaWrapper::raiseAutomationEvent(IRawElementProviderSimple *pProvider, EVENTID id) ++{ ++ if (!m_pUiaRaiseAutomationEvent) ++ return UIA_E_NOTSUPPORTED; ++ return m_pUiaRaiseAutomationEvent(pProvider, id); ++} ++ ++HRESULT QWindowsUiaWrapper::raiseNotificationEvent(IRawElementProviderSimple *pProvider, NotificationKind notificationKind, NotificationProcessing notificationProcessing, BSTR displayString, BSTR activityId) ++{ ++ if (!m_pUiaRaiseNotificationEvent) ++ return UIA_E_NOTSUPPORTED; ++ return m_pUiaRaiseNotificationEvent(pProvider, notificationKind, notificationProcessing, displayString, activityId); ++} ++ ++QT_END_NAMESPACE ++ +diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiawrapper_p.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiawrapper_p.h +new file mode 100644 +index 00000000000..e005318114c +--- /dev/null ++++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiawrapper_p.h +@@ -0,0 +1,57 @@ ++// Copyright (C) 2017 The Qt Company Ltd. ++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only ++ ++#ifndef QWINDOWSUIAWRAPPER_H ++#define QWINDOWSUIAWRAPPER_H ++ ++// ++// W A R N I N G ++// ------------- ++// ++// This file is not part of the Qt API. It exists for the convenience ++// of other Qt classes. This header file may change from version to ++// version without notice, or even be removed. ++// ++// We mean it. ++// ++ ++#include ++ ++QT_REQUIRE_CONFIG(accessibility); ++ ++QT_BEGIN_NAMESPACE ++ ++class QWindowsUiaWrapper ++{ ++ QWindowsUiaWrapper(); ++ virtual ~QWindowsUiaWrapper(); ++public: ++ static QWindowsUiaWrapper *instance(); ++ BOOL ready(); ++ BOOL clientsAreListening(); ++ LRESULT returnRawElementProvider(HWND hwnd, WPARAM wParam, LPARAM lParam, IRawElementProviderSimple *el); ++ HRESULT hostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **ppProvider); ++ HRESULT raiseAutomationPropertyChangedEvent(IRawElementProviderSimple *pProvider, PROPERTYID id, VARIANT oldValue, VARIANT newValue); ++ HRESULT raiseAutomationEvent(IRawElementProviderSimple *pProvider, EVENTID id); ++ HRESULT raiseNotificationEvent(IRawElementProviderSimple *pProvider, NotificationKind notificationKind, NotificationProcessing notificationProcessing, BSTR displayString, BSTR activityId); ++ ++private: ++ typedef LRESULT (WINAPI *PtrUiaReturnRawElementProvider)(HWND, WPARAM, LPARAM, IRawElementProviderSimple *); ++ typedef HRESULT (WINAPI *PtrUiaHostProviderFromHwnd)(HWND, IRawElementProviderSimple **); ++ typedef HRESULT (WINAPI *PtrUiaRaiseAutomationPropertyChangedEvent)(IRawElementProviderSimple *, PROPERTYID, VARIANT, VARIANT); ++ typedef HRESULT (WINAPI *PtrUiaRaiseAutomationEvent)(IRawElementProviderSimple *, EVENTID); ++ typedef HRESULT (WINAPI *PtrUiaRaiseNotificationEvent)(IRawElementProviderSimple *, NotificationKind, NotificationProcessing, BSTR, BSTR); ++ ++ typedef BOOL (WINAPI *PtrUiaClientsAreListening)(); ++ PtrUiaReturnRawElementProvider m_pUiaReturnRawElementProvider = nullptr; ++ PtrUiaHostProviderFromHwnd m_pUiaHostProviderFromHwnd = nullptr; ++ PtrUiaRaiseAutomationPropertyChangedEvent m_pUiaRaiseAutomationPropertyChangedEvent = nullptr; ++ PtrUiaRaiseAutomationEvent m_pUiaRaiseAutomationEvent = nullptr; ++ PtrUiaRaiseNotificationEvent m_pUiaRaiseNotificationEvent = nullptr; ++ PtrUiaClientsAreListening m_pUiaClientsAreListening = nullptr; ++}; ++ ++QT_END_NAMESPACE ++ ++#endif //QWINDOWSUIAWRAPPER_H ++ +diff --git a/src/plugins/platforms/windows/vxkex.h b/src/plugins/platforms/windows/vxkex.h +new file mode 100644 +index 00000000000..6bbf2209f43 +--- /dev/null ++++ b/src/plugins/platforms/windows/vxkex.h +@@ -0,0 +1,426 @@ ++#pragma once ++ ++#include ++#include ++#include ++#include ++ ++#define MDT_MAXIMUM_DPI 3 ++ ++namespace vxkex { ++ ++static INT GetSystemMetricsForDpi( ++ IN INT Index, ++ IN UINT Dpi) ++{ ++ INT Value; ++ ++ Value = GetSystemMetrics(Index); ++ ++ switch (Index) { ++ case SM_CXVSCROLL: ++ case SM_CYHSCROLL: ++ case SM_CYCAPTION: ++ case SM_CYVTHUMB: ++ case SM_CXHTHUMB: ++ case SM_CXICON: ++ case SM_CYICON: ++ case SM_CXCURSOR: ++ case SM_CYCURSOR: ++ case SM_CYMENU: ++ case SM_CYVSCROLL: ++ case SM_CXHSCROLL: ++ case SM_CXMIN: ++ case SM_CXMINTRACK: ++ case SM_CYMIN: ++ case SM_CYMINTRACK: ++ case SM_CXSIZE: ++ case SM_CXFRAME: ++ case SM_CYFRAME: ++ case SM_CXICONSPACING: ++ case SM_CYICONSPACING: ++ case SM_CXSMICON: ++ case SM_CYSMICON: ++ case SM_CYSMCAPTION: ++ case SM_CXSMSIZE: ++ case SM_CYSMSIZE: ++ case SM_CXMENUSIZE: ++ case SM_CYMENUSIZE: ++ case SM_CXMENUCHECK: ++ case SM_CYMENUCHECK: ++ // These are pixel values that have to be scaled according to DPI. ++ Value *= Dpi; ++ Value /= USER_DEFAULT_SCREEN_DPI; ++ break; ++ } ++ ++ return Value; ++} ++ ++static BOOL SystemParametersInfoForDpi( ++ IN UINT Action, ++ IN UINT Parameter, ++ IN OUT PVOID Data, ++ IN UINT WinIni, ++ IN UINT Dpi) ++{ ++ switch (Action) { ++ case SPI_GETICONTITLELOGFONT: ++ return SystemParametersInfo(Action, Parameter, Data, 0); ++ case SPI_GETICONMETRICS: ++ { ++ BOOL Success; ++ PICONMETRICS IconMetrics; ++ ++ Success = SystemParametersInfo(Action, Parameter, Data, 0); ++ ++ if (Success) { ++ IconMetrics = (PICONMETRICS) Data; ++ ++ IconMetrics->iHorzSpacing *= Dpi; ++ IconMetrics->iVertSpacing *= Dpi; ++ IconMetrics->iHorzSpacing /= USER_DEFAULT_SCREEN_DPI; ++ IconMetrics->iVertSpacing /= USER_DEFAULT_SCREEN_DPI; ++ } ++ ++ return Success; ++ } ++ case SPI_GETNONCLIENTMETRICS: ++ { ++ BOOL Success; ++ PNONCLIENTMETRICS NonClientMetrics; ++ ++ Success = SystemParametersInfo(Action, Parameter, Data, 0); ++ ++ if (Success) { ++ NonClientMetrics = (PNONCLIENTMETRICS) Data; ++ ++ NonClientMetrics->iBorderWidth *= Dpi; ++ NonClientMetrics->iScrollWidth *= Dpi; ++ NonClientMetrics->iScrollHeight *= Dpi; ++ NonClientMetrics->iCaptionWidth *= Dpi; ++ NonClientMetrics->iCaptionHeight *= Dpi; ++ NonClientMetrics->iSmCaptionWidth *= Dpi; ++ NonClientMetrics->iSmCaptionHeight *= Dpi; ++ NonClientMetrics->iMenuWidth *= Dpi; ++ NonClientMetrics->iMenuHeight *= Dpi; ++ NonClientMetrics->iPaddedBorderWidth *= Dpi; ++ ++ NonClientMetrics->iBorderWidth /= USER_DEFAULT_SCREEN_DPI; ++ NonClientMetrics->iScrollWidth /= USER_DEFAULT_SCREEN_DPI; ++ NonClientMetrics->iScrollHeight /= USER_DEFAULT_SCREEN_DPI; ++ NonClientMetrics->iCaptionWidth /= USER_DEFAULT_SCREEN_DPI; ++ NonClientMetrics->iCaptionHeight /= USER_DEFAULT_SCREEN_DPI; ++ NonClientMetrics->iSmCaptionWidth /= USER_DEFAULT_SCREEN_DPI; ++ NonClientMetrics->iSmCaptionHeight /= USER_DEFAULT_SCREEN_DPI; ++ NonClientMetrics->iMenuWidth /= USER_DEFAULT_SCREEN_DPI; ++ NonClientMetrics->iMenuHeight /= USER_DEFAULT_SCREEN_DPI; ++ NonClientMetrics->iPaddedBorderWidth /= USER_DEFAULT_SCREEN_DPI; ++ } ++ ++ return Success; ++ } ++ default: ++ SetLastError(ERROR_INVALID_PARAMETER); ++ return FALSE; ++ } ++} ++ ++static HRESULT GetScaleFactorForMonitor( ++ IN HMONITOR Monitor, ++ OUT DEVICE_SCALE_FACTOR *ScaleFactor) ++{ ++ HDC DeviceContext; ++ ULONG LogPixelsX; ++ ++ DeviceContext = GetDC(NULL); ++ if (!DeviceContext) { ++ *ScaleFactor = SCALE_100_PERCENT; ++ return S_OK; ++ } ++ ++ LogPixelsX = GetDeviceCaps(DeviceContext, LOGPIXELSX); ++ ReleaseDC(NULL, DeviceContext); ++ ++ *ScaleFactor = (DEVICE_SCALE_FACTOR) (9600 / LogPixelsX); ++ return S_OK; ++} ++ ++static HRESULT GetDpiForMonitor( ++ IN HMONITOR Monitor, ++ IN MONITOR_DPI_TYPE DpiType, ++ OUT UINT * DpiX, ++ OUT UINT * DpiY) ++{ ++ HDC DeviceContext; ++ ++ if (DpiType >= MDT_MAXIMUM_DPI) { ++ return E_INVALIDARG; ++ } ++ ++ if (!DpiX || !DpiY) { ++ return E_INVALIDARG; ++ } ++ ++ if (!IsProcessDPIAware()) { ++ *DpiX = USER_DEFAULT_SCREEN_DPI; ++ *DpiY = USER_DEFAULT_SCREEN_DPI; ++ return S_OK; ++ } ++ ++ DeviceContext = GetDC(NULL); ++ if (!DeviceContext) { ++ *DpiX = USER_DEFAULT_SCREEN_DPI; ++ *DpiY = USER_DEFAULT_SCREEN_DPI; ++ return S_OK; ++ } ++ ++ *DpiX = GetDeviceCaps(DeviceContext, LOGPIXELSX); ++ *DpiY = GetDeviceCaps(DeviceContext, LOGPIXELSY); ++ ++ if (DpiType == MDT_EFFECTIVE_DPI) { ++ DEVICE_SCALE_FACTOR ScaleFactor; ++ ++ // We have to multiply the DPI values by the scaling factor. ++ vxkex::GetScaleFactorForMonitor(Monitor, &ScaleFactor); ++ ++ *DpiX *= ScaleFactor; ++ *DpiY *= ScaleFactor; ++ *DpiX /= 100; ++ *DpiY /= 100; ++ } ++ ++ ReleaseDC(NULL, DeviceContext); ++ return S_OK; ++} ++ ++static UINT GetDpiForSystem( ++ VOID) ++{ ++ HDC DeviceContext; ++ ULONG LogPixelsX; ++ ++ if (!IsProcessDPIAware()) { ++ return 96; ++ } ++ ++ DeviceContext = GetDC(NULL); ++ if (!DeviceContext) { ++ return 96; ++ } ++ ++ LogPixelsX = GetDeviceCaps(DeviceContext, LOGPIXELSX); ++ ReleaseDC(NULL, DeviceContext); ++ ++ return LogPixelsX; ++} ++ ++static UINT GetDpiForWindow( ++ IN HWND Window) ++{ ++ if (!IsWindow(Window)) { ++ return 0; ++ } ++ ++ return vxkex::GetDpiForSystem(); ++} ++ ++static BOOL AdjustWindowRectExForDpi( ++ IN OUT LPRECT Rect, ++ IN ULONG WindowStyle, ++ IN BOOL HasMenu, ++ IN ULONG WindowExStyle, ++ IN ULONG Dpi) ++{ ++ // I'm not sure how to implement this function properly. ++ // If it turns out to be important, I'll have to do some testing ++ // on a Win10 VM. ++ ++ return AdjustWindowRectEx( ++ Rect, ++ WindowStyle, ++ HasMenu, ++ WindowExStyle); ++} ++ ++static BOOL SetDisplayAutoRotationPreferences( ++ IN ORIENTATION_PREFERENCE Orientation) ++{ ++ return TRUE; ++} ++ ++static BOOL GetDisplayAutoRotationPreferences( ++ OUT ORIENTATION_PREFERENCE * Orientation) ++{ ++ *Orientation = ORIENTATION_PREFERENCE_NONE; ++ return TRUE; ++} ++ ++// scaling.c ++ ++static BOOL SetProcessDpiAwarenessContext( ++ IN DPI_AWARENESS_CONTEXT DpiContext) ++{ ++ if ((ULONG_PTR)DpiContext == (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE) { ++ //NOTHING; ++ } else if ((ULONG_PTR)DpiContext == (ULONG_PTR)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE || ++ (ULONG_PTR)DpiContext == (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE || ++ (ULONG_PTR)DpiContext == (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) { ++ SetProcessDPIAware(); ++ } else { ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++static BOOL AreDpiAwarenessContextsEqual( ++ IN DPI_AWARENESS_CONTEXT Value1, ++ IN DPI_AWARENESS_CONTEXT Value2) ++{ ++ return (Value1 == Value2); ++} ++ ++static BOOL IsValidDpiAwarenessContext( ++ IN DPI_AWARENESS_CONTEXT Value) ++{ ++ if ((ULONG_PTR)Value == (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE || ++ (ULONG_PTR)Value == (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED || ++ (ULONG_PTR)Value == (ULONG_PTR)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE || ++ (ULONG_PTR)Value == (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE || ++ (ULONG_PTR)Value == (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) { ++ return TRUE; ++ } else { ++ return FALSE; ++ } ++} ++ ++static BOOL EnableNonClientDpiScaling( ++ IN HWND Window) ++{ ++ return TRUE; ++} ++ ++static DPI_AWARENESS_CONTEXT GetThreadDpiAwarenessContext( ++ VOID) ++{ ++ if (IsProcessDPIAware()) { ++ return DPI_AWARENESS_CONTEXT_SYSTEM_AWARE; ++ } else { ++ return DPI_AWARENESS_CONTEXT_UNAWARE; ++ } ++} ++ ++static DPI_AWARENESS_CONTEXT GetWindowDpiAwarenessContext( ++ IN HWND Window) ++{ ++ ULONG WindowThreadId; ++ ULONG WindowProcessId; ++ ++ WindowThreadId = GetWindowThreadProcessId(Window, &WindowProcessId); ++ if (!WindowThreadId) { ++ return 0; ++ } ++ ++ // looks like there's a bug in vxkex, here should be == instead of = ++ // and if is always true ++ // anyway I don't want to deal with Windows kernel mode structures here ++ ++ if (1) { //if (WindowProcessId = (ULONG) NtCurrentTeb()->ClientId.UniqueProcess) { ++ return vxkex::GetThreadDpiAwarenessContext(); ++ } ++ ++ return DPI_AWARENESS_CONTEXT_UNAWARE; ++} ++ ++// pointer.c ++ ++static BOOL GetPointerType( ++ IN UINT32 PointerId, ++ OUT POINTER_INPUT_TYPE *PointerType) ++{ ++ *PointerType = PT_MOUSE; ++ return TRUE; ++} ++ ++static BOOL GetPointerFrameTouchInfo( ++ IN UINT32 PointerId, ++ IN OUT UINT32 *PointerCount, ++ OUT LPVOID TouchInfo) ++{ ++ return FALSE; ++} ++ ++static BOOL GetPointerFrameTouchInfoHistory( ++ IN UINT32 PointerId, ++ IN OUT UINT32 *EntriesCount, ++ IN OUT UINT32 *PointerCount, ++ OUT LPVOID TouchInfo) ++{ ++ return FALSE; ++} ++ ++static BOOL GetPointerPenInfo( ++ IN UINT32 PointerId, ++ OUT LPVOID PenInfo) ++{ ++ return FALSE; ++} ++ ++static BOOL GetPointerPenInfoHistory( ++ IN UINT32 PointerId, ++ IN OUT UINT32 *EntriesCount, ++ OUT LPVOID PenInfo) ++{ ++ return FALSE; ++} ++ ++static BOOL SkipPointerFrameMessages( ++ IN UINT32 PointerId) ++{ ++ return TRUE; ++} ++ ++static BOOL GetPointerDeviceRects( ++ IN HANDLE Device, ++ OUT LPRECT PointerDeviceRect, ++ OUT LPRECT DisplayRect) ++{ ++ PointerDeviceRect->top = 0; ++ PointerDeviceRect->left = 0; ++ PointerDeviceRect->bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN); ++ PointerDeviceRect->right = GetSystemMetrics(SM_CXVIRTUALSCREEN); ++ ++ DisplayRect->top = 0; ++ DisplayRect->left = 0; ++ DisplayRect->bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN); ++ DisplayRect->right = GetSystemMetrics(SM_CXVIRTUALSCREEN); ++ ++ return TRUE; ++} ++ ++static BOOL GetPointerInfo( ++ IN DWORD PointerId, ++ OUT POINTER_INFO *PointerInfo) ++{ ++ PointerInfo->pointerType = PT_MOUSE; ++ PointerInfo->pointerId = PointerId; ++ PointerInfo->frameId = 0; ++ PointerInfo->pointerFlags = POINTER_FLAG_NONE; ++ PointerInfo->sourceDevice = NULL; ++ PointerInfo->hwndTarget = NULL; ++ GetCursorPos(&PointerInfo->ptPixelLocation); ++ GetCursorPos(&PointerInfo->ptHimetricLocation); ++ GetCursorPos(&PointerInfo->ptPixelLocationRaw); ++ GetCursorPos(&PointerInfo->ptHimetricLocationRaw); ++ PointerInfo->dwTime = 0; ++ PointerInfo->historyCount = 1; ++ PointerInfo->InputData = 0; ++ PointerInfo->dwKeyStates = 0; ++ PointerInfo->PerformanceCount = 0; ++ PointerInfo->ButtonChangeType = POINTER_CHANGE_NONE; ++ ++ return TRUE; ++} ++ ++} // namespace vxkex +diff --git a/src/widgets/styles/qwindowsstyle.cpp b/src/widgets/styles/qwindowsstyle.cpp +index a8407add019..a8097330210 100644 +--- a/src/widgets/styles/qwindowsstyle.cpp ++++ b/src/widgets/styles/qwindowsstyle.cpp +@@ -59,6 +59,10 @@ + + #include + ++#if defined(Q_OS_WIN) ++#include "../../plugins/platforms/windows/vxkex.h" ++#endif ++ + QT_BEGIN_NAMESPACE + + #if defined(Q_OS_WIN) +@@ -254,6 +258,11 @@ void QWindowsStyle::polish(QPalette &pal) + QCommonStyle::polish(pal); + } + ++#if defined(Q_OS_WIN) ++typedef BOOL (WINAPI *GetSystemMetricsForDpiFunc)(int, UINT); ++typedef BOOL (WINAPI *SystemParametersInfoForDpiFunc)(UINT, UINT, PVOID, UINT, UINT); ++#endif ++ + int QWindowsStylePrivate::pixelMetricFromSystemDp(QStyle::PixelMetric pm, const QStyleOption *, const QWidget *widget) + { + #if defined(Q_OS_WIN) +@@ -261,29 +270,43 @@ int QWindowsStylePrivate::pixelMetricFromSystemDp(QStyle::PixelMetric pm, const + // hardcode DPI to 1x 96 DPI. + const int dpi = 96; + ++ static GetSystemMetricsForDpiFunc myGetSystemMetricsForDpi = ++ (GetSystemMetricsForDpiFunc)::GetProcAddress(::GetModuleHandle(L"User32"), "GetSystemMetricsForDpi"); ++ ++ static SystemParametersInfoForDpiFunc mySystemParametersInfoForDpi = ++ (SystemParametersInfoForDpiFunc)::GetProcAddress(::GetModuleHandle(L"User32"), "SystemParametersInfoForDpi"); ++ + switch (pm) { + case QStyle::PM_DockWidgetFrameWidth: +- return GetSystemMetricsForDpi(SM_CXFRAME, dpi); ++ return myGetSystemMetricsForDpi ? myGetSystemMetricsForDpi(SM_CXFRAME, dpi) : vxkex::GetSystemMetricsForDpi(SM_CXFRAME, dpi); + + case QStyle::PM_TitleBarHeight: { +- const int resizeBorderThickness = +- GetSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) + GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi); ++ const int resizeBorderThickness = myGetSystemMetricsForDpi ? ++ (myGetSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) + myGetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi)) : ++ (vxkex::GetSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) + vxkex::GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi)) ; + if (widget && (widget->windowType() == Qt::Tool)) +- return GetSystemMetricsForDpi(SM_CYSMCAPTION, dpi) + resizeBorderThickness; +- return GetSystemMetricsForDpi(SM_CYCAPTION, dpi) + resizeBorderThickness; ++ return myGetSystemMetricsForDpi ? ++ (myGetSystemMetricsForDpi(SM_CYSMCAPTION, dpi) + resizeBorderThickness) : ++ (vxkex::GetSystemMetricsForDpi(SM_CYSMCAPTION, dpi) + resizeBorderThickness); ++ return myGetSystemMetricsForDpi ? ++ (myGetSystemMetricsForDpi(SM_CYCAPTION, dpi) + resizeBorderThickness) : ++ (vxkex::GetSystemMetricsForDpi(SM_CYCAPTION, dpi) + resizeBorderThickness); + } + + case QStyle::PM_ScrollBarExtent: + { + NONCLIENTMETRICS ncm; + ncm.cbSize = sizeof(NONCLIENTMETRICS); +- if (SystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0, dpi)) ++ BOOL bResult = mySystemParametersInfoForDpi ++ ? mySystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0, dpi) ++ : vxkex::SystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0, dpi); ++ if (bResult) + return qMax(ncm.iScrollHeight, ncm.iScrollWidth); + } + break; + + case QStyle::PM_MdiSubWindowFrameWidth: +- return GetSystemMetricsForDpi(SM_CYFRAME, dpi); ++ return myGetSystemMetricsForDpi ? myGetSystemMetricsForDpi(SM_CYFRAME, dpi) : vxkex::GetSystemMetricsForDpi(SM_CYFRAME, dpi); + + default: + break;