11#include <QtCore/private/wcharhelpers_win_p.h>
13#include <qt_windows.h>
17#ifndef KEY_WOW64_64KEY
19# define KEY_WOW64_64KEY 0x0100
22#ifndef KEY_WOW64_32KEY
24# define KEY_WOW64_32KEY 0x0200
29using namespace Qt::StringLiterals;
32
33
36
37
40
41
42
47 int idx = rKey.lastIndexOf(u'\\');
50 return rKey.left(idx + 1);
55 int idx = rKey.lastIndexOf(u'\\');
61 res = rKey.mid(idx + 1);
63 if (res ==
"Default"_L1 || res ==
"."_L1)
71 QChar *data = uKey.data();
72 int l = uKey.length();
73 for (
int i = 0; i < l; ++i) {
74 auto &ucs = data[i].unicode();
85 return escapedKey(rKey);
92 NameSet::const_iterator it = src.constBegin();
93 for (; it != src.constEnd(); ++it)
94 dest->insert(unescapedKey(it.key()), QString());
99 QStringList::const_iterator it = src.constBegin();
100 for (; it != src.constEnd(); ++it)
101 dest->insert(unescapedKey(*it), QString());
105
106
112static HKEY openKey(HKEY parentHandle, REGSAM perms,
const QString &rSubKey, REGSAM access = 0)
114 HKEY resultHandle = 0;
115 LONG res = RegOpenKeyEx(parentHandle,
reinterpret_cast<
const wchar_t *>(rSubKey.utf16()),
116 0, perms | access, &resultHandle);
118 if (res == ERROR_SUCCESS)
129 HKEY resultHandle = openKey(parentHandle, perms, rSubKey, access);
130 if (resultHandle != 0)
134 LONG res = RegCreateKeyEx(parentHandle,
reinterpret_cast<
const wchar_t *>(rSubKey.utf16()), 0, 0,
135 REG_OPTION_NON_VOLATILE, perms | access, 0, &resultHandle, 0);
137 if (res == ERROR_SUCCESS)
151 HKEY resultHandle = createOrOpenKey(parentHandle, registryPermissions, rSubKey, access);
152 if (resultHandle != 0) {
159 resultHandle = createOrOpenKey(parentHandle, KEY_READ, rSubKey, access);
160 if (resultHandle != 0) {
174 DWORD maxSubgroupSize;
177 LONG res = RegQueryInfoKey(parentHandle, 0, 0, 0, &numSubgroups, &maxSubgroupSize, 0,
178 &numKeys, &maxKeySize, 0, 0, 0);
180 if (res != ERROR_SUCCESS) {
181 qErrnoWarning(
int(res),
"QSettings: RegQueryInfoKey() failed");
190 if (spec == QSettingsPrivate::ChildKeys) {
202 QByteArray buff(m *
sizeof(
wchar_t), 0);
203 for (
int i = 0; i < n; ++i) {
205 DWORD l = DWORD(buff.size()) / DWORD(
sizeof(
wchar_t));
206 if (spec == QSettingsPrivate::ChildKeys) {
207 res = RegEnumValue(parentHandle, i,
reinterpret_cast<
wchar_t *>(buff.data()), &l, 0, 0, 0, 0);
209 res = RegEnumKeyEx(parentHandle, i,
reinterpret_cast<
wchar_t *>(buff.data()), &l, 0, 0, 0, 0);
211 if (res == ERROR_SUCCESS)
212 item = QString::fromWCharArray((
const wchar_t *)buff.constData(), l);
214 if (res != ERROR_SUCCESS) {
215 qErrnoWarning(
int(res),
"QSettings: RegEnumValue failed");
225static void allKeys(HKEY parentHandle,
const QString &rSubKey,
NameSet *result, REGSAM access = 0)
227 HKEY handle = openKey(parentHandle, KEY_READ, rSubKey, access);
231 QStringList childKeys = childKeysOrGroups(handle, QSettingsPrivate::ChildKeys);
232 QStringList childGroups = childKeysOrGroups(handle, QSettingsPrivate::ChildGroups);
235 for (
int i = 0; i < childKeys.size(); ++i) {
239 s += childKeys.at(i);
240 result->insert(s, QString());
243 for (
int i = 0; i < childGroups.size(); ++i) {
247 s += childGroups.at(i);
248 allKeys(parentHandle, s, result, access);
254 QStringList childGroups = childKeysOrGroups(parentHandle, QSettingsPrivate::ChildGroups);
256 for (
int i = 0; i < childGroups.size(); ++i) {
257 QString group = childGroups.at(i);
260 HKEY childGroupHandle = openKey(parentHandle, registryPermissions, group, access);
261 if (childGroupHandle == 0)
263 deleteChildGroups(childGroupHandle, access);
264 RegCloseKey(childGroupHandle);
267 LONG res = RegDeleteKey(parentHandle, qt_castToWchar(group));
268 if (res != ERROR_SUCCESS) {
269 qErrnoWarning(
int(res),
"QSettings: RegDeleteKey failed on subkey \"%ls\"",
270 qUtf16Printable(group));
277
278
283 RegistryKey(HKEY parent_handle = 0,
const QString &key = QString(),
bool read_only =
true, REGSAM access = 0);
290 HKEY m_parent_handle;
291 mutable HKEY m_handle;
293 mutable bool m_read_only;
301 m_read_only(read_only),
317 m_handle = openKey(m_parent_handle, KEY_READ, m_key, m_access);
319 m_handle = createOrOpenKey(m_parent_handle, m_key, &m_read_only, m_access);
326 return m_parent_handle;
337 RegCloseKey(m_handle);
344
345
356 void remove(
const QString &uKey)
override;
357 void set(
const QString &uKey,
const QVariant &value)
override;
370 bool deleteWriteHandleOnExit;
375 const QString &application, REGSAM access)
376 : QSettingsPrivate(QSettings::NativeFormat, scope, organization, application),
379 deleteWriteHandleOnExit =
false;
381 if (!organization.isEmpty()) {
382 QString prefix =
"Software\\"_L1 + organization;
383 QString orgPrefix = prefix +
"\\OrganizationDefaults"_L1;
384 QString appPrefix = prefix + u'\\' + application;
386 if (scope == QSettings::UserScope) {
387 if (!application.isEmpty())
388 regList.append(RegistryKey(HKEY_CURRENT_USER, appPrefix, !regList.isEmpty(), access));
390 regList.append(RegistryKey(HKEY_CURRENT_USER, orgPrefix, !regList.isEmpty(), access));
393 if (!application.isEmpty())
394 regList.append(RegistryKey(HKEY_LOCAL_MACHINE, appPrefix, !regList.isEmpty(), access));
396 regList.append(RegistryKey(HKEY_LOCAL_MACHINE, orgPrefix, !regList.isEmpty(), access));
399 if (regList.isEmpty())
400 setStatus(QSettings::AccessError);
407 deleteWriteHandleOnExit =
false;
409 if (rPath.startsWith(u'\\'))
415 if (rPath.startsWith(
"HKEY_CURRENT_USER"_L1)) {
417 keyName = HKEY_CURRENT_USER;
418 }
else if (rPath.startsWith(
"HKCU"_L1)) {
420 keyName = HKEY_CURRENT_USER;
421 }
else if (rPath.startsWith(
"HKEY_LOCAL_MACHINE"_L1)) {
423 keyName = HKEY_LOCAL_MACHINE;
424 }
else if (rPath.startsWith(
"HKLM"_L1)) {
426 keyName = HKEY_LOCAL_MACHINE;
427 }
else if (rPath.startsWith(
"HKEY_CLASSES_ROOT"_L1)) {
429 keyName = HKEY_CLASSES_ROOT;
430 }
else if (rPath.startsWith(
"HKCR"_L1)) {
432 keyName = HKEY_CLASSES_ROOT;
433 }
else if (rPath.startsWith(
"HKEY_USERS"_L1)) {
435 keyName = HKEY_USERS;
436 }
else if (rPath.startsWith(
"HKU"_L1)) {
438 keyName = HKEY_USERS;
443 if (rPath.length() == keyLength)
444 regList.append(RegistryKey(keyName, QString(),
false, access));
445 else if (rPath[keyLength] == u'\\')
446 regList.append(RegistryKey(keyName, rPath.mid(keyLength+1),
false, access));
451 QString rSubkeyName = keyName(rSubKey);
452 QString rSubkeyPath = keyPath(rSubKey);
455 HKEY handle = openKey(parentHandle, KEY_READ, rSubkeyPath, access);
459 const auto closeKey = qScopeGuard([handle] { RegCloseKey(handle); });
464 LONG res = RegQueryValueEx(handle,
reinterpret_cast<
const wchar_t *>(rSubkeyName.utf16()), 0, &dataType, 0, &dataSize);
465 if (res != ERROR_SUCCESS)
469 if (dataType == REG_SZ || dataType == REG_EXPAND_SZ)
471 else if (dataType == REG_MULTI_SZ)
475 QByteArray data(dataSize, 0);
476 res = RegQueryValueEx(handle,
reinterpret_cast<
const wchar_t *>(rSubkeyName.utf16()), 0, 0,
477 reinterpret_cast<
unsigned char*>(data.data()), &dataSize);
478 if (res != ERROR_SUCCESS)
486 s = QString::fromWCharArray(
reinterpret_cast<
const wchar_t *>(data.constData()));
488 return stringToVariant(s);
496 QString s = QString::fromWCharArray(
reinterpret_cast<
const wchar_t *>(data.constData()) + i);
504 return stringListToVariantList(l);
511 s = QString::fromWCharArray(
reinterpret_cast<
const wchar_t *>(data.constData()), data.size() / 2);
513 return stringToVariant(s);
516 case REG_DWORD_BIG_ENDIAN:
518 Q_ASSERT(data.size() ==
sizeof(
int));
520 memcpy(
reinterpret_cast<
char*>(&i), data.constData(),
sizeof(
int));
525 Q_ASSERT(data.size() ==
sizeof(qint64));
527 memcpy(
reinterpret_cast<
char*>(&i), data.constData(),
sizeof(qint64));
532 qWarning(
"QSettings: Unknown data %d type in Windows registry",
static_cast<
int>(dataType));
541 if (regList.isEmpty())
551 if (deleteWriteHandleOnExit && writeHandle() != 0) {
552 DWORD res = RegDeleteKey(writeHandle(), L"");
553 if (res != ERROR_SUCCESS) {
554 qErrnoWarning(
int(res),
"QSettings: Failed to delete key \"%ls\"",
555 qUtf16Printable(regList.constFirst().key()));
559 for (
int i = 0; i < regList.size(); ++i)
565 if (writeHandle() == 0) {
566 setStatus(QSettings::AccessError);
570 QString rKey = escapedKey(uKey);
574 HKEY handle = openKey(writeHandle(), registryPermissions, keyPath(rKey), access);
576 res = RegDeleteValue(handle,
reinterpret_cast<
const wchar_t *>(keyName(rKey).utf16()));
581 handle = openKey(writeHandle(), registryPermissions, rKey, access);
583 deleteChildGroups(handle, access);
585 if (rKey.isEmpty()) {
586 const QStringList childKeys = childKeysOrGroups(handle, QSettingsPrivate::ChildKeys);
588 for (
const QString &group : childKeys) {
589 LONG res = RegDeleteValue(handle, qt_castToWchar(group));
590 if (res != ERROR_SUCCESS) {
591 qErrnoWarning(
int(res),
"QSettings: RegDeleteValue failed on subkey \"%ls\"",
592 qUtf16Printable(group));
596 res = RegDeleteKey(writeHandle(),
reinterpret_cast<
const wchar_t *>(rKey.utf16()));
598 if (res != ERROR_SUCCESS) {
599 qErrnoWarning(
int(res),
"QSettings: RegDeleteKey failed on key \"%ls\"",
600 qUtf16Printable(rKey));
609 if (writeHandle() == 0) {
610 setStatus(QSettings::AccessError);
614 QString rKey = escapedKey(uKey);
616 HKEY handle = createOrOpenKey(writeHandle(), registryPermissions, keyPath(rKey), access);
618 setStatus(QSettings::AccessError);
623 QByteArray regValueBuff;
626 switch (value.typeId()) {
627 case QMetaType::QVariantList:
628 case QMetaType::QStringList: {
632 QStringList l = variantListToStringList(value.toList());
633 QStringList::const_iterator it = l.constBegin();
634 for (; it != l.constEnd(); ++it) {
635 if ((*it).length() == 0 || it->contains(QChar::Null)) {
641 if (type == REG_BINARY) {
642 const QString s = variantToString(value);
643 regValueBuff = QByteArray(
reinterpret_cast<
const char *>(s.data()), s.length() * 2);
645 QStringList::const_iterator it = l.constBegin();
646 for (; it != l.constEnd(); ++it) {
647 const QString &s = *it;
648 regValueBuff += QByteArray(
reinterpret_cast<
const char*>(s.utf16()), (s.length() + 1) * 2);
650 regValueBuff.append((
char)0);
651 regValueBuff.append((
char)0);
657 case QMetaType::UInt: {
659 qint32 i = value.toInt();
660 regValueBuff = QByteArray(
reinterpret_cast<
const char*>(&i),
sizeof(qint32));
664 case QMetaType::LongLong:
665 case QMetaType::ULongLong: {
667 qint64 i = value.toLongLong();
668 regValueBuff = QByteArray(
reinterpret_cast<
const char*>(&i),
sizeof(qint64));
672 case QMetaType::QByteArray:
678 QString s = variantToString(value);
679 type = s.contains(QChar::Null) ? REG_BINARY : REG_SZ;
680 int length = s.length();
683 regValueBuff = QByteArray(
reinterpret_cast<
const char *>(s.constData()),
684 int(
sizeof(
wchar_t)) * length);
690 LONG res = RegSetValueEx(handle,
reinterpret_cast<
const wchar_t *>(keyName(rKey).utf16()), 0, type,
691 reinterpret_cast<
const unsigned char*>(regValueBuff.constData()),
692 regValueBuff.size());
694 if (res == ERROR_SUCCESS) {
695 deleteWriteHandleOnExit =
false;
697 qErrnoWarning(
int(res),
"QSettings: failed to set subkey \"%ls\"",
698 qUtf16Printable(rKey));
699 setStatus(QSettings::AccessError);
707 QString rKey = escapedKey(uKey);
709 for (
const RegistryKey &r : regList) {
710 HKEY handle = r.handle();
712 if (
auto result = readKey(handle, rKey))
725 QString rKey = escapedKey(uKey);
727 for (
const RegistryKey &r : regList) {
728 HKEY parent_handle = r.handle();
729 if (parent_handle == 0) {
734 HKEY handle = openKey(parent_handle, KEY_READ, rKey, access);
741 if (spec == AllKeys) {
743 allKeys(handle,
""_L1, &keys, access);
744 mergeKeySets(&result, keys);
746 QStringList names = childKeysOrGroups(handle, spec);
747 mergeKeySets(&result, names);
753 return result.keys();
756 return result.keys();
762 deleteWriteHandleOnExit =
true;
767 RegFlushKey(writeHandle());
777 if (regList.isEmpty())
782 if (key.parentHandle() == HKEY_CURRENT_USER)
783 result =
"\\HKEY_CURRENT_USER\\"_L1;
785 result =
"\\HKEY_LOCAL_MACHINE\\"_L1;
787 return result + regList.at(0).key();
792 return writeHandle() != 0;
795QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope,
796 const QString &organization,
const QString &application)
799 case QSettings::NativeFormat:
800 return new QWinSettingsPrivate(scope, organization, application);
801 case QSettings::Registry32Format:
802 return new QWinSettingsPrivate(scope, organization, application,
KEY_WOW64_32KEY);
803 case QSettings::Registry64Format:
804 return new QWinSettingsPrivate(scope, organization, application,
KEY_WOW64_64KEY);
808 return new QConfFileSettingsPrivate(format, scope, organization, application);
811QSettingsPrivate *QSettingsPrivate::create(
const QString &fileName, QSettings::Format format)
814 case QSettings::NativeFormat:
815 return new QWinSettingsPrivate(fileName);
816 case QSettings::Registry32Format:
818 case QSettings::Registry64Format:
823 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)
Combined button and popup list for selecting options.
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)