Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qsettings_win.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:trusted-data-only
4
5#include "qsettings.h"
6
7#include "qsettings_p.h"
8#include "qlist.h"
9#include "qmap.h"
10#include "qdebug.h"
11#include "qscopeguard.h"
12#include <QtCore/private/wcharhelpers_win_p.h>
13
14#include <qt_windows.h>
15
16// See "Accessing an Alternate Registry View" at:
17// http://msdn.microsoft.com/en-us/library/aa384129%28VS.85%29.aspx
18#ifndef KEY_WOW64_64KEY
19 // Access a 32-bit key from either a 32-bit or 64-bit application.
20# define KEY_WOW64_64KEY 0x0100
21#endif
22
23#ifndef KEY_WOW64_32KEY
24 // Access a 64-bit key from either a 32-bit or 64-bit application.
25# define KEY_WOW64_32KEY 0x0200
26#endif
27
29
30using namespace Qt::StringLiterals;
31
32/* Keys are stored in QStrings. If the variable name starts with 'u', this is a "user"
33 key, ie. "foo/bar/alpha/beta". If the variable name starts with 'r', this is a "registry"
34 key, ie. "\foo\bar\alpha\beta". */
35
36/*******************************************************************************
37** Some convenience functions
38*/
39
40/*
41 We don't use KEY_ALL_ACCESS because it gives more rights than what we
42 need. See task 199061.
43 */
44static const REGSAM registryPermissions = KEY_READ | KEY_WRITE;
45
46static QString keyPath(const QString &rKey)
47{
48 int idx = rKey.lastIndexOf(u'\\');
49 if (idx == -1)
50 return QString();
51 return rKey.left(idx + 1);
52}
53
54static QString keyName(const QString &rKey)
55{
56 int idx = rKey.lastIndexOf(u'\\');
57
58 QString res;
59 if (idx == -1)
60 res = rKey;
61 else
62 res = rKey.mid(idx + 1);
63
64 if (res == "Default"_L1 || res == "."_L1)
65 res = ""_L1;
66
67 return res;
68}
69
70static QString escapedKey(QString uKey)
71{
72 QChar *data = uKey.data();
73 int l = uKey.length();
74 for (int i = 0; i < l; ++i) {
75 auto &ucs = data[i].unicode();
76 if (ucs == '\\')
77 ucs = '/';
78 else if (ucs == '/')
79 ucs = '\\';
80 }
81 return uKey;
82}
83
84static QString unescapedKey(QString rKey)
85{
86 return escapedKey(rKey);
87}
88
90
91static void mergeKeySets(NameSet *dest, const NameSet &src)
92{
93 NameSet::const_iterator it = src.constBegin();
94 for (; it != src.constEnd(); ++it)
95 dest->insert(unescapedKey(it.key()), QString());
96}
97
98static void mergeKeySets(NameSet *dest, const QStringList &src)
99{
100 QStringList::const_iterator it = src.constBegin();
101 for (; it != src.constEnd(); ++it)
102 dest->insert(unescapedKey(*it), QString());
103}
104
105/*******************************************************************************
106** Wrappers for the insane windows registry API
107*/
108
109// ### Qt 6: Use new helpers from qwinregistry.cpp (once bootstrap builds are obsolete)
110
111// Open a key with the specified "perms".
112// "access" is to explicitly use the 32- or 64-bit branch.
113static HKEY openKey(HKEY parentHandle, REGSAM perms, const QString &rSubKey, REGSAM access = 0)
114{
115 HKEY resultHandle = 0;
116 LONG res = RegOpenKeyEx(parentHandle, reinterpret_cast<const wchar_t *>(rSubKey.utf16()),
117 0, perms | access, &resultHandle);
118
119 if (res == ERROR_SUCCESS)
120 return resultHandle;
121
122 return 0;
123}
124
125// Open a key with the specified "perms", create it if it does not exist.
126// "access" is to explicitly use the 32- or 64-bit branch.
127static HKEY createOrOpenKey(HKEY parentHandle, REGSAM perms, const QString &rSubKey, REGSAM access = 0)
128{
129 // try to open it
130 HKEY resultHandle = openKey(parentHandle, perms, rSubKey, access);
131 if (resultHandle != 0)
132 return resultHandle;
133
134 // try to create it
135 LONG res = RegCreateKeyEx(parentHandle, reinterpret_cast<const wchar_t *>(rSubKey.utf16()), 0, 0,
136 REG_OPTION_NON_VOLATILE, perms | access, 0, &resultHandle, 0);
137
138 if (res == ERROR_SUCCESS)
139 return resultHandle;
140
141 //qErrnoWarning(int(res), "QSettings: Failed to create subkey \"%ls\"",
142 // qUtf16Printable(rSubKey));
143
144 return 0;
145}
146
147// Open or create a key in read-write mode if possible, otherwise read-only.
148// "access" is to explicitly use the 32- or 64-bit branch.
149static HKEY createOrOpenKey(HKEY parentHandle, const QString &rSubKey, bool *readOnly, REGSAM access = 0)
150{
151 // try to open or create it read/write
152 HKEY resultHandle = createOrOpenKey(parentHandle, registryPermissions, rSubKey, access);
153 if (resultHandle != 0) {
154 if (readOnly != 0)
155 *readOnly = false;
156 return resultHandle;
157 }
158
159 // try to open or create it read/only
160 resultHandle = createOrOpenKey(parentHandle, KEY_READ, rSubKey, access);
161 if (resultHandle != 0) {
162 if (readOnly != 0)
163 *readOnly = true;
164 return resultHandle;
165 }
166 return 0;
167}
168
169static QStringList childKeysOrGroups(HKEY parentHandle, QSettingsPrivate::ChildSpec spec)
170{
171 QStringList result;
172 DWORD numKeys;
173 DWORD maxKeySize;
174 DWORD numSubgroups;
175 DWORD maxSubgroupSize;
176
177 // Find the number of keys and subgroups, as well as the max of their lengths.
178 LONG res = RegQueryInfoKey(parentHandle, 0, 0, 0, &numSubgroups, &maxSubgroupSize, 0,
179 &numKeys, &maxKeySize, 0, 0, 0);
180
181 if (res != ERROR_SUCCESS) {
182 qErrnoWarning(int(res), "QSettings: RegQueryInfoKey() failed");
183 return result;
184 }
185
186 ++maxSubgroupSize;
187 ++maxKeySize;
188
189 int n;
190 int m;
191 if (spec == QSettingsPrivate::ChildKeys) {
192 n = numKeys;
193 m = maxKeySize;
194 } else {
195 n = numSubgroups;
196 m = maxSubgroupSize;
197 }
198
199 /* The size does not include the terminating null character. */
200 ++m;
201
202 // Get the list
203 QByteArray buff(m * sizeof(wchar_t), 0);
204 for (int i = 0; i < n; ++i) {
205 QString item;
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);
209 } else {
210 res = RegEnumKeyEx(parentHandle, i, reinterpret_cast<wchar_t *>(buff.data()), &l, 0, 0, 0, 0);
211 }
212 if (res == ERROR_SUCCESS)
213 item = QString::fromWCharArray((const wchar_t *)buff.constData(), l);
214
215 if (res != ERROR_SUCCESS) {
216 qErrnoWarning(int(res), "QSettings: RegEnumValue failed");
217 continue;
218 }
219 if (item.isEmpty())
220 item = "."_L1;
221 result.append(item);
222 }
223 return result;
224}
225
226static void allKeys(HKEY parentHandle, const QString &rSubKey, NameSet *result, REGSAM access = 0)
227{
228 HKEY handle = openKey(parentHandle, KEY_READ, rSubKey, access);
229 if (handle == 0)
230 return;
231
232 QStringList childKeys = childKeysOrGroups(handle, QSettingsPrivate::ChildKeys);
233 QStringList childGroups = childKeysOrGroups(handle, QSettingsPrivate::ChildGroups);
234 RegCloseKey(handle);
235
236 for (int i = 0; i < childKeys.size(); ++i) {
237 QString s = rSubKey;
238 if (!s.isEmpty())
239 s += u'\\';
240 s += childKeys.at(i);
241 result->insert(s, QString());
242 }
243
244 for (int i = 0; i < childGroups.size(); ++i) {
245 QString s = rSubKey;
246 if (!s.isEmpty())
247 s += u'\\';
248 s += childGroups.at(i);
249 allKeys(parentHandle, s, result, access);
250 }
251}
252
253static void deleteChildGroups(HKEY parentHandle, REGSAM access = 0)
254{
255 QStringList childGroups = childKeysOrGroups(parentHandle, QSettingsPrivate::ChildGroups);
256
257 for (int i = 0; i < childGroups.size(); ++i) {
258 QString group = childGroups.at(i);
259
260 // delete subgroups in group
261 HKEY childGroupHandle = openKey(parentHandle, registryPermissions, group, access);
262 if (childGroupHandle == 0)
263 continue;
264 deleteChildGroups(childGroupHandle, access);
265 RegCloseKey(childGroupHandle);
266
267 // delete group itself
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));
272 return;
273 }
274 }
275}
276
277/*******************************************************************************
278** class RegistryKey
279*/
280
282{
283public:
284 RegistryKey(HKEY parent_handle = 0, const QString &key = QString(), bool read_only = true, REGSAM access = 0);
285 QString key() const;
286 HKEY handle() const;
288 bool readOnly() const;
289 void close();
290private:
291 HKEY m_parent_handle;
292 mutable HKEY m_handle;
293 QString m_key;
294 mutable bool m_read_only;
295 REGSAM m_access;
296};
297
298RegistryKey::RegistryKey(HKEY parent_handle, const QString &key, bool read_only, REGSAM access)
300 m_handle(0),
301 m_key(key),
302 m_read_only(read_only),
304{
305}
306
308{
309 return m_key;
310}
311
313{
314 if (m_handle != 0)
315 return m_handle;
316
317 if (m_read_only)
318 m_handle = openKey(m_parent_handle, KEY_READ, m_key, m_access);
319 else
320 m_handle = createOrOpenKey(m_parent_handle, m_key, &m_read_only, m_access);
321
322 return m_handle;
323}
324
326{
327 return m_parent_handle;
328}
329
331{
332 return m_read_only;
333}
334
336{
337 if (m_handle != 0)
338 RegCloseKey(m_handle);
339 m_handle = 0;
340}
341
343
344/*******************************************************************************
345** class QWinSettingsPrivate
346*/
347
349{
351public:
353 const QString &application, REGSAM access = 0);
354 QWinSettingsPrivate(QString rKey, REGSAM access = 0);
356
357 void remove(const QString &uKey) override;
358 void set(const QString &uKey, const QVariant &value) override;
359 std::optional<QVariant> get(const QString &uKey) const override;
360 QStringList children(const QString &uKey, ChildSpec spec) const override;
364 bool isWritable() const override;
366 std::optional<QVariant> readKey(HKEY parentHandle, const QString &rSubKey) const;
367 QString fileName() const override;
368
369private:
370 RegistryKeyList regList; // list of registry locations to search for keys
371 bool deleteWriteHandleOnExit;
372 REGSAM access;
373};
374
375QWinSettingsPrivate::QWinSettingsPrivate(QSettings::Scope scope, const QString &organization,
376 const QString &application, REGSAM access)
377 : QSettingsPrivate(QSettings::NativeFormat, scope, organization, application),
378 access(access)
379{
380 deleteWriteHandleOnExit = false;
381
382 if (!organization.isEmpty()) {
383 QString prefix = "Software\\"_L1 + organization;
384 QString orgPrefix = prefix + "\\OrganizationDefaults"_L1;
385 QString appPrefix = prefix + u'\\' + application;
386
387 if (scope == QSettings::UserScope) {
388 if (!application.isEmpty())
389 regList.append(RegistryKey(HKEY_CURRENT_USER, appPrefix, !regList.isEmpty(), access));
390
391 regList.append(RegistryKey(HKEY_CURRENT_USER, orgPrefix, !regList.isEmpty(), access));
392 }
393
394 if (!application.isEmpty())
395 regList.append(RegistryKey(HKEY_LOCAL_MACHINE, appPrefix, !regList.isEmpty(), access));
396
397 regList.append(RegistryKey(HKEY_LOCAL_MACHINE, orgPrefix, !regList.isEmpty(), access));
398 }
399
400 if (regList.isEmpty())
401 setStatus(QSettings::AccessError);
402}
403
404QWinSettingsPrivate::QWinSettingsPrivate(QString rPath, REGSAM access)
407{
408 deleteWriteHandleOnExit = false;
409
410 if (rPath.startsWith(u'\\'))
411 rPath.remove(0, 1);
412
413 int keyLength;
414 HKEY keyName;
415
416 if (rPath.startsWith("HKEY_CURRENT_USER"_L1)) {
417 keyLength = 17;
418 keyName = HKEY_CURRENT_USER;
419 } else if (rPath.startsWith("HKCU"_L1)) {
420 keyLength = 4;
421 keyName = HKEY_CURRENT_USER;
422 } else if (rPath.startsWith("HKEY_LOCAL_MACHINE"_L1)) {
423 keyLength = 18;
424 keyName = HKEY_LOCAL_MACHINE;
425 } else if (rPath.startsWith("HKLM"_L1)) {
426 keyLength = 4;
427 keyName = HKEY_LOCAL_MACHINE;
428 } else if (rPath.startsWith("HKEY_CLASSES_ROOT"_L1)) {
429 keyLength = 17;
430 keyName = HKEY_CLASSES_ROOT;
431 } else if (rPath.startsWith("HKCR"_L1)) {
432 keyLength = 4;
433 keyName = HKEY_CLASSES_ROOT;
434 } else if (rPath.startsWith("HKEY_USERS"_L1)) {
435 keyLength = 10;
436 keyName = HKEY_USERS;
437 } else if (rPath.startsWith("HKU"_L1)) {
438 keyLength = 3;
439 keyName = HKEY_USERS;
440 } else {
441 return;
442 }
443
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));
448}
449
450std::optional<QVariant> QWinSettingsPrivate::readKey(HKEY parentHandle, const QString &rSubKey) const
451{
452 QString rSubkeyName = keyName(rSubKey);
453 QString rSubkeyPath = keyPath(rSubKey);
454
455 // open a handle on the subkey
456 HKEY handle = openKey(parentHandle, KEY_READ, rSubkeyPath, access);
457 if (handle == 0)
458 return std::nullopt;
459
460 const auto closeKey = qScopeGuard([handle] { RegCloseKey(handle); });
461
462 // get the size and type of the value
463 DWORD dataType;
464 DWORD dataSize;
465 LONG res = RegQueryValueEx(handle, reinterpret_cast<const wchar_t *>(rSubkeyName.utf16()), 0, &dataType, 0, &dataSize);
466 if (res != ERROR_SUCCESS)
467 return std::nullopt;
468
469 // workaround for rare cases where trailing '\0' are missing in registry
470 if (dataType == REG_SZ || dataType == REG_EXPAND_SZ)
471 dataSize += 2;
472 else if (dataType == REG_MULTI_SZ)
473 dataSize += 4;
474
475 // get the value
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)
480 return std::nullopt;
481
482 switch (dataType) {
483 case REG_EXPAND_SZ:
484 case REG_SZ: {
485 QString s;
486 if (dataSize) {
487 s = QString::fromWCharArray(reinterpret_cast<const wchar_t *>(data.constData()));
488 }
489 return stringToVariant(s);
490 }
491
492 case REG_MULTI_SZ: {
493 QStringList l;
494 if (dataSize) {
495 int i = 0;
496 for (;;) {
497 QString s = QString::fromWCharArray(reinterpret_cast<const wchar_t *>(data.constData()) + i);
498 i += s.length() + 1;
499
500 if (s.isEmpty())
501 break;
502 l.append(s);
503 }
504 }
505 return stringListToVariantList(l);
506 }
507
508 case REG_NONE:
509 case REG_BINARY: {
510 QString s;
511 if (dataSize) {
512 s = QString::fromWCharArray(reinterpret_cast<const wchar_t *>(data.constData()), data.size() / 2);
513 }
514 return stringToVariant(s);
515 }
516
517 case REG_DWORD_BIG_ENDIAN:
518 case REG_DWORD: {
519 Q_ASSERT(data.size() == sizeof(int));
520 int i;
521 memcpy(reinterpret_cast<char*>(&i), data.constData(), sizeof(int));
522 return i;
523 }
524
525 case REG_QWORD: {
526 Q_ASSERT(data.size() == sizeof(qint64));
527 qint64 i;
528 memcpy(reinterpret_cast<char*>(&i), data.constData(), sizeof(qint64));
529 return i;
530 }
531
532 default:
533 qWarning("QSettings: Unknown data %d type in Windows registry", static_cast<int>(dataType));
534 break;
535 }
536
537 return std::nullopt;
538}
539
541{
542 if (regList.isEmpty())
543 return 0;
544 const RegistryKey &key = regList.at(0);
545 if (key.handle() == 0 || key.readOnly())
546 return 0;
547 return key.handle();
548}
549
551{
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()));
557 }
558 }
559
560 for (int i = 0; i < regList.size(); ++i)
561 regList[i].close();
562}
563
564void QWinSettingsPrivate::remove(const QString &uKey)
565{
566 if (writeHandle() == 0) {
567 setStatus(QSettings::AccessError);
568 return;
569 }
570
571 QString rKey = escapedKey(uKey);
572
573 // try to delete value bar in key foo
574 LONG res;
575 HKEY handle = openKey(writeHandle(), registryPermissions, keyPath(rKey), access);
576 if (handle != 0) {
577 res = RegDeleteValue(handle, reinterpret_cast<const wchar_t *>(keyName(rKey).utf16()));
578 RegCloseKey(handle);
579 }
580
581 // try to delete key foo/bar and all subkeys
582 handle = openKey(writeHandle(), registryPermissions, rKey, access);
583 if (handle != 0) {
584 deleteChildGroups(handle, access);
585
586 if (rKey.isEmpty()) {
587 const QStringList childKeys = childKeysOrGroups(handle, QSettingsPrivate::ChildKeys);
588
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));
594 }
595 }
596 } else {
597 res = RegDeleteKey(writeHandle(), reinterpret_cast<const wchar_t *>(rKey.utf16()));
598
599 if (res != ERROR_SUCCESS) {
600 qErrnoWarning(int(res), "QSettings: RegDeleteKey failed on key \"%ls\"",
601 qUtf16Printable(rKey));
602 }
603 }
604 RegCloseKey(handle);
605 }
606}
607
608void QWinSettingsPrivate::set(const QString &uKey, const QVariant &value)
609{
610 if (writeHandle() == 0) {
611 setStatus(QSettings::AccessError);
612 return;
613 }
614
615 QString rKey = escapedKey(uKey);
616
617 HKEY handle = createOrOpenKey(writeHandle(), registryPermissions, keyPath(rKey), access);
618 if (handle == 0) {
619 setStatus(QSettings::AccessError);
620 return;
621 }
622
623 DWORD type;
624 QByteArray regValueBuff;
625
626 // Determine the type
627 switch (value.typeId()) {
628 case QMetaType::QVariantList:
629 case QMetaType::QStringList: {
630 // If none of the elements contains '\0', we can use REG_MULTI_SZ, the
631 // native registry string list type. Otherwise we use REG_BINARY.
632 type = REG_MULTI_SZ;
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)) {
637 type = REG_BINARY;
638 break;
639 }
640 }
641
642 if (type == REG_BINARY) {
643 const QString s = variantToString(value);
644 regValueBuff = QByteArray(reinterpret_cast<const char *>(s.data()), s.length() * 2);
645 } else {
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);
650 }
651 regValueBuff.append((char)0);
652 regValueBuff.append((char)0);
653 }
654 break;
655 }
656
657 case QMetaType::Int:
658 case QMetaType::UInt: {
659 type = REG_DWORD;
660 qint32 i = value.toInt();
661 regValueBuff = QByteArray(reinterpret_cast<const char*>(&i), sizeof(qint32));
662 break;
663 }
664
665 case QMetaType::LongLong:
666 case QMetaType::ULongLong: {
667 type = REG_QWORD;
668 qint64 i = value.toLongLong();
669 regValueBuff = QByteArray(reinterpret_cast<const char*>(&i), sizeof(qint64));
670 break;
671 }
672
673 case QMetaType::QByteArray:
674 Q_FALLTHROUGH();
675
676 default: {
677 // If the string does not contain '\0', we can use REG_SZ, the native registry
678 // string type. Otherwise we use REG_BINARY.
679 QString s = variantToString(value);
680 type = s.contains(QChar::Null) ? REG_BINARY : REG_SZ;
681 int length = s.length();
682 if (type == REG_SZ)
683 ++length;
684 regValueBuff = QByteArray(reinterpret_cast<const char *>(s.constData()),
685 int(sizeof(wchar_t)) * length);
686 break;
687 }
688 }
689
690 // set the value
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());
694
695 if (res == ERROR_SUCCESS) {
696 deleteWriteHandleOnExit = false;
697 } else {
698 qErrnoWarning(int(res), "QSettings: failed to set subkey \"%ls\"",
699 qUtf16Printable(rKey));
700 setStatus(QSettings::AccessError);
701 }
702
703 RegCloseKey(handle);
704}
705
706std::optional<QVariant> QWinSettingsPrivate::get(const QString &uKey) const
707{
708 QString rKey = escapedKey(uKey);
709
710 for (const RegistryKey &r : regList) {
711 HKEY handle = r.handle();
712 if (handle != 0) {
713 if (auto result = readKey(handle, rKey))
714 return result;
715 }
716 if (!fallbacks)
717 return std::nullopt;
718 }
719
720 return std::nullopt;
721}
722
723QStringList QWinSettingsPrivate::children(const QString &uKey, ChildSpec spec) const
724{
725 NameSet result;
726 QString rKey = escapedKey(uKey);
727
728 for (const RegistryKey &r : regList) {
729 HKEY parent_handle = r.handle();
730 if (parent_handle == 0) {
731 if (fallbacks)
732 continue;
733 break;
734 }
735 HKEY handle = openKey(parent_handle, KEY_READ, rKey, access);
736 if (handle == 0) {
737 if (fallbacks)
738 continue;
739 break;
740 }
741
742 if (spec == AllKeys) {
743 NameSet keys;
744 allKeys(handle, ""_L1, &keys, access);
745 mergeKeySets(&result, keys);
746 } else { // ChildGroups or ChildKeys
747 QStringList names = childKeysOrGroups(handle, spec);
748 mergeKeySets(&result, names);
749 }
750
751 RegCloseKey(handle);
752
753 if (!fallbacks)
754 return result.keys();
755 }
756
757 return result.keys();
758}
759
761{
762 remove(QString());
763 deleteWriteHandleOnExit = true;
764}
765
767{
768 RegFlushKey(writeHandle());
769}
770
772{
773 // Windows does this for us.
774}
775
777{
778 if (regList.isEmpty())
779 return QString();
780
781 const RegistryKey &key = regList.at(0);
782 QString result;
783 if (key.parentHandle() == HKEY_CURRENT_USER)
784 result = "\\HKEY_CURRENT_USER\\"_L1;
785 else
786 result = "\\HKEY_LOCAL_MACHINE\\"_L1;
787
788 return result + regList.at(0).key();
789}
790
792{
793 return writeHandle() != 0;
794}
795
796QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope,
797 const QString &organization, const QString &application)
798{
799 switch (format) {
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);
806 default:
807 break;
808 }
809 return new QConfFileSettingsPrivate(format, scope, organization, application);
810}
811
812QSettingsPrivate *QSettingsPrivate::create(const QString &fileName, QSettings::Format format)
813{
814 switch (format) {
815 case QSettings::NativeFormat:
816 return new QWinSettingsPrivate(fileName);
817 case QSettings::Registry32Format:
818 return new QWinSettingsPrivate(fileName, KEY_WOW64_32KEY);
819 case QSettings::Registry64Format:
820 return new QWinSettingsPrivate(fileName, KEY_WOW64_64KEY);
821 default:
822 break;
823 }
824 return new QConfFileSettingsPrivate(fileName, format);
825}
826
827QT_END_NAMESPACE
Definition qlist.h:80
void sync() override
~QWinSettingsPrivate() override
void clear() 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
void flush() override
QWinSettingsPrivate(QString rKey, REGSAM access=0)
QString fileName() const override
HKEY handle() const
bool readOnly() const
HKEY parentHandle() const
RegistryKey(HKEY parent_handle=0, const QString &key=QString(), bool read_only=true, REGSAM access=0)
QString key() const
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)
#define KEY_WOW64_32KEY
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)
#define KEY_WOW64_64KEY
static const REGSAM registryPermissions
static HKEY createOrOpenKey(HKEY parentHandle, const QString &rSubKey, bool *readOnly, REGSAM access=0)