summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qsettings_win.cpp
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/corelib/io/qsettings_win.cpp
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/corelib/io/qsettings_win.cpp')
-rw-r--r--src/corelib/io/qsettings_win.cpp847
1 files changed, 847 insertions, 0 deletions
diff --git a/src/corelib/io/qsettings_win.cpp b/src/corelib/io/qsettings_win.cpp
new file mode 100644
index 0000000000..3ef919a5ff
--- /dev/null
+++ b/src/corelib/io/qsettings_win.cpp
@@ -0,0 +1,847 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsettings.h"
+
+#ifndef QT_NO_SETTINGS
+
+#include "qsettings_p.h"
+#include "qvector.h"
+#include "qmap.h"
+#include "qt_windows.h"
+#include "qdebug.h"
+
+QT_BEGIN_NAMESPACE
+
+/* Keys are stored in QStrings. If the variable name starts with 'u', this is a "user"
+ key, ie. "foo/bar/alpha/beta". If the variable name starts with 'r', this is a "registry"
+ key, ie. "\foo\bar\alpha\beta". */
+
+/*******************************************************************************
+** Some convenience functions
+*/
+
+/*
+ We don't use KEY_ALL_ACCESS because it gives more rights than what we
+ need. See task 199061.
+ */
+static const REGSAM registryPermissions = KEY_READ | KEY_WRITE;
+
+static QString keyPath(const QString &rKey)
+{
+ int idx = rKey.lastIndexOf(QLatin1Char('\\'));
+ if (idx == -1)
+ return QString();
+ return rKey.left(idx + 1);
+}
+
+static QString keyName(const QString &rKey)
+{
+ int idx = rKey.lastIndexOf(QLatin1Char('\\'));
+
+ QString res;
+ if (idx == -1)
+ res = rKey;
+ else
+ res = rKey.mid(idx + 1);
+
+ if (res == QLatin1String("Default") || res == QLatin1String("."))
+ res = QLatin1String("");
+
+ return res;
+}
+
+static QString escapedKey(QString uKey)
+{
+ QChar *data = uKey.data();
+ int l = uKey.length();
+ for (int i = 0; i < l; ++i) {
+ ushort &ucs = data[i].unicode();
+ if (ucs == '\\')
+ ucs = '/';
+ else if (ucs == '/')
+ ucs = '\\';
+ }
+ return uKey;
+}
+
+static QString unescapedKey(QString rKey)
+{
+ return escapedKey(rKey);
+}
+
+typedef QMap<QString, QString> NameSet;
+
+static void mergeKeySets(NameSet *dest, const NameSet &src)
+{
+ NameSet::const_iterator it = src.constBegin();
+ for (; it != src.constEnd(); ++it)
+ dest->insert(unescapedKey(it.key()), QString());
+}
+
+static void mergeKeySets(NameSet *dest, const QStringList &src)
+{
+ QStringList::const_iterator it = src.constBegin();
+ for (; it != src.constEnd(); ++it)
+ dest->insert(unescapedKey(*it), QString());
+}
+
+/*******************************************************************************
+** Wrappers for the insane windows registry API
+*/
+
+static QString errorCodeToString(DWORD errorCode)
+{
+ wchar_t *data = 0;
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, errorCode, 0, data, 0, 0);
+ QString result = QString::fromWCharArray(data);
+
+ if (data != 0)
+ LocalFree(data);
+
+ if (result.endsWith(QLatin1Char('\n')))
+ result.truncate(result.length() - 1);
+
+ return result;
+}
+
+// Open a key with the specified perms
+static HKEY openKey(HKEY parentHandle, REGSAM perms, const QString &rSubKey)
+{
+ HKEY resultHandle = 0;
+ LONG res = RegOpenKeyEx(parentHandle, reinterpret_cast<const wchar_t *>(rSubKey.utf16()),
+ 0, perms, &resultHandle);
+
+ if (res == ERROR_SUCCESS)
+ return resultHandle;
+
+ return 0;
+}
+
+// Open a key with the specified perms, create it if it does not exist
+static HKEY createOrOpenKey(HKEY parentHandle, REGSAM perms, const QString &rSubKey)
+{
+ // try to open it
+ HKEY resultHandle = openKey(parentHandle, perms, rSubKey);
+ if (resultHandle != 0)
+ return resultHandle;
+
+ // try to create it
+ LONG res = RegCreateKeyEx(parentHandle, reinterpret_cast<const wchar_t *>(rSubKey.utf16()), 0, 0,
+ REG_OPTION_NON_VOLATILE, perms, 0, &resultHandle, 0);
+
+ if (res == ERROR_SUCCESS)
+ return resultHandle;
+
+ //qWarning("QSettings: Failed to create subkey \"%s\": %s",
+ // rSubKey.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+
+ return 0;
+}
+
+// Open or create a key in read-write mode if possible, otherwise read-only
+static HKEY createOrOpenKey(HKEY parentHandle, const QString &rSubKey, bool *readOnly)
+{
+ // try to open or create it read/write
+ HKEY resultHandle = createOrOpenKey(parentHandle, registryPermissions, rSubKey);
+ if (resultHandle != 0) {
+ if (readOnly != 0)
+ *readOnly = false;
+ return resultHandle;
+ }
+
+ // try to open or create it read/only
+ resultHandle = createOrOpenKey(parentHandle, KEY_READ, rSubKey);
+ if (resultHandle != 0) {
+ if (readOnly != 0)
+ *readOnly = true;
+ return resultHandle;
+ }
+ return 0;
+}
+
+static QStringList childKeysOrGroups(HKEY parentHandle, QSettingsPrivate::ChildSpec spec)
+{
+ QStringList result;
+ DWORD numKeys;
+ DWORD maxKeySize;
+ DWORD numSubgroups;
+ DWORD maxSubgroupSize;
+
+ // Find the number of keys and subgroups, as well as the max of their lengths.
+ LONG res = RegQueryInfoKey(parentHandle, 0, 0, 0, &numSubgroups, &maxSubgroupSize, 0,
+ &numKeys, &maxKeySize, 0, 0, 0);
+
+ if (res != ERROR_SUCCESS) {
+ qWarning("QSettings: RegQueryInfoKey() failed: %s", errorCodeToString(res).toLatin1().data());
+ return result;
+ }
+
+ ++maxSubgroupSize;
+ ++maxKeySize;
+
+ int n;
+ int m;
+ if (spec == QSettingsPrivate::ChildKeys) {
+ n = numKeys;
+ m = maxKeySize;
+ } else {
+ n = numSubgroups;
+ m = maxSubgroupSize;
+ }
+
+ /* The size does not include the terminating null character. */
+ ++m;
+
+ // Get the list
+ QByteArray buff(m * sizeof(wchar_t), 0);
+ for (int i = 0; i < n; ++i) {
+ QString item;
+ DWORD l = buff.size() / sizeof(wchar_t);
+ if (spec == QSettingsPrivate::ChildKeys) {
+ res = RegEnumValue(parentHandle, i, reinterpret_cast<wchar_t *>(buff.data()), &l, 0, 0, 0, 0);
+ } else {
+ res = RegEnumKeyEx(parentHandle, i, reinterpret_cast<wchar_t *>(buff.data()), &l, 0, 0, 0, 0);
+ }
+ if (res == ERROR_SUCCESS)
+ item = QString::fromWCharArray((const wchar_t *)buff.constData(), l);
+
+ if (res != ERROR_SUCCESS) {
+ qWarning("QSettings: RegEnumValue failed: %s", errorCodeToString(res).toLatin1().data());
+ continue;
+ }
+ if (item.isEmpty())
+ item = QLatin1String(".");
+ result.append(item);
+ }
+ return result;
+}
+
+static void allKeys(HKEY parentHandle, const QString &rSubKey, NameSet *result)
+{
+ HKEY handle = openKey(parentHandle, KEY_READ, rSubKey);
+ if (handle == 0)
+ return;
+
+ QStringList childKeys = childKeysOrGroups(handle, QSettingsPrivate::ChildKeys);
+ QStringList childGroups = childKeysOrGroups(handle, QSettingsPrivate::ChildGroups);
+ RegCloseKey(handle);
+
+ for (int i = 0; i < childKeys.size(); ++i) {
+ QString s = rSubKey;
+ if (!s.isEmpty())
+ s += QLatin1Char('\\');
+ s += childKeys.at(i);
+ result->insert(s, QString());
+ }
+
+ for (int i = 0; i < childGroups.size(); ++i) {
+ QString s = rSubKey;
+ if (!s.isEmpty())
+ s += QLatin1Char('\\');
+ s += childGroups.at(i);
+ allKeys(parentHandle, s, result);
+ }
+}
+
+static void deleteChildGroups(HKEY parentHandle)
+{
+ QStringList childGroups = childKeysOrGroups(parentHandle, QSettingsPrivate::ChildGroups);
+
+ for (int i = 0; i < childGroups.size(); ++i) {
+ QString group = childGroups.at(i);
+
+ // delete subgroups in group
+ HKEY childGroupHandle = openKey(parentHandle, registryPermissions, group);
+ if (childGroupHandle == 0)
+ continue;
+ deleteChildGroups(childGroupHandle);
+ RegCloseKey(childGroupHandle);
+
+ // delete group itself
+ LONG res = RegDeleteKey(parentHandle, reinterpret_cast<const wchar_t *>(group.utf16()));
+ if (res != ERROR_SUCCESS) {
+ qWarning("QSettings: RegDeleteKey failed on subkey \"%s\": %s",
+ group.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ return;
+ }
+ }
+}
+
+/*******************************************************************************
+** class RegistryKey
+*/
+
+class RegistryKey
+{
+public:
+ RegistryKey(HKEY parent_handle = 0, const QString &key = QString(), bool read_only = true);
+ QString key() const;
+ HKEY handle() const;
+ HKEY parentHandle() const;
+ bool readOnly() const;
+ void close();
+private:
+ HKEY m_parent_handle;
+ mutable HKEY m_handle;
+ QString m_key;
+ mutable bool m_read_only;
+};
+
+RegistryKey::RegistryKey(HKEY parent_handle, const QString &key, bool read_only)
+{
+ m_parent_handle = parent_handle;
+ m_handle = 0;
+ m_read_only = read_only;
+ m_key = key;
+}
+
+QString RegistryKey::key() const
+{
+ return m_key;
+}
+
+HKEY RegistryKey::handle() const
+{
+ if (m_handle != 0)
+ return m_handle;
+
+ if (m_read_only)
+ m_handle = openKey(m_parent_handle, KEY_READ, m_key);
+ else
+ m_handle = createOrOpenKey(m_parent_handle, m_key, &m_read_only);
+
+ return m_handle;
+}
+
+HKEY RegistryKey::parentHandle() const
+{
+ return m_parent_handle;
+}
+
+bool RegistryKey::readOnly() const
+{
+ return m_read_only;
+}
+
+void RegistryKey::close()
+{
+ if (m_handle != 0)
+ RegCloseKey(m_handle);
+ m_handle = 0;
+}
+
+typedef QVector<RegistryKey> RegistryKeyList;
+
+/*******************************************************************************
+** class QWinSettingsPrivate
+*/
+
+class QWinSettingsPrivate : public QSettingsPrivate
+{
+public:
+ QWinSettingsPrivate(QSettings::Scope scope, const QString &organization,
+ const QString &application);
+ QWinSettingsPrivate(QString rKey);
+ ~QWinSettingsPrivate();
+
+ void remove(const QString &uKey);
+ void set(const QString &uKey, const QVariant &value);
+ bool get(const QString &uKey, QVariant *value) const;
+ QStringList children(const QString &uKey, ChildSpec spec) const;
+ void clear();
+ void sync();
+ void flush();
+ bool isWritable() const;
+ HKEY writeHandle() const;
+ bool readKey(HKEY parentHandle, const QString &rSubKey, QVariant *value) const;
+ QString fileName() const;
+
+private:
+ RegistryKeyList regList; // list of registry locations to search for keys
+ bool deleteWriteHandleOnExit;
+};
+
+QWinSettingsPrivate::QWinSettingsPrivate(QSettings::Scope scope, const QString &organization,
+ const QString &application)
+ : QSettingsPrivate(QSettings::NativeFormat, scope, organization, application)
+{
+ deleteWriteHandleOnExit = false;
+
+ if (!organization.isEmpty()) {
+ QString prefix = QLatin1String("Software\\") + organization;
+ QString orgPrefix = prefix + QLatin1String("\\OrganizationDefaults");
+ QString appPrefix = prefix + QLatin1Char('\\') + application;
+
+ if (scope == QSettings::UserScope) {
+ if (!application.isEmpty())
+ regList.append(RegistryKey(HKEY_CURRENT_USER, appPrefix, !regList.isEmpty()));
+
+ regList.append(RegistryKey(HKEY_CURRENT_USER, orgPrefix, !regList.isEmpty()));
+ }
+
+ if (!application.isEmpty())
+ regList.append(RegistryKey(HKEY_LOCAL_MACHINE, appPrefix, !regList.isEmpty()));
+
+ regList.append(RegistryKey(HKEY_LOCAL_MACHINE, orgPrefix, !regList.isEmpty()));
+ }
+
+ if (regList.isEmpty())
+ setStatus(QSettings::AccessError);
+}
+
+QWinSettingsPrivate::QWinSettingsPrivate(QString rPath)
+ : QSettingsPrivate(QSettings::NativeFormat)
+{
+ deleteWriteHandleOnExit = false;
+
+ if (rPath.startsWith(QLatin1String("\\")))
+ rPath = rPath.mid(1);
+
+ if (rPath.startsWith(QLatin1String("HKEY_CURRENT_USER\\")))
+ regList.append(RegistryKey(HKEY_CURRENT_USER, rPath.mid(18), false));
+ else if (rPath == QLatin1String("HKEY_CURRENT_USER"))
+ regList.append(RegistryKey(HKEY_CURRENT_USER, QString(), false));
+ else if (rPath.startsWith(QLatin1String("HKEY_LOCAL_MACHINE\\")))
+ regList.append(RegistryKey(HKEY_LOCAL_MACHINE, rPath.mid(19), false));
+ else if (rPath == QLatin1String("HKEY_LOCAL_MACHINE"))
+ regList.append(RegistryKey(HKEY_LOCAL_MACHINE, QString(), false));
+ else if (rPath.startsWith(QLatin1String("HKEY_CLASSES_ROOT\\")))
+ regList.append(RegistryKey(HKEY_CLASSES_ROOT, rPath.mid(18), false));
+ else if (rPath == QLatin1String("HKEY_CLASSES_ROOT"))
+ regList.append(RegistryKey(HKEY_CLASSES_ROOT, QString(), false));
+ else if (rPath.startsWith(QLatin1String("HKEY_USERS\\")))
+ regList.append(RegistryKey(HKEY_USERS, rPath.mid(11), false));
+ else if (rPath == QLatin1String(QLatin1String("HKEY_USERS")))
+ regList.append(RegistryKey(HKEY_USERS, QString(), false));
+ else
+ regList.append(RegistryKey(HKEY_LOCAL_MACHINE, rPath, false));
+}
+
+bool QWinSettingsPrivate::readKey(HKEY parentHandle, const QString &rSubKey, QVariant *value) const
+{
+ QString rSubkeyName = keyName(rSubKey);
+ QString rSubkeyPath = keyPath(rSubKey);
+
+ // open a handle on the subkey
+ HKEY handle = openKey(parentHandle, KEY_READ, rSubkeyPath);
+ if (handle == 0)
+ return false;
+
+ // get the size and type of the value
+ DWORD dataType;
+ DWORD dataSize;
+ LONG res = RegQueryValueEx(handle, reinterpret_cast<const wchar_t *>(rSubkeyName.utf16()), 0, &dataType, 0, &dataSize);
+ if (res != ERROR_SUCCESS) {
+ RegCloseKey(handle);
+ return false;
+ }
+
+ // get the value
+ QByteArray data(dataSize, 0);
+ res = RegQueryValueEx(handle, reinterpret_cast<const wchar_t *>(rSubkeyName.utf16()), 0, 0,
+ reinterpret_cast<unsigned char*>(data.data()), &dataSize);
+ if (res != ERROR_SUCCESS) {
+ RegCloseKey(handle);
+ return false;
+ }
+
+ switch (dataType) {
+ case REG_EXPAND_SZ:
+ case REG_SZ: {
+ QString s;
+ if (dataSize) {
+ s = QString::fromWCharArray(((const wchar_t *)data.constData()));
+ }
+ if (value != 0)
+ *value = stringToVariant(s);
+ break;
+ }
+
+ case REG_MULTI_SZ: {
+ QStringList l;
+ if (dataSize) {
+ int i = 0;
+ for (;;) {
+ QString s = QString::fromWCharArray((const wchar_t *)data.constData() + i);
+ i += s.length() + 1;
+
+ if (s.isEmpty())
+ break;
+ l.append(s);
+ }
+ }
+ if (value != 0)
+ *value = stringListToVariantList(l);
+ break;
+ }
+
+ case REG_NONE:
+ case REG_BINARY: {
+ QString s;
+ if (dataSize) {
+ s = QString::fromWCharArray((const wchar_t *)data.constData(), data.size() / 2);
+ }
+ if (value != 0)
+ *value = stringToVariant(s);
+ break;
+ }
+
+ case REG_DWORD_BIG_ENDIAN:
+ case REG_DWORD: {
+ Q_ASSERT(data.size() == sizeof(int));
+ int i;
+ memcpy((char*)&i, data.constData(), sizeof(int));
+ if (value != 0)
+ *value = i;
+ break;
+ }
+
+ case REG_QWORD: {
+ Q_ASSERT(data.size() == sizeof(qint64));
+ qint64 i;
+ memcpy((char*)&i, data.constData(), sizeof(qint64));
+ if (value != 0)
+ *value = i;
+ break;
+ }
+
+ default:
+ qWarning("QSettings: Unknown data %d type in Windows registry", static_cast<int>(dataType));
+ if (value != 0)
+ *value = QVariant();
+ break;
+ }
+
+ RegCloseKey(handle);
+ return true;
+}
+
+HKEY QWinSettingsPrivate::writeHandle() const
+{
+ if (regList.isEmpty())
+ return 0;
+ const RegistryKey &key = regList.at(0);
+ if (key.handle() == 0 || key.readOnly())
+ return 0;
+ return key.handle();
+}
+
+QWinSettingsPrivate::~QWinSettingsPrivate()
+{
+ if (deleteWriteHandleOnExit && writeHandle() != 0) {
+#if defined(Q_OS_WINCE)
+ remove(regList.at(0).key());
+#else
+ QString emptyKey;
+ DWORD res = RegDeleteKey(writeHandle(), reinterpret_cast<const wchar_t *>(emptyKey.utf16()));
+ if (res != ERROR_SUCCESS) {
+ qWarning("QSettings: Failed to delete key \"%s\": %s",
+ regList.at(0).key().toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ }
+#endif
+ }
+
+ for (int i = 0; i < regList.size(); ++i)
+ regList[i].close();
+}
+
+void QWinSettingsPrivate::remove(const QString &uKey)
+{
+ if (writeHandle() == 0) {
+ setStatus(QSettings::AccessError);
+ return;
+ }
+
+ QString rKey = escapedKey(uKey);
+
+ // try to delete value bar in key foo
+ LONG res;
+ HKEY handle = openKey(writeHandle(), registryPermissions, keyPath(rKey));
+ if (handle != 0) {
+ res = RegDeleteValue(handle, reinterpret_cast<const wchar_t *>(keyName(rKey).utf16()));
+ RegCloseKey(handle);
+ }
+
+ // try to delete key foo/bar and all subkeys
+ handle = openKey(writeHandle(), registryPermissions, rKey);
+ if (handle != 0) {
+ deleteChildGroups(handle);
+
+ if (rKey.isEmpty()) {
+ QStringList childKeys = childKeysOrGroups(handle, QSettingsPrivate::ChildKeys);
+
+ for (int i = 0; i < childKeys.size(); ++i) {
+ QString group = childKeys.at(i);
+
+ LONG res = RegDeleteValue(handle, reinterpret_cast<const wchar_t *>(group.utf16()));
+ if (res != ERROR_SUCCESS) {
+ qWarning("QSettings: RegDeleteValue failed on subkey \"%s\": %s",
+ group.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ }
+ }
+ } else {
+#if defined(Q_OS_WINCE)
+ // For WinCE always Close the handle first.
+ RegCloseKey(handle);
+#endif
+ res = RegDeleteKey(writeHandle(), reinterpret_cast<const wchar_t *>(rKey.utf16()));
+
+ if (res != ERROR_SUCCESS) {
+ qWarning("QSettings: RegDeleteKey failed on key \"%s\": %s",
+ rKey.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ }
+ }
+ RegCloseKey(handle);
+ }
+}
+
+static bool stringContainsNullChar(const QString &s)
+{
+ for (int i = 0; i < s.length(); ++i) {
+ if (s.at(i).unicode() == 0)
+ return true;
+ }
+ return false;
+}
+
+void QWinSettingsPrivate::set(const QString &uKey, const QVariant &value)
+{
+ if (writeHandle() == 0) {
+ setStatus(QSettings::AccessError);
+ return;
+ }
+
+ QString rKey = escapedKey(uKey);
+
+ HKEY handle = createOrOpenKey(writeHandle(), registryPermissions, keyPath(rKey));
+ if (handle == 0) {
+ setStatus(QSettings::AccessError);
+ return;
+ }
+
+ DWORD type;
+ QByteArray regValueBuff;
+
+ // Determine the type
+ switch (value.type()) {
+ case QVariant::List:
+ case QVariant::StringList: {
+ // If none of the elements contains '\0', we can use REG_MULTI_SZ, the
+ // native registry string list type. Otherwise we use REG_BINARY.
+ type = REG_MULTI_SZ;
+ QStringList l = variantListToStringList(value.toList());
+ QStringList::const_iterator it = l.constBegin();
+ for (; it != l.constEnd(); ++it) {
+ if ((*it).length() == 0 || stringContainsNullChar(*it)) {
+ type = REG_BINARY;
+ break;
+ }
+ }
+
+ if (type == REG_BINARY) {
+ QString s = variantToString(value);
+ regValueBuff = QByteArray((const char*)s.utf16(), s.length() * 2);
+ } else {
+ QStringList::const_iterator it = l.constBegin();
+ for (; it != l.constEnd(); ++it) {
+ const QString &s = *it;
+ regValueBuff += QByteArray((const char*)s.utf16(), (s.length() + 1) * 2);
+ }
+ regValueBuff.append((char)0);
+ regValueBuff.append((char)0);
+ }
+ break;
+ }
+
+ case QVariant::Int:
+ case QVariant::UInt: {
+ type = REG_DWORD;
+ qint32 i = value.toInt();
+ regValueBuff = QByteArray((const char*)&i, sizeof(qint32));
+ break;
+ }
+
+ case QVariant::LongLong:
+ case QVariant::ULongLong: {
+ type = REG_QWORD;
+ qint64 i = value.toLongLong();
+ regValueBuff = QByteArray((const char*)&i, sizeof(qint64));
+ break;
+ }
+
+ case QVariant::ByteArray:
+ // fallthrough intended
+
+ default: {
+ // If the string does not contain '\0', we can use REG_SZ, the native registry
+ // string type. Otherwise we use REG_BINARY.
+ QString s = variantToString(value);
+ type = stringContainsNullChar(s) ? REG_BINARY : REG_SZ;
+ if (type == REG_BINARY) {
+ regValueBuff = QByteArray((const char*)s.utf16(), s.length() * 2);
+ } else {
+ regValueBuff = QByteArray((const char*)s.utf16(), (s.length() + 1) * 2);
+ }
+ break;
+ }
+ }
+
+ // set the value
+ LONG res = RegSetValueEx(handle, reinterpret_cast<const wchar_t *>(keyName(rKey).utf16()), 0, type,
+ reinterpret_cast<const unsigned char*>(regValueBuff.constData()),
+ regValueBuff.size());
+
+ if (res == ERROR_SUCCESS) {
+ deleteWriteHandleOnExit = false;
+ } else {
+ qWarning("QSettings: failed to set subkey \"%s\": %s",
+ rKey.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ setStatus(QSettings::AccessError);
+ }
+
+ RegCloseKey(handle);
+}
+
+bool QWinSettingsPrivate::get(const QString &uKey, QVariant *value) const
+{
+ QString rKey = escapedKey(uKey);
+
+ for (int i = 0; i < regList.size(); ++i) {
+ HKEY handle = regList.at(i).handle();
+ if (handle != 0 && readKey(handle, rKey, value))
+ return true;
+
+ if (!fallbacks)
+ return false;
+ }
+
+ return false;
+}
+
+QStringList QWinSettingsPrivate::children(const QString &uKey, ChildSpec spec) const
+{
+ NameSet result;
+ QString rKey = escapedKey(uKey);
+
+ for (int i = 0; i < regList.size(); ++i) {
+ HKEY parent_handle = regList.at(i).handle();
+ if (parent_handle == 0)
+ continue;
+ HKEY handle = openKey(parent_handle, KEY_READ, rKey);
+ if (handle == 0)
+ continue;
+
+ if (spec == AllKeys) {
+ NameSet keys;
+ allKeys(handle, QLatin1String(""), &keys);
+ mergeKeySets(&result, keys);
+ } else { // ChildGroups or ChildKeys
+ QStringList names = childKeysOrGroups(handle, spec);
+ mergeKeySets(&result, names);
+ }
+
+ RegCloseKey(handle);
+
+ if (!fallbacks)
+ return result.keys();
+ }
+
+ return result.keys();
+}
+
+void QWinSettingsPrivate::clear()
+{
+ remove(QString());
+ deleteWriteHandleOnExit = true;
+}
+
+void QWinSettingsPrivate::sync()
+{
+ RegFlushKey(writeHandle());
+}
+
+void QWinSettingsPrivate::flush()
+{
+ // Windows does this for us.
+}
+
+QString QWinSettingsPrivate::fileName() const
+{
+ if (regList.isEmpty())
+ return QString();
+
+ const RegistryKey &key = regList.at(0);
+ QString result;
+ if (key.parentHandle() == HKEY_CURRENT_USER)
+ result = QLatin1String("\\HKEY_CURRENT_USER\\");
+ else
+ result = QLatin1String("\\HKEY_LOCAL_MACHINE\\");
+
+ return result + regList.at(0).key();
+}
+
+bool QWinSettingsPrivate::isWritable() const
+{
+ return writeHandle() != 0;
+}
+
+QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope,
+ const QString &organization, const QString &application)
+{
+ if (format == QSettings::NativeFormat) {
+ return new QWinSettingsPrivate(scope, organization, application);
+ } else {
+ return new QConfFileSettingsPrivate(format, scope, organization, application);
+ }
+}
+
+QSettingsPrivate *QSettingsPrivate::create(const QString &fileName, QSettings::Format format)
+{
+ if (format == QSettings::NativeFormat) {
+ return new QWinSettingsPrivate(fileName);
+ } else {
+ return new QConfFileSettingsPrivate(fileName, format);
+ }
+}
+
+QT_END_NAMESPACE
+#endif // QT_NO_SETTINGS