summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qwinregistry.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/kernel/qwinregistry.cpp')
-rw-r--r--src/corelib/kernel/qwinregistry.cpp132
1 files changed, 92 insertions, 40 deletions
diff --git a/src/corelib/kernel/qwinregistry.cpp b/src/corelib/kernel/qwinregistry.cpp
index 368ae2faad..d237316577 100644
--- a/src/corelib/kernel/qwinregistry.cpp
+++ b/src/corelib/kernel/qwinregistry.cpp
@@ -2,15 +2,13 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwinregistry_p.h"
-
#include <QtCore/qvarlengtharray.h>
-
-#include <algorithm>
+#include <QtCore/qendian.h>
+#include <QtCore/qlist.h>
QT_BEGIN_NAMESPACE
-QWinRegistryKey::QWinRegistryKey() :
- m_key(nullptr)
+QWinRegistryKey::QWinRegistryKey()
{
}
@@ -19,8 +17,8 @@ QWinRegistryKey::QWinRegistryKey() :
QWinRegistryKey::QWinRegistryKey(HKEY parentHandle, QStringView subKey,
REGSAM permissions, REGSAM access)
{
- if (RegOpenKeyEx(parentHandle, reinterpret_cast<const wchar_t *>(subKey.utf16()),
- 0, permissions | access, &m_key) != ERROR_SUCCESS) {
+ if (RegOpenKeyExW(parentHandle, reinterpret_cast<const wchar_t *>(subKey.utf16()),
+ 0, permissions | access, &m_key) != ERROR_SUCCESS) {
m_key = nullptr;
}
}
@@ -38,45 +36,99 @@ void QWinRegistryKey::close()
}
}
-QString QWinRegistryKey::stringValue(QStringView subKey) const
+QVariant QWinRegistryKey::value(QStringView subKey) const
{
- QString result;
+ // NOTE: Empty value name is allowed in Windows registry, it means the default
+ // or unnamed value of a key, you can read/write/delete such value normally.
+
if (!isValid())
- return result;
- DWORD type;
- DWORD size;
- auto subKeyC = reinterpret_cast<const wchar_t *>(subKey.utf16());
- if (RegQueryValueEx(m_key, subKeyC, nullptr, &type, nullptr, &size) != ERROR_SUCCESS
- || (type != REG_SZ && type != REG_EXPAND_SZ) || size <= 2) {
- return result;
+ return {};
+
+ // Use nullptr when we need to access the default value.
+ const auto subKeyC = subKey.isEmpty() ? nullptr : reinterpret_cast<const wchar_t *>(subKey.utf16());
+
+ // Get the size and type of the value.
+ DWORD dataType = REG_NONE;
+ DWORD dataSize = 0;
+ LONG ret = RegQueryValueExW(m_key, subKeyC, nullptr, &dataType, nullptr, &dataSize);
+ if (ret != ERROR_SUCCESS)
+ return {};
+
+ // Workaround for rare cases where the trailing '\0' is missing.
+ if (dataType == REG_SZ || dataType == REG_EXPAND_SZ)
+ dataSize += 2;
+ else if (dataType == REG_MULTI_SZ)
+ dataSize += 4;
+
+ // Get the value.
+ QVarLengthArray<unsigned char> data(dataSize);
+ std::fill(data.data(), data.data() + dataSize, 0u);
+
+ ret = RegQueryValueExW(m_key, subKeyC, nullptr, nullptr, data.data(), &dataSize);
+ if (ret != ERROR_SUCCESS)
+ return {};
+
+ switch (dataType) {
+ case REG_SZ:
+ case REG_EXPAND_SZ: {
+ if (dataSize > 0) {
+ return QString::fromWCharArray(
+ reinterpret_cast<const wchar_t *>(data.constData()));
+ }
+ return QString();
+ }
+
+ case REG_MULTI_SZ: {
+ if (dataSize > 0) {
+ QStringList list = {};
+ int i = 0;
+ while (true) {
+ const QString str = QString::fromWCharArray(
+ reinterpret_cast<const wchar_t *>(data.constData()) + i);
+ i += str.length() + 1;
+ if (str.isEmpty())
+ break;
+ list.append(str);
+ }
+ return list;
+ }
+ return QStringList();
+ }
+
+ case REG_NONE: // No specific type, treat as binary data.
+ case REG_BINARY: {
+ if (dataSize > 0) {
+ return QString::fromWCharArray(
+ reinterpret_cast<const wchar_t *>(data.constData()), data.size() / 2);
+ }
+ return QString();
+ }
+
+ case REG_DWORD: // Same as REG_DWORD_LITTLE_ENDIAN
+ return qFromLittleEndian<quint32>(data.constData());
+
+ case REG_DWORD_BIG_ENDIAN:
+ return qFromBigEndian<quint32>(data.constData());
+
+ case REG_QWORD: // Same as REG_QWORD_LITTLE_ENDIAN
+ return qFromLittleEndian<quint64>(data.constData());
+
+ default:
+ break;
}
- // Reserve more for rare cases where trailing '\0' are missing in registry.
- // Rely on 0-termination since strings of size 256 padded with 0 have been
- // observed (QTBUG-84455).
- size += 2;
- QVarLengthArray<unsigned char> buffer(static_cast<int>(size));
- std::fill(buffer.data(), buffer.data() + size, 0u);
- if (RegQueryValueEx(m_key, subKeyC, nullptr, &type, buffer.data(), &size) == ERROR_SUCCESS)
- result = QString::fromWCharArray(reinterpret_cast<const wchar_t *>(buffer.constData()));
- return result;
+
+ return {};
}
-QPair<DWORD, bool> QWinRegistryKey::dwordValue(QStringView subKey) const
+QString QWinRegistryKey::stringValue(QStringView subKey) const
{
- if (!isValid())
- return qMakePair(0, false);
- DWORD type;
- auto subKeyC = reinterpret_cast<const wchar_t *>(subKey.utf16());
- if (RegQueryValueEx(m_key, subKeyC, nullptr, &type, nullptr, nullptr) != ERROR_SUCCESS
- || type != REG_DWORD) {
- return qMakePair(0, false);
- }
- DWORD value = 0;
- DWORD size = sizeof(value);
- const bool ok =
- RegQueryValueEx(m_key, subKeyC, nullptr, nullptr,
- reinterpret_cast<unsigned char *>(&value), &size) == ERROR_SUCCESS;
- return qMakePair(value, ok);
+ return value<QString>(subKey).value_or(QString());
+}
+
+std::pair<DWORD, bool> QWinRegistryKey::dwordValue(QStringView subKey) const
+{
+ const std::optional<DWORD> val = value<DWORD>(subKey);
+ return {val.value_or(0), val.has_value()};
}
QT_END_NAMESPACE