12#include <QtCore/private/wcharhelpers_win_p.h>
14#include <qt_windows.h>
18#ifndef KEY_WOW64_64KEY
20# define KEY_WOW64_64KEY 0x0100
23#ifndef KEY_WOW64_32KEY
25# define KEY_WOW64_32KEY 0x0200
30using namespace Qt::StringLiterals;
33
34
37
38
41
42
43
48 int idx = rKey.lastIndexOf(u'\\');
51 return rKey.left(idx + 1);
56 int idx = rKey.lastIndexOf(u'\\');
62 res = rKey.mid(idx + 1);
64 if (res ==
"Default"_L1 || res ==
"."_L1)
72 QChar *data = uKey.data();
73 int l = uKey.length();
74 for (
int i = 0; i < l; ++i) {
75 auto &ucs = data[i].unicode();
86 return escapedKey(rKey);
93 NameSet::const_iterator it = src.constBegin();
94 for (; it != src.constEnd(); ++it)
95 dest->insert(unescapedKey(it.key()), QString());
100 QStringList::const_iterator it = src.constBegin();
101 for (; it != src.constEnd(); ++it)
102 dest->insert(unescapedKey(*it), QString());
106
107
113static HKEY openKey(HKEY parentHandle, REGSAM perms,
const QString &rSubKey, REGSAM access = 0)
115 HKEY resultHandle = 0;
116 LONG res = RegOpenKeyEx(parentHandle,
reinterpret_cast<
const wchar_t *>(rSubKey.utf16()),
117 0, perms | access, &resultHandle);
119 if (res == ERROR_SUCCESS)
130 HKEY resultHandle = openKey(parentHandle, perms, rSubKey, access);
131 if (resultHandle != 0)
135 LONG res = RegCreateKeyEx(parentHandle,
reinterpret_cast<
const wchar_t *>(rSubKey.utf16()), 0, 0,
136 REG_OPTION_NON_VOLATILE, perms | access, 0, &resultHandle, 0);
138 if (res == ERROR_SUCCESS)
152 HKEY resultHandle = createOrOpenKey(parentHandle, registryPermissions, rSubKey, access);
153 if (resultHandle != 0) {
160 resultHandle = createOrOpenKey(parentHandle, KEY_READ, rSubKey, access);
161 if (resultHandle != 0) {
175 DWORD maxSubgroupSize;
178 LONG res = RegQueryInfoKey(parentHandle, 0, 0, 0, &numSubgroups, &maxSubgroupSize, 0,
179 &numKeys, &maxKeySize, 0, 0, 0);
181 if (res != ERROR_SUCCESS) {
182 qErrnoWarning(
int(res),
"QSettings: RegQueryInfoKey() failed");
191 if (spec == QSettingsPrivate::ChildKeys) {
203 QByteArray buff(m *
sizeof(
wchar_t), 0);
204 for (
int i = 0; i < n; ++i) {
206 DWORD l = DWORD(buff.size()) / DWORD(
sizeof(
wchar_t));
207 if (spec == QSettingsPrivate::ChildKeys) {
208 res = RegEnumValue(parentHandle, i,
reinterpret_cast<
wchar_t *>(buff.data()), &l, 0, 0, 0, 0);
210 res = RegEnumKeyEx(parentHandle, i,
reinterpret_cast<
wchar_t *>(buff.data()), &l, 0, 0, 0, 0);
212 if (res == ERROR_SUCCESS)
213 item = QString::fromWCharArray((
const wchar_t *)buff.constData(), l);
215 if (res != ERROR_SUCCESS) {
216 qErrnoWarning(
int(res),
"QSettings: RegEnumValue failed");
226static void allKeys(HKEY parentHandle,
const QString &rSubKey,
NameSet *result, REGSAM access = 0)
228 HKEY handle = openKey(parentHandle, KEY_READ, rSubKey, access);
232 QStringList childKeys = childKeysOrGroups(handle, QSettingsPrivate::ChildKeys);
233 QStringList childGroups = childKeysOrGroups(handle, QSettingsPrivate::ChildGroups);
236 for (
int i = 0; i < childKeys.size(); ++i) {
240 s += childKeys.at(i);
241 result->insert(s, QString());
244 for (
int i = 0; i < childGroups.size(); ++i) {
248 s += childGroups.at(i);
249 allKeys(parentHandle, s, result, access);
255 QStringList childGroups = childKeysOrGroups(parentHandle, QSettingsPrivate::ChildGroups);
257 for (
int i = 0; i < childGroups.size(); ++i) {
258 QString group = childGroups.at(i);
261 HKEY childGroupHandle = openKey(parentHandle, registryPermissions, group, access);
262 if (childGroupHandle == 0)
264 deleteChildGroups(childGroupHandle, access);
265 RegCloseKey(childGroupHandle);
268 LONG res = RegDeleteKey(parentHandle, qt_castToWchar(group));
269 if (res != ERROR_SUCCESS) {
270 qErrnoWarning(
int(res),
"QSettings: RegDeleteKey failed on subkey \"%ls\"",
271 qUtf16Printable(group));
278
279
284 RegistryKey(HKEY parent_handle = 0,
const QString &key = QString(),
bool read_only =
true, REGSAM access = 0);
291 HKEY m_parent_handle;
292 mutable HKEY m_handle;
294 mutable bool m_read_only;
302 m_read_only(read_only),
318 m_handle = openKey(m_parent_handle, KEY_READ, m_key, m_access);
320 m_handle = createOrOpenKey(m_parent_handle, m_key, &m_read_only, m_access);
327 return m_parent_handle;
338 RegCloseKey(m_handle);
345
346
357 void remove(
const QString &uKey)
override;
358 void set(
const QString &uKey,
const QVariant &value)
override;
371 bool deleteWriteHandleOnExit;
376 const QString &application, REGSAM access)
377 : QSettingsPrivate(QSettings::NativeFormat, scope, organization, application),
380 deleteWriteHandleOnExit =
false;
382 if (!organization.isEmpty()) {
383 QString prefix =
"Software\\"_L1 + organization;
384 QString orgPrefix = prefix +
"\\OrganizationDefaults"_L1;
385 QString appPrefix = prefix + u'\\' + application;
387 if (scope == QSettings::UserScope) {
388 if (!application.isEmpty())
389 regList.append(RegistryKey(HKEY_CURRENT_USER, appPrefix, !regList.isEmpty(), access));
391 regList.append(RegistryKey(HKEY_CURRENT_USER, orgPrefix, !regList.isEmpty(), access));
394 if (!application.isEmpty())
395 regList.append(RegistryKey(HKEY_LOCAL_MACHINE, appPrefix, !regList.isEmpty(), access));
397 regList.append(RegistryKey(HKEY_LOCAL_MACHINE, orgPrefix, !regList.isEmpty(), access));
400 if (regList.isEmpty())
401 setStatus(QSettings::AccessError);
408 deleteWriteHandleOnExit =
false;
410 if (rPath.startsWith(u'\\'))
416 if (rPath.startsWith(
"HKEY_CURRENT_USER"_L1)) {
418 keyName = HKEY_CURRENT_USER;
419 }
else if (rPath.startsWith(
"HKCU"_L1)) {
421 keyName = HKEY_CURRENT_USER;
422 }
else if (rPath.startsWith(
"HKEY_LOCAL_MACHINE"_L1)) {
424 keyName = HKEY_LOCAL_MACHINE;
425 }
else if (rPath.startsWith(
"HKLM"_L1)) {
427 keyName = HKEY_LOCAL_MACHINE;
428 }
else if (rPath.startsWith(
"HKEY_CLASSES_ROOT"_L1)) {
430 keyName = HKEY_CLASSES_ROOT;
431 }
else if (rPath.startsWith(
"HKCR"_L1)) {
433 keyName = HKEY_CLASSES_ROOT;
434 }
else if (rPath.startsWith(
"HKEY_USERS"_L1)) {
436 keyName = HKEY_USERS;
437 }
else if (rPath.startsWith(
"HKU"_L1)) {
439 keyName = HKEY_USERS;
444 if (rPath.length() == keyLength)
445 regList.append(RegistryKey(keyName, QString(),
false, access));
446 else if (rPath[keyLength] == u'\\')
447 regList.append(RegistryKey(keyName, rPath.mid(keyLength+1),
false, access));
452 QString rSubkeyName = keyName(rSubKey);
453 QString rSubkeyPath = keyPath(rSubKey);
456 HKEY handle = openKey(parentHandle, KEY_READ, rSubkeyPath, access);
460 const auto closeKey = qScopeGuard([handle] { RegCloseKey(handle); });
465 LONG res = RegQueryValueEx(handle,
reinterpret_cast<
const wchar_t *>(rSubkeyName.utf16()), 0, &dataType, 0, &dataSize);
466 if (res != ERROR_SUCCESS)
470 if (dataType == REG_SZ || dataType == REG_EXPAND_SZ)
472 else if (dataType == REG_MULTI_SZ)
476 QByteArray data(dataSize, 0);
477 res = RegQueryValueEx(handle,
reinterpret_cast<
const wchar_t *>(rSubkeyName.utf16()), 0, 0,
478 reinterpret_cast<
unsigned char*>(data.data()), &dataSize);
479 if (res != ERROR_SUCCESS)
487 s = QString::fromWCharArray(
reinterpret_cast<
const wchar_t *>(data.constData()));
489 return stringToVariant(s);
497 QString s = QString::fromWCharArray(
reinterpret_cast<
const wchar_t *>(data.constData()) + i);
505 return stringListToVariantList(l);
512 s = QString::fromWCharArray(
reinterpret_cast<
const wchar_t *>(data.constData()), data.size() / 2);
514 return stringToVariant(s);
517 case REG_DWORD_BIG_ENDIAN:
519 Q_ASSERT(data.size() ==
sizeof(
int));
521 memcpy(
reinterpret_cast<
char*>(&i), data.constData(),
sizeof(
int));
526 Q_ASSERT(data.size() ==
sizeof(qint64));
528 memcpy(
reinterpret_cast<
char*>(&i), data.constData(),
sizeof(qint64));
533 qWarning(
"QSettings: Unknown data %d type in Windows registry",
static_cast<
int>(dataType));
542 if (regList.isEmpty())
552 if (deleteWriteHandleOnExit && writeHandle() != 0) {
553 DWORD res = RegDeleteKey(writeHandle(), L"");
554 if (res != ERROR_SUCCESS) {
555 qErrnoWarning(
int(res),
"QSettings: Failed to delete key \"%ls\"",
556 qUtf16Printable(regList.constFirst().key()));
560 for (
int i = 0; i < regList.size(); ++i)
566 if (writeHandle() == 0) {
567 setStatus(QSettings::AccessError);
571 QString rKey = escapedKey(uKey);
575 HKEY handle = openKey(writeHandle(), registryPermissions, keyPath(rKey), access);
577 res = RegDeleteValue(handle,
reinterpret_cast<
const wchar_t *>(keyName(rKey).utf16()));
582 handle = openKey(writeHandle(), registryPermissions, rKey, access);
584 deleteChildGroups(handle, access);
586 if (rKey.isEmpty()) {
587 const QStringList childKeys = childKeysOrGroups(handle, QSettingsPrivate::ChildKeys);
589 for (
const QString &group : childKeys) {
590 LONG res = RegDeleteValue(handle, qt_castToWchar(group));
591 if (res != ERROR_SUCCESS) {
592 qErrnoWarning(
int(res),
"QSettings: RegDeleteValue failed on subkey \"%ls\"",
593 qUtf16Printable(group));
597 res = RegDeleteKey(writeHandle(),
reinterpret_cast<
const wchar_t *>(rKey.utf16()));
599 if (res != ERROR_SUCCESS) {
600 qErrnoWarning(
int(res),
"QSettings: RegDeleteKey failed on key \"%ls\"",
601 qUtf16Printable(rKey));
610 if (writeHandle() == 0) {
611 setStatus(QSettings::AccessError);
615 QString rKey = escapedKey(uKey);
617 HKEY handle = createOrOpenKey(writeHandle(), registryPermissions, keyPath(rKey), access);
619 setStatus(QSettings::AccessError);
624 QByteArray regValueBuff;
627 switch (value.typeId()) {
628 case QMetaType::QVariantList:
629 case QMetaType::QStringList: {
633 QStringList l = variantListToStringList(value.toList());
634 QStringList::const_iterator it = l.constBegin();
635 for (; it != l.constEnd(); ++it) {
636 if ((*it).length() == 0 || it->contains(QChar::Null)) {
642 if (type == REG_BINARY) {
643 const QString s = variantToString(value);
644 regValueBuff = QByteArray(
reinterpret_cast<
const char *>(s.data()), s.length() * 2);
646 QStringList::const_iterator it = l.constBegin();
647 for (; it != l.constEnd(); ++it) {
648 const QString &s = *it;
649 regValueBuff += QByteArray(
reinterpret_cast<
const char*>(s.utf16()), (s.length() + 1) * 2);
651 regValueBuff.append((
char)0);
652 regValueBuff.append((
char)0);
658 case QMetaType::UInt: {
660 qint32 i = value.toInt();
661 regValueBuff = QByteArray(
reinterpret_cast<
const char*>(&i),
sizeof(qint32));
665 case QMetaType::LongLong:
666 case QMetaType::ULongLong: {
668 qint64 i = value.toLongLong();
669 regValueBuff = QByteArray(
reinterpret_cast<
const char*>(&i),
sizeof(qint64));
673 case QMetaType::QByteArray:
679 QString s = variantToString(value);
680 type = s.contains(QChar::Null) ? REG_BINARY : REG_SZ;
681 int length = s.length();
684 regValueBuff = QByteArray(
reinterpret_cast<
const char *>(s.constData()),
685 int(
sizeof(
wchar_t)) * length);
691 LONG res = RegSetValueEx(handle,
reinterpret_cast<
const wchar_t *>(keyName(rKey).utf16()), 0, type,
692 reinterpret_cast<
const unsigned char*>(regValueBuff.constData()),
693 regValueBuff.size());
695 if (res == ERROR_SUCCESS) {
696 deleteWriteHandleOnExit =
false;
698 qErrnoWarning(
int(res),
"QSettings: failed to set subkey \"%ls\"",
699 qUtf16Printable(rKey));
700 setStatus(QSettings::AccessError);
708 QString rKey = escapedKey(uKey);
710 for (
const RegistryKey &r : regList) {
711 HKEY handle = r.handle();
713 if (
auto result = readKey(handle, rKey))
726 QString rKey = escapedKey(uKey);
728 for (
const RegistryKey &r : regList) {
729 HKEY parent_handle = r.handle();
730 if (parent_handle == 0) {
735 HKEY handle = openKey(parent_handle, KEY_READ, rKey, access);
742 if (spec == AllKeys) {
744 allKeys(handle,
""_L1, &keys, access);
745 mergeKeySets(&result, keys);
747 QStringList names = childKeysOrGroups(handle, spec);
748 mergeKeySets(&result, names);
754 return result.keys();
757 return result.keys();
763 deleteWriteHandleOnExit =
true;
768 RegFlushKey(writeHandle());
778 if (regList.isEmpty())
783 if (key.parentHandle() == HKEY_CURRENT_USER)
784 result =
"\\HKEY_CURRENT_USER\\"_L1;
786 result =
"\\HKEY_LOCAL_MACHINE\\"_L1;
788 return result + regList.at(0).key();
793 return writeHandle() != 0;
796QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope,
797 const QString &organization,
const QString &application)
800 case QSettings::NativeFormat:
801 return new QWinSettingsPrivate(scope, organization, application);
802 case QSettings::Registry32Format:
803 return new QWinSettingsPrivate(scope, organization, application,
KEY_WOW64_32KEY);
804 case QSettings::Registry64Format:
805 return new QWinSettingsPrivate(scope, organization, application,
KEY_WOW64_64KEY);
809 return new QConfFileSettingsPrivate(format, scope, organization, application);
812QSettingsPrivate *QSettingsPrivate::create(
const QString &fileName, QSettings::Format format)
815 case QSettings::NativeFormat:
816 return new QWinSettingsPrivate(fileName);
817 case QSettings::Registry32Format:
819 case QSettings::Registry64Format:
824 return new QConfFileSettingsPrivate(fileName, format);
~QWinSettingsPrivate() override
bool isWritable() const override
void set(const QString &uKey, const QVariant &value) override
void remove(const QString &uKey) override
QStringList children(const QString &uKey, ChildSpec spec) const override
std::optional< QVariant > get(const QString &uKey) const override
std::optional< QVariant > readKey(HKEY parentHandle, const QString &rSubKey) const
QWinSettingsPrivate(QString rKey, REGSAM access=0)
QString fileName() const override
HKEY parentHandle() const
RegistryKey(HKEY parent_handle=0, const QString &key=QString(), bool read_only=true, REGSAM access=0)
static void deleteChildGroups(HKEY parentHandle, REGSAM access=0)
static QString escapedKey(QString uKey)
QList< RegistryKey > RegistryKeyList
static void mergeKeySets(NameSet *dest, const NameSet &src)
static QString unescapedKey(QString rKey)
static void allKeys(HKEY parentHandle, const QString &rSubKey, NameSet *result, REGSAM access=0)
static HKEY createOrOpenKey(HKEY parentHandle, REGSAM perms, const QString &rSubKey, REGSAM access=0)
static QString keyPath(const QString &rKey)
static QString keyName(const QString &rKey)
QMap< QString, QString > NameSet
static QStringList childKeysOrGroups(HKEY parentHandle, QSettingsPrivate::ChildSpec spec)
static HKEY openKey(HKEY parentHandle, REGSAM perms, const QString &rSubKey, REGSAM access=0)
static const REGSAM registryPermissions
static HKEY createOrOpenKey(HKEY parentHandle, const QString &rSubKey, bool *readOnly, REGSAM access=0)