diff --git a/src/corelib/kernel/qfunctions_winrt_p.h b/src/corelib/kernel/qfunctions_winrt_p.h index c895733c935..6c406961fd6 100644 --- a/src/corelib/kernel/qfunctions_winrt_p.h +++ b/src/corelib/kernel/qfunctions_winrt_p.h @@ -24,8 +24,8 @@ #include #include #include +#include -#include #include // Convenience macros for handling HRESULT values @@ -68,10 +68,10 @@ enum AwaitStyle using EarlyExitConditionFunction = std::function; template -static inline HRESULT _await_impl(const Microsoft::WRL::ComPtr &asyncOp, AwaitStyle awaitStyle, - uint timeout, EarlyExitConditionFunction func) +static inline HRESULT _await_impl(const ComPtr &asyncOp, AwaitStyle awaitStyle, uint timeout, + EarlyExitConditionFunction func) { - Microsoft::WRL::ComPtr asyncInfo; + ComPtr asyncInfo; HRESULT hr = asyncOp.As(&asyncInfo); if (FAILED(hr)) return hr; @@ -127,9 +127,8 @@ static inline HRESULT _await_impl(const Microsoft::WRL::ComPtr &asyncOp, Awai } template -static inline HRESULT await(const Microsoft::WRL::ComPtr &asyncOp, - AwaitStyle awaitStyle = YieldThread, uint timeout = 0, - EarlyExitConditionFunction func = nullptr) +static inline HRESULT await(const ComPtr &asyncOp, AwaitStyle awaitStyle = YieldThread, + uint timeout = 0, EarlyExitConditionFunction func = nullptr) { HRESULT hr = _await_impl(asyncOp, awaitStyle, timeout, func); if (FAILED(hr)) @@ -139,7 +138,7 @@ static inline HRESULT await(const Microsoft::WRL::ComPtr &asyncOp, } template -static inline HRESULT await(const Microsoft::WRL::ComPtr &asyncOp, U *results, +static inline HRESULT await(const ComPtr &asyncOp, U *results, AwaitStyle awaitStyle = YieldThread, uint timeout = 0, EarlyExitConditionFunction func = nullptr) { diff --git a/src/corelib/platform/windows/qcomptr_p.h b/src/corelib/platform/windows/qcomptr_p.h index 7ee286d254e..2a69e7b6038 100644 --- a/src/corelib/platform/windows/qcomptr_p.h +++ b/src/corelib/platform/windows/qcomptr_p.h @@ -16,11 +16,136 @@ // #include - +#include +#include #if defined(Q_OS_WIN) || defined(Q_QDOC) +// clang-format off #include #include +// clang-format on + +QT_BEGIN_NAMESPACE + +namespace Detail { + +template +struct has_equal_to_operator : std::false_type +{ +}; + +template +struct has_equal_to_operator< + T, U, std::void_t(), std::declval()))>> + : std::true_type +{ +}; + +template +using EnableIfMissingEqualToOperator = std::enable_if_t::value, bool>; + +template +struct has_not_equal_to_operator : std::false_type +{ +}; + +template +struct has_not_equal_to_operator< + T, U, std::void_t(), std::declval()))>> + : std::true_type +{ +}; + +template +using EnableIfMissingNotEqualToOperator = + std::enable_if_t::value, bool>; + +template +struct has_less_than_operator : std::false_type +{ +}; + +template +struct has_less_than_operator< + T, U, std::void_t(), std::declval()))>> + : std::true_type +{ +}; + +template +using EnableIfMissingLessThanOperator = + std::enable_if_t::value, bool>; + +} // namespace Detail + +QT_END_NAMESPACE + +namespace Microsoft { +namespace WRL { + +// Add missing comparison operators if MINGW does not provide them + +template , ComPtr> = true> +bool operator==(const ComPtr &lhs, const ComPtr &rhs) noexcept +{ + static_assert(std::is_base_of_v || std::is_base_of_v); + return lhs.Get() == rhs.Get(); +} + +template , std::nullptr_t> = + true> +bool operator==(const ComPtr &lhs, std::nullptr_t) noexcept +{ + return lhs.Get() == nullptr; +} + +template > = + true> +bool operator==(std::nullptr_t, const ComPtr &rhs) noexcept +{ + return rhs.Get() == nullptr; +} + +template , ComPtr> = + true> +bool operator!=(const ComPtr &a, const ComPtr &b) noexcept +{ + static_assert(std::is_base_of_v || std::is_base_of_v); + return a.Get() != b.Get(); +} + +template , std::nullptr_t> = true> +bool operator!=(const ComPtr &a, std::nullptr_t) noexcept +{ + return a.Get() != nullptr; +} + +template > = true> +bool operator!=(std::nullptr_t, const ComPtr &a) noexcept +{ + return a.Get() != nullptr; +} + +// MSVC WRL only defines operator<, we do not add other variants such as <=, > or >= +template < + class T, class U, + QT_PREPEND_NAMESPACE(Detail)::EnableIfMissingLessThanOperator, ComPtr> = true> +bool operator<(const ComPtr &a, const ComPtr &b) noexcept +{ + static_assert(std::is_base_of_v || std::is_base_of_v); + return a.Get() < b.Get(); +} + +} // namespace WRL +} // namespace Microsoft QT_BEGIN_NAMESPACE diff --git a/src/network/kernel/qnetconmonitor_win.cpp b/src/network/kernel/qnetconmonitor_win.cpp index bf6aff1e468..76299e9a025 100644 --- a/src/network/kernel/qnetconmonitor_win.cpp +++ b/src/network/kernel/qnetconmonitor_win.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h index d91cd8a4cc6..1bfe33e91ce 100644 --- a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h +++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #if QT_CONFIG(cpp_winrt) diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp index 310053eedc3..8f9812e41e4 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp @@ -6,13 +6,10 @@ #include "qwindowsdirect2dhelpers.h" #include "qwindowsdirect2ddevicecontext.h" +#include #include #include -#include - -using Microsoft::WRL::ComPtr; - QT_BEGIN_NAMESPACE class QWindowsDirect2DBitmapPrivate diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp index 307ca2e550d..a955137cfd6 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp @@ -6,15 +6,14 @@ #include "qwindowsdirect2dhelpers.h" #include "qwindowsdirect2dintegration.h" +#include + #include #include #include #include -#include #include -using Microsoft::WRL::ComPtr; - QT_BEGIN_NAMESPACE class QWindowsDirect2DContextPrivate diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp index 2eb6e2c36d1..268a6f0188f 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp @@ -5,9 +5,7 @@ #include "qwindowsdirect2dhelpers.h" #include "qwindowsdirect2ddevicecontext.h" -#include - -using Microsoft::WRL::ComPtr; +#include QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp index bc304f78be9..2e80c121920 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -22,9 +23,6 @@ #include #include -#include - -using Microsoft::WRL::ComPtr; QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h index bb7d406a337..0d6bd8bd96d 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h @@ -5,7 +5,7 @@ #define QWINDOWSDIRECT2DWINDOW_H #include "qwindowswindow.h" -#include +#include struct IDXGISwapChain1; struct ID2D1DeviceContext; @@ -34,8 +34,8 @@ private: void setupBitmap(); private: - Microsoft::WRL::ComPtr m_swapChain; - Microsoft::WRL::ComPtr m_deviceContext; + ComPtr m_swapChain; + ComPtr m_deviceContext; QScopedPointer m_bitmap; QScopedPointer m_pixmap; bool m_needsFullFlush = true; diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index a9fcf711edd..25c15861ba1 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -50,8 +50,7 @@ #include #include - -#include +#include #include @@ -721,8 +720,6 @@ void QWindowsIntegration::setApplicationBadge(const QImage &image) { QComHelper comHelper; - using Microsoft::WRL::ComPtr; - ComPtr taskbarList; CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&taskbarList)); diff --git a/tests/auto/corelib/platform/windows/CMakeLists.txt b/tests/auto/corelib/platform/windows/CMakeLists.txt index 2c6d6e9ffee..abcb17471c9 100644 --- a/tests/auto/corelib/platform/windows/CMakeLists.txt +++ b/tests/auto/corelib/platform/windows/CMakeLists.txt @@ -3,4 +3,5 @@ add_subdirectory(qcomobject) add_subdirectory(qbstr) +add_subdirectory(qcomptr) add_subdirectory(qcomvariant) diff --git a/tests/auto/corelib/platform/windows/qcomptr/CMakeLists.txt b/tests/auto/corelib/platform/windows/qcomptr/CMakeLists.txt new file mode 100644 index 00000000000..5530f98a0f6 --- /dev/null +++ b/tests/auto/corelib/platform/windows/qcomptr/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## tst_qcomptr Test: +##################################################################### + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qcomptr LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qcomptr + SOURCES + tst_qcomptr.cpp + LIBRARIES + Qt::CorePrivate +) diff --git a/tests/auto/corelib/platform/windows/qcomptr/tst_qcomptr.cpp b/tests/auto/corelib/platform/windows/qcomptr/tst_qcomptr.cpp new file mode 100644 index 00000000000..219438af620 --- /dev/null +++ b/tests/auto/corelib/platform/windows/qcomptr/tst_qcomptr.cpp @@ -0,0 +1,143 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include +#include +#include + +MIDL_INTERFACE("8B06D1DA-94F2-45A5-9E86-77E89A51FAC7") +IMyInterface : IUnknown{}; + +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IMyInterface, 0x8b06d1da, 0x94f2, 0x45a5, 0x9e, 0x86, 0x77, 0xe8, 0x9a, 0x51, 0xfa, + 0xc7); +#endif + +QT_USE_NAMESPACE + +class IMyInterfaceImpl : public QComObject +{ +}; + +qsizetype s_instanceCount = 0; + +class IUnknownImpl : public QComObject +{ +public: + IUnknownImpl() + { // + ++s_instanceCount; + } + + ~IUnknownImpl() + { // + --s_instanceCount; + } +}; + +class IDispatchImpl : public QComObject +{ +public: + HRESULT GetTypeInfoCount(UINT *) override { return E_FAIL; } + HRESULT GetTypeInfo(UINT, LCID, ITypeInfo **) override { return E_FAIL; } + HRESULT GetIDsOfNames(const IID &, LPOLESTR *, UINT, LCID, DISPID *) override { return E_FAIL; } + HRESULT Invoke(DISPID, const IID &, LCID, WORD, DISPPARAMS *, VARIANT *, EXCEPINFO *, + UINT *) override + { + return E_FAIL; + } +}; + +class tst_qcomptr : public QObject +{ + Q_OBJECT +private slots: + void makeComObject_createsComObject() + { + // See bug report https://sourceforge.net/p/mingw-w64/bugs/892/ + { + ComPtr o = makeComObject(); + QCOMPARE_EQ(o->AddRef(), 2ul); + QCOMPARE_EQ(o->Release(), 1ul); + QVERIFY(o); + } + QCOMPARE_EQ(s_instanceCount, 0); + } + + void comparison_returnsTrue_withEqualInstances() + { + { + // MINGW may lack comparison operator + ComPtr o1 = makeComObject(); + ComPtr o2 = o1; + QCOMPARE_EQ(o1, o2); + QVERIFY(!(o1 != o2)); + } + { + //ComPtr o1 = makeComObject(); + //ComPtr o2 = makeComObject(); + //QVERIFY(!(o1 == o2)); // Intentionally fails to compile + } + } + + void comparison_returnsFalse_withUnequalInstances() + { + // MINGW may lack comparison operator + { + ComPtr o1 = makeComObject(); + ComPtr o2 = makeComObject(); + QCOMPARE_NE(o1, o2); + QVERIFY(!(o1 == o2)); + } + { + ComPtr o1 = makeComObject(); + ComPtr o2 = makeComObject(); + QCOMPARE_NE(o1, o2); + QVERIFY(!(o1 == o2)); + } + { + //ComPtr o1 = makeComObject(); + //ComPtr o2 = makeComObject(); + //QCOMPARE_NE(o1, o2); // Intentionally fails to compile + } + } + + void comparison_returnsTrue_whenComparingNullWithNullptr() + { + // MINGW may lack comparison operator + ComPtr o; + QCOMPARE_EQ(o, nullptr); + QCOMPARE_EQ(nullptr, o); + } + + void comparison_returnsTrue_whenComparingNotNullWithNullptr() + { + // MINGW may lack comparison operator + ComPtr o = makeComObject(); + QCOMPARE_NE(o, nullptr); + QCOMPARE_NE(nullptr, o); + } + + void lessThan_returnsEqualToRawPointerComparison() + { + // MINGW may lack comparison operator + { + ComPtr o1 = makeComObject(); + ComPtr o2 = makeComObject(); + QCOMPARE_EQ(o1 < o2, o1.Get() < o2.Get()); + } + { + ComPtr o1 = makeComObject(); + ComPtr o2 = makeComObject(); + QCOMPARE_EQ(o1 < o2, o1.Get() < o2.Get()); + } + { + //ComPtr o1 = makeComObject(); + //ComPtr o2 = makeComObject(); + //QCOMPARE_EQ(o1 < o2, o1.Get() < o2.Get()); // Intentionally fails to compile + } + } +}; + +QTEST_MAIN(tst_qcomptr) +#include "tst_qcomptr.moc" diff --git a/tests/auto/corelib/platform/windows/qcomvariant/tst_qcomvariant.cpp b/tests/auto/corelib/platform/windows/qcomvariant/tst_qcomvariant.cpp index 1e781101a85..01d12881f62 100644 --- a/tests/auto/corelib/platform/windows/qcomvariant/tst_qcomvariant.cpp +++ b/tests/auto/corelib/platform/windows/qcomvariant/tst_qcomvariant.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include using Microsoft::WRL::ComPtr;