Teach QWinRegistryKey to observe changes to the key
In some cases there are no explicit notification APIs for changes to system settings, and the developer is expected to observe changes to the registry keys directly. For example this applies to color profile associations, as documented in: https://learn.microsoft.com/en-us/windows/win32/wcs/wcs-registry-keys Change-Id: I3507058d90b1d32b8b5256f40861126277242cd6 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
e88940941f
commit
589bfddc7c
@ -8,6 +8,8 @@
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qendian.h>
|
||||
#include <QtCore/qlist.h>
|
||||
#include <QtCore/qwineventnotifier.h>
|
||||
#include <QtCore/private/qsystemerror_p.h>
|
||||
|
||||
#include <ntstatus.h>
|
||||
|
||||
@ -20,14 +22,17 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
QWinRegistryKey::QWinRegistryKey()
|
||||
QWinRegistryKey::QWinRegistryKey(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
// Open a key with the specified permissions (KEY_READ/KEY_WRITE).
|
||||
// "access" is to explicitly use the 32- or 64-bit branch.
|
||||
QWinRegistryKey::QWinRegistryKey(HKEY parentHandle, QStringView subKey,
|
||||
REGSAM permissions, REGSAM access)
|
||||
REGSAM permissions, REGSAM access,
|
||||
QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
if (RegOpenKeyExW(parentHandle, reinterpret_cast<const wchar_t *>(subKey.utf16()),
|
||||
0, permissions | access, &m_key) != ERROR_SUCCESS) {
|
||||
@ -174,6 +179,45 @@ QString QWinRegistryKey::stringValue(QStringView subKey) const
|
||||
return value<QString>(subKey).value_or(QString());
|
||||
}
|
||||
|
||||
void QWinRegistryKey::connectNotify(const QMetaMethod &signal)
|
||||
{
|
||||
if (signal != QMetaMethod::fromSignal(&QWinRegistryKey::valueChanged))
|
||||
return;
|
||||
|
||||
if (!isValid())
|
||||
return;
|
||||
|
||||
if (m_keyChangedEvent)
|
||||
return;
|
||||
|
||||
m_keyChangedEvent.reset(CreateEvent(nullptr, false, false, nullptr));
|
||||
auto *notifier = new QWinEventNotifier(m_keyChangedEvent.get(), this);
|
||||
|
||||
auto registerForNotification = [this] {
|
||||
constexpr auto changeFilter =
|
||||
REG_NOTIFY_CHANGE_NAME
|
||||
| REG_NOTIFY_CHANGE_ATTRIBUTES
|
||||
| REG_NOTIFY_CHANGE_LAST_SET
|
||||
| REG_NOTIFY_CHANGE_SECURITY;
|
||||
|
||||
if (auto status = RegNotifyChangeKeyValue(m_key, true, changeFilter,
|
||||
m_keyChangedEvent.get(), true); status != ERROR_SUCCESS) {
|
||||
qWarning() << "Failed to register notification for registry key"
|
||||
<< this << "due to" << QSystemError::windowsString(status);
|
||||
}
|
||||
};
|
||||
|
||||
QObject::connect(notifier, &QWinEventNotifier::activated, this,
|
||||
[this, registerForNotification] {
|
||||
emit valueChanged();
|
||||
registerForNotification();
|
||||
});
|
||||
|
||||
registerForNotification();
|
||||
|
||||
return QObject::connectNotify(signal);
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
QDebug operator<<(QDebug debug, const QWinRegistryKey &key)
|
||||
{
|
||||
|
@ -20,17 +20,21 @@
|
||||
#include <QtCore/qstringview.h>
|
||||
#include <QtCore/qt_windows.h>
|
||||
#include <QtCore/qvariant.h>
|
||||
#include <QtCore/qmetaobject.h>
|
||||
#include <QtCore/private/quniquehandle_types_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class Q_CORE_EXPORT QWinRegistryKey
|
||||
class Q_CORE_EXPORT QWinRegistryKey : public QObject
|
||||
{
|
||||
Q_DISABLE_COPY(QWinRegistryKey)
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QWinRegistryKey();
|
||||
QWinRegistryKey(QObject *parent = nullptr);
|
||||
explicit QWinRegistryKey(HKEY parentHandle, QStringView subKey,
|
||||
REGSAM permissions = KEY_READ, REGSAM access = 0);
|
||||
REGSAM permissions = KEY_READ, REGSAM access = 0,
|
||||
QObject *parent = nullptr);
|
||||
~QWinRegistryKey();
|
||||
|
||||
QWinRegistryKey(QWinRegistryKey &&other) noexcept
|
||||
@ -64,8 +68,15 @@ public:
|
||||
friend Q_CORE_EXPORT QDebug operator<<(QDebug dbg, const QWinRegistryKey &);
|
||||
#endif
|
||||
|
||||
Q_SIGNALS:
|
||||
void valueChanged();
|
||||
|
||||
protected:
|
||||
void connectNotify(const QMetaMethod &signal) override;
|
||||
|
||||
private:
|
||||
HKEY m_key = nullptr;
|
||||
QUniqueWin32NullHandle m_keyChangedEvent;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -99,6 +99,7 @@ private Q_SLOTS:
|
||||
void cleanupTestCase();
|
||||
void qwinregistrykey();
|
||||
void name();
|
||||
void valueChanged();
|
||||
|
||||
private:
|
||||
bool m_available = false;
|
||||
@ -266,6 +267,28 @@ void tst_qwinregistrykey::name()
|
||||
}
|
||||
}
|
||||
|
||||
void tst_qwinregistrykey::valueChanged()
|
||||
{
|
||||
if (!m_available)
|
||||
QSKIP("The test data is not ready.");
|
||||
|
||||
QWinRegistryKey testKey(HKEY_CURRENT_USER, TEST_KEY, KEY_READ | KEY_WRITE);
|
||||
QVERIFY(testKey.isValid());
|
||||
|
||||
QVERIFY(write(testKey, u"valueThatCanChange", -1));
|
||||
|
||||
bool valueChanged = false;
|
||||
QObject::connect(&testKey, &QWinRegistryKey::valueChanged, [&] {
|
||||
valueChanged = true;
|
||||
});
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
valueChanged = false;
|
||||
QVERIFY(write(testKey, u"valueThatCanChange", i));
|
||||
QTRY_VERIFY(valueChanged);
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qwinregistrykey)
|
||||
|
||||
#include "tst_qwinregistrykey.moc"
|
||||
|
Loading…
x
Reference in New Issue
Block a user