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