Add missing comparison operators for Microsoft::WRL::ComPtr on MINGW
MINGW's implementation of Microsoft::WRL::ComPtr lacks comparison operators, and calling operator==() on them will implicitly convert them to bool before comparing the resulting bool values. Two non-zero ComPtr instances will therefore always compare equal, even if they point to different interfaces. This patch adds ComPtr comparison operators if they are missing, and replaces existing includes to wrl.h or wrl/client.h with QtCore/private/qcomptr_p.h Pick-to: 6.8 Change-Id: I8123d9d874ae53ebfd6d381b69097e75527848b6 Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io> (cherry picked from commit 6d1384034deb681c1c4a656a1582f3e1606b1c1a) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
d7e2d6b22c
commit
69cdf3cbbb
@ -24,8 +24,8 @@
|
||||
#include <QtCore/QAbstractEventDispatcher>
|
||||
#include <QtCore/QElapsedTimer>
|
||||
#include <QtCore/qt_windows.h>
|
||||
#include <QtCore/private/qcomptr_p.h>
|
||||
|
||||
#include <wrl.h>
|
||||
#include <windows.foundation.h>
|
||||
|
||||
// Convenience macros for handling HRESULT values
|
||||
@ -68,10 +68,10 @@ enum AwaitStyle
|
||||
using EarlyExitConditionFunction = std::function<bool(void)>;
|
||||
|
||||
template<typename T>
|
||||
static inline HRESULT _await_impl(const Microsoft::WRL::ComPtr<T> &asyncOp, AwaitStyle awaitStyle,
|
||||
uint timeout, EarlyExitConditionFunction func)
|
||||
static inline HRESULT _await_impl(const ComPtr<T> &asyncOp, AwaitStyle awaitStyle, uint timeout,
|
||||
EarlyExitConditionFunction func)
|
||||
{
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
|
||||
ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
|
||||
HRESULT hr = asyncOp.As(&asyncInfo);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
@ -127,9 +127,8 @@ static inline HRESULT _await_impl(const Microsoft::WRL::ComPtr<T> &asyncOp, Awai
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline HRESULT await(const Microsoft::WRL::ComPtr<T> &asyncOp,
|
||||
AwaitStyle awaitStyle = YieldThread, uint timeout = 0,
|
||||
EarlyExitConditionFunction func = nullptr)
|
||||
static inline HRESULT await(const ComPtr<T> &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<T> &asyncOp,
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
static inline HRESULT await(const Microsoft::WRL::ComPtr<T> &asyncOp, U *results,
|
||||
static inline HRESULT await(const ComPtr<T> &asyncOp, U *results,
|
||||
AwaitStyle awaitStyle = YieldThread, uint timeout = 0,
|
||||
EarlyExitConditionFunction func = nullptr)
|
||||
{
|
||||
|
@ -16,11 +16,136 @@
|
||||
//
|
||||
|
||||
#include <QtCore/private/qglobal_p.h>
|
||||
|
||||
#include <QtCore/qtconfigmacros.h>
|
||||
#include <type_traits>
|
||||
#if defined(Q_OS_WIN) || defined(Q_QDOC)
|
||||
|
||||
// clang-format off
|
||||
#include <QtCore/qt_windows.h>
|
||||
#include <wrl/client.h>
|
||||
// clang-format on
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace Detail {
|
||||
|
||||
template <typename, typename, typename = void>
|
||||
struct has_equal_to_operator : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
struct has_equal_to_operator<
|
||||
T, U, std::void_t<decltype(operator==(std::declval<T>(), std::declval<U>()))>>
|
||||
: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
using EnableIfMissingEqualToOperator = std::enable_if_t<!has_equal_to_operator<T, U>::value, bool>;
|
||||
|
||||
template <typename, typename, typename = void>
|
||||
struct has_not_equal_to_operator : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
struct has_not_equal_to_operator<
|
||||
T, U, std::void_t<decltype(operator!=(std::declval<T>(), std::declval<U>()))>>
|
||||
: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
using EnableIfMissingNotEqualToOperator =
|
||||
std::enable_if_t<!has_not_equal_to_operator<T, U>::value, bool>;
|
||||
|
||||
template <typename, typename, typename = void>
|
||||
struct has_less_than_operator : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
struct has_less_than_operator<
|
||||
T, U, std::void_t<decltype(operator<(std::declval<T>(), std::declval<U>()))>>
|
||||
: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
using EnableIfMissingLessThanOperator =
|
||||
std::enable_if_t<!has_less_than_operator<T, U>::value, bool>;
|
||||
|
||||
} // namespace Detail
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Microsoft {
|
||||
namespace WRL {
|
||||
|
||||
// Add missing comparison operators if MINGW does not provide them
|
||||
|
||||
template <typename T, typename U,
|
||||
QT_PREPEND_NAMESPACE(Detail)::EnableIfMissingEqualToOperator<ComPtr<T>, ComPtr<U>> = true>
|
||||
bool operator==(const ComPtr<T> &lhs, const ComPtr<U> &rhs) noexcept
|
||||
{
|
||||
static_assert(std::is_base_of_v<T, U> || std::is_base_of_v<U, T>);
|
||||
return lhs.Get() == rhs.Get();
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
QT_PREPEND_NAMESPACE(Detail)::EnableIfMissingEqualToOperator<ComPtr<T>, std::nullptr_t> =
|
||||
true>
|
||||
bool operator==(const ComPtr<T> &lhs, std::nullptr_t) noexcept
|
||||
{
|
||||
return lhs.Get() == nullptr;
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
QT_PREPEND_NAMESPACE(Detail)::EnableIfMissingEqualToOperator<std::nullptr_t, ComPtr<T>> =
|
||||
true>
|
||||
bool operator==(std::nullptr_t, const ComPtr<T> &rhs) noexcept
|
||||
{
|
||||
return rhs.Get() == nullptr;
|
||||
}
|
||||
|
||||
template <typename T, typename U,
|
||||
QT_PREPEND_NAMESPACE(Detail)::EnableIfMissingNotEqualToOperator<ComPtr<T>, ComPtr<U>> =
|
||||
true>
|
||||
bool operator!=(const ComPtr<T> &a, const ComPtr<U> &b) noexcept
|
||||
{
|
||||
static_assert(std::is_base_of_v<T, U> || std::is_base_of_v<U, T>);
|
||||
return a.Get() != b.Get();
|
||||
}
|
||||
|
||||
template <class T,
|
||||
QT_PREPEND_NAMESPACE(
|
||||
Detail)::EnableIfMissingNotEqualToOperator<ComPtr<T>, std::nullptr_t> = true>
|
||||
bool operator!=(const ComPtr<T> &a, std::nullptr_t) noexcept
|
||||
{
|
||||
return a.Get() != nullptr;
|
||||
}
|
||||
|
||||
template <class T,
|
||||
QT_PREPEND_NAMESPACE(
|
||||
Detail)::EnableIfMissingNotEqualToOperator<std::nullptr_t, ComPtr<T>> = true>
|
||||
bool operator!=(std::nullptr_t, const ComPtr<T> &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<T>, ComPtr<U>> = true>
|
||||
bool operator<(const ComPtr<T> &a, const ComPtr<U> &b) noexcept
|
||||
{
|
||||
static_assert(std::is_base_of_v<T, U> || std::is_base_of_v<U, T>);
|
||||
return a.Get() < b.Get();
|
||||
}
|
||||
|
||||
} // namespace WRL
|
||||
} // namespace Microsoft
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
#include <objbase.h>
|
||||
#include <netlistmgr.h>
|
||||
#include <wrl/client.h>
|
||||
#include <QtCore/private/qcomptr_p.h>
|
||||
#include <wrl/wrappers/corewrappers.h>
|
||||
#include <iphlpapi.h>
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include <objbase.h>
|
||||
#include <ocidl.h>
|
||||
#include <netlistmgr.h>
|
||||
#include <wrl/client.h>
|
||||
#include <QtCore/private/qcomptr_p.h>
|
||||
#include <wrl/wrappers/corewrappers.h>
|
||||
|
||||
#if QT_CONFIG(cpp_winrt)
|
||||
|
@ -6,13 +6,10 @@
|
||||
#include "qwindowsdirect2dhelpers.h"
|
||||
#include "qwindowsdirect2ddevicecontext.h"
|
||||
|
||||
#include <QtCore/private/qcomptr_p.h>
|
||||
#include <QtGui/qimage.h>
|
||||
#include <QtGui/qcolor.h>
|
||||
|
||||
#include <wrl.h>
|
||||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QWindowsDirect2DBitmapPrivate
|
||||
|
@ -6,15 +6,14 @@
|
||||
#include "qwindowsdirect2dhelpers.h"
|
||||
#include "qwindowsdirect2dintegration.h"
|
||||
|
||||
#include <QtCore/private/qcomptr_p.h>
|
||||
|
||||
#include <d3d11_1.h>
|
||||
#include <d2d1_1.h>
|
||||
#include <d2d1_1helper.h>
|
||||
#include <dxgi1_2.h>
|
||||
#include <wrl.h>
|
||||
#include <dwrite.h>
|
||||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QWindowsDirect2DContextPrivate
|
||||
|
@ -5,9 +5,7 @@
|
||||
#include "qwindowsdirect2dhelpers.h"
|
||||
#include "qwindowsdirect2ddevicecontext.h"
|
||||
|
||||
#include <wrl.h>
|
||||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
#include <QtCore/private/qcomptr_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <QtCore/qmath.h>
|
||||
#include <QtCore/qstack.h>
|
||||
#include <QtCore/qsettings.h>
|
||||
#include <QtCore/private/qcomptr_p.h>
|
||||
#include <QtGui/private/qpaintengine_p.h>
|
||||
#include <QtGui/private/qtextengine_p.h>
|
||||
#include <QtGui/private/qfontengine_p.h>
|
||||
@ -22,9 +23,6 @@
|
||||
|
||||
#include <d2d1_1.h>
|
||||
#include <dwrite_1.h>
|
||||
#include <wrl.h>
|
||||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
#define QWINDOWSDIRECT2DWINDOW_H
|
||||
|
||||
#include "qwindowswindow.h"
|
||||
#include <wrl.h>
|
||||
#include <QtCore/private/qcomptr_p.h>
|
||||
|
||||
struct IDXGISwapChain1;
|
||||
struct ID2D1DeviceContext;
|
||||
@ -34,8 +34,8 @@ private:
|
||||
void setupBitmap();
|
||||
|
||||
private:
|
||||
Microsoft::WRL::ComPtr<IDXGISwapChain1> m_swapChain;
|
||||
Microsoft::WRL::ComPtr<ID2D1DeviceContext> m_deviceContext;
|
||||
ComPtr<IDXGISwapChain1> m_swapChain;
|
||||
ComPtr<ID2D1DeviceContext> m_deviceContext;
|
||||
QScopedPointer<QWindowsDirect2DBitmap> m_bitmap;
|
||||
QScopedPointer<QPixmap> m_pixmap;
|
||||
bool m_needsFullFlush = true;
|
||||
|
@ -50,8 +50,7 @@
|
||||
|
||||
#include <QtCore/qoperatingsystemversion.h>
|
||||
#include <QtCore/private/qfunctions_win_p.h>
|
||||
|
||||
#include <wrl.h>
|
||||
#include <QtCore/private/qcomptr_p.h>
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
@ -721,8 +720,6 @@ void QWindowsIntegration::setApplicationBadge(const QImage &image)
|
||||
{
|
||||
QComHelper comHelper;
|
||||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
ComPtr<ITaskbarList3> taskbarList;
|
||||
CoCreateInstance(CLSID_TaskbarList, nullptr,
|
||||
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&taskbarList));
|
||||
|
@ -3,4 +3,5 @@
|
||||
|
||||
add_subdirectory(qcomobject)
|
||||
add_subdirectory(qbstr)
|
||||
add_subdirectory(qcomptr)
|
||||
add_subdirectory(qcomvariant)
|
||||
|
19
tests/auto/corelib/platform/windows/qcomptr/CMakeLists.txt
Normal file
19
tests/auto/corelib/platform/windows/qcomptr/CMakeLists.txt
Normal file
@ -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
|
||||
)
|
143
tests/auto/corelib/platform/windows/qcomptr/tst_qcomptr.cpp
Normal file
143
tests/auto/corelib/platform/windows/qcomptr/tst_qcomptr.cpp
Normal file
@ -0,0 +1,143 @@
|
||||
// Copyright (C) 2025 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#include <QtTest/qtest.h>
|
||||
#include <QtCore/private/qcomptr_p.h>
|
||||
#include <QtCore/private/qcomobject_p.h>
|
||||
|
||||
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<IMyInterface>
|
||||
{
|
||||
};
|
||||
|
||||
qsizetype s_instanceCount = 0;
|
||||
|
||||
class IUnknownImpl : public QComObject<IUnknown>
|
||||
{
|
||||
public:
|
||||
IUnknownImpl()
|
||||
{ //
|
||||
++s_instanceCount;
|
||||
}
|
||||
|
||||
~IUnknownImpl()
|
||||
{ //
|
||||
--s_instanceCount;
|
||||
}
|
||||
};
|
||||
|
||||
class IDispatchImpl : public QComObject<IDispatch>
|
||||
{
|
||||
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<IUnknown> o = makeComObject<IUnknownImpl>();
|
||||
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<IUnknown> o1 = makeComObject<IUnknownImpl>();
|
||||
ComPtr<IUnknown> o2 = o1;
|
||||
QCOMPARE_EQ(o1, o2);
|
||||
QVERIFY(!(o1 != o2));
|
||||
}
|
||||
{
|
||||
//ComPtr<IMyInterface> o1 = makeComObject<IMyInterfaceImpl>();
|
||||
//ComPtr<IDispatch> o2 = makeComObject<IDispatchImpl>();
|
||||
//QVERIFY(!(o1 == o2)); // Intentionally fails to compile
|
||||
}
|
||||
}
|
||||
|
||||
void comparison_returnsFalse_withUnequalInstances()
|
||||
{
|
||||
// MINGW may lack comparison operator
|
||||
{
|
||||
ComPtr<IUnknown> o1 = makeComObject<IUnknownImpl>();
|
||||
ComPtr<IUnknown> o2 = makeComObject<IUnknownImpl>();
|
||||
QCOMPARE_NE(o1, o2);
|
||||
QVERIFY(!(o1 == o2));
|
||||
}
|
||||
{
|
||||
ComPtr<IUnknown> o1 = makeComObject<IUnknownImpl>();
|
||||
ComPtr<IMyInterface> o2 = makeComObject<IMyInterfaceImpl>();
|
||||
QCOMPARE_NE(o1, o2);
|
||||
QVERIFY(!(o1 == o2));
|
||||
}
|
||||
{
|
||||
//ComPtr<IMyInterface> o1 = makeComObject<IMyInterfaceImpl>();
|
||||
//ComPtr<IDispatch> o2 = makeComObject<IDispatchImpl>();
|
||||
//QCOMPARE_NE(o1, o2); // Intentionally fails to compile
|
||||
}
|
||||
}
|
||||
|
||||
void comparison_returnsTrue_whenComparingNullWithNullptr()
|
||||
{
|
||||
// MINGW may lack comparison operator
|
||||
ComPtr<IUnknown> o;
|
||||
QCOMPARE_EQ(o, nullptr);
|
||||
QCOMPARE_EQ(nullptr, o);
|
||||
}
|
||||
|
||||
void comparison_returnsTrue_whenComparingNotNullWithNullptr()
|
||||
{
|
||||
// MINGW may lack comparison operator
|
||||
ComPtr<IUnknown> o = makeComObject<IUnknownImpl>();
|
||||
QCOMPARE_NE(o, nullptr);
|
||||
QCOMPARE_NE(nullptr, o);
|
||||
}
|
||||
|
||||
void lessThan_returnsEqualToRawPointerComparison()
|
||||
{
|
||||
// MINGW may lack comparison operator
|
||||
{
|
||||
ComPtr<IUnknown> o1 = makeComObject<IUnknownImpl>();
|
||||
ComPtr<IUnknown> o2 = makeComObject<IUnknownImpl>();
|
||||
QCOMPARE_EQ(o1 < o2, o1.Get() < o2.Get());
|
||||
}
|
||||
{
|
||||
ComPtr<IUnknown> o1 = makeComObject<IUnknownImpl>();
|
||||
ComPtr<IMyInterface> o2 = makeComObject<IMyInterfaceImpl>();
|
||||
QCOMPARE_EQ(o1 < o2, o1.Get() < o2.Get());
|
||||
}
|
||||
{
|
||||
//ComPtr<IMyInterface> o1 = makeComObject<IMyInterfaceImpl>();
|
||||
//ComPtr<IDispatch> o2 = makeComObject<IDispatchImpl>();
|
||||
//QCOMPARE_EQ(o1 < o2, o1.Get() < o2.Get()); // Intentionally fails to compile
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_qcomptr)
|
||||
#include "tst_qcomptr.moc"
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include <private/qcomvariant_p.h>
|
||||
#include <private/qcomobject_p.h>
|
||||
#include <wrl/client.h>
|
||||
#include <QtCore/private/qcomptr_p.h>
|
||||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user