From f89ac0101ad4a6cb5339a3bfe132aad897eafc9d Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 14 Dec 2018 21:12:11 +0100 Subject: qmake: add $$read_registry() function Change-Id: I7f9f17e0f44c273e4754d1decc92a8594cad8658 Reviewed-by: Simon Hausmann --- qmake/library/qmakebuiltins.cpp | 40 +++++++++- qmake/library/registry.cpp | 158 ++++++++++++++++++++++++++++++++++++++++ qmake/library/registry_p.h | 73 +++++++++++++++++++ 3 files changed, 270 insertions(+), 1 deletion(-) create mode 100644 qmake/library/registry.cpp create mode 100644 qmake/library/registry_p.h (limited to 'qmake/library') diff --git a/qmake/library/qmakebuiltins.cpp b/qmake/library/qmakebuiltins.cpp index f81bec158b..dd7766c8e0 100644 --- a/qmake/library/qmakebuiltins.cpp +++ b/qmake/library/qmakebuiltins.cpp @@ -52,6 +52,9 @@ # include #endif #include +#ifdef Q_OS_WIN +# include +#endif #include @@ -93,7 +96,7 @@ enum ExpandFunc { E_UPPER, E_LOWER, E_TITLE, E_FILES, E_PROMPT, E_RE_ESCAPE, E_VAL_ESCAPE, E_REPLACE, E_SORT_DEPENDS, E_RESOLVE_DEPENDS, E_ENUMERATE_VARS, E_SHADOWED, E_ABSOLUTE_PATH, E_RELATIVE_PATH, E_CLEAN_PATH, - E_SYSTEM_PATH, E_SHELL_PATH, E_SYSTEM_QUOTE, E_SHELL_QUOTE, E_GETENV + E_SYSTEM_PATH, E_SHELL_PATH, E_SYSTEM_QUOTE, E_SHELL_QUOTE, E_GETENV, E_READ_REGISTRY }; enum TestFunc { @@ -190,6 +193,7 @@ void QMakeEvaluator::initFunctionStatics() { "system_quote", E_SYSTEM_QUOTE, -1, 1, "arg" }, { "shell_quote", E_SHELL_QUOTE, -1, 1, "arg" }, { "getenv", E_GETENV, 1, 1, "arg" }, + { "read_registry", E_READ_REGISTRY, 2, 3, "tree, key, [wow64]" }, }; statics.expands.reserve((int)(sizeof(expandInits)/sizeof(expandInits[0]))); for (unsigned i = 0; i < sizeof(expandInits)/sizeof(expandInits[0]); ++i) @@ -1214,6 +1218,40 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( ret << ProString(m_option->getEnv(u1.str())); break; } +#ifdef Q_OS_WIN + case E_READ_REGISTRY: { + HKEY tree; + const auto par = args.at(0); + if (!par.compare(QLatin1String("HKCU"), Qt::CaseInsensitive) + || !par.compare(QLatin1String("HKEY_CURRENT_USER"), Qt::CaseInsensitive)) { + tree = HKEY_CURRENT_USER; + } else if (!par.compare(QLatin1String("HKLM"), Qt::CaseInsensitive) + || !par.compare(QLatin1String("HKEY_LOCAL_MACHINE"), Qt::CaseInsensitive)) { + tree = HKEY_LOCAL_MACHINE; + } else { + evalError(fL1S("read_registry(): invalid or unsupported registry tree %1.") + .arg(par.toQStringView())); + goto allfail; + } + int flags = 0; + if (args.count() > 2) { + const auto opt = args.at(2); + if (opt == "32" + || !opt.compare(QLatin1String("wow64_32key"), Qt::CaseInsensitive)) { + flags = KEY_WOW64_32KEY; + } else if (opt == "64" + || !opt.compare(QLatin1String("wow64_64key"), Qt::CaseInsensitive)) { + flags = KEY_WOW64_64KEY; + } else { + evalError(fL1S("read_registry(): invalid option %1.") + .arg(opt.toQStringView())); + goto allfail; + } + } + ret << ProString(qt_readRegistryKey(tree, args.at(1).toQString(m_tmp1), flags)); + break; + } +#endif default: evalError(fL1S("Function '%1' is not implemented.").arg(func.toQStringView())); break; diff --git a/qmake/library/registry.cpp b/qmake/library/registry.cpp new file mode 100644 index 0000000000..3391ab9512 --- /dev/null +++ b/qmake/library/registry.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the qmake application of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "registry_p.h" + +QT_BEGIN_NAMESPACE + +#ifdef Q_OS_WIN32 +/* + Returns the path part of a registry key. + e.g. + For a key + "Software\\Microsoft\\VisualStudio\\8.0\\Setup\\VC\\ProductDir" + it returns + "Software\\Microsoft\\VisualStudio\\8.0\\Setup\\VC\\" +*/ +static QString keyPath(const QString &rKey) +{ + int idx = rKey.lastIndexOf(QLatin1Char('\\')); + if (idx == -1) + return QString(); + return rKey.left(idx + 1); +} + +/* + Returns the name part of a registry key. + e.g. + For a key + "Software\\Microsoft\\VisualStudio\\8.0\\Setup\\VC\\ProductDir" + it returns + "ProductDir" +*/ +static QString keyName(const QString &rKey) +{ + int idx = rKey.lastIndexOf(QLatin1Char('\\')); + if (idx == -1) + return rKey; + + QString res(rKey.mid(idx + 1)); + if (res == QLatin1String("Default") || res == QLatin1String(".")) + res = QString(); + return res; +} +#endif + +QString qt_readRegistryKey(HKEY parentHandle, const QString &rSubkey, unsigned long options) +{ + QString result; + +#ifdef Q_OS_WIN32 + QString rSubkeyName = keyName(rSubkey); + QString rSubkeyPath = keyPath(rSubkey); + + HKEY handle = nullptr; + LONG res = RegOpenKeyEx(parentHandle, (wchar_t*)rSubkeyPath.utf16(), 0, + KEY_READ | options, &handle); + + if (res != ERROR_SUCCESS) + return QString(); + + // get the size and type of the value + DWORD dataType; + DWORD dataSize; + res = RegQueryValueEx(handle, (wchar_t*)rSubkeyName.utf16(), nullptr, &dataType, nullptr, &dataSize); + if (res != ERROR_SUCCESS) { + RegCloseKey(handle); + return QString(); + } + + // get the value + QByteArray data(dataSize, 0); + res = RegQueryValueEx(handle, (wchar_t*)rSubkeyName.utf16(), nullptr, nullptr, + reinterpret_cast(data.data()), &dataSize); + if (res != ERROR_SUCCESS) { + RegCloseKey(handle); + return QString(); + } + + switch (dataType) { + case REG_EXPAND_SZ: + case REG_SZ: { + result = QString::fromWCharArray(((const wchar_t *)data.constData())); + break; + } + + case REG_MULTI_SZ: { + QStringList l; + 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); + } + result = l.join(QLatin1String(", ")); + break; + } + + case REG_NONE: + case REG_BINARY: { + result = QString::fromWCharArray((const wchar_t *)data.constData(), data.size() / 2); + break; + } + + case REG_DWORD_BIG_ENDIAN: + case REG_DWORD: { + Q_ASSERT(data.size() == sizeof(int)); + int i; + memcpy((char*)&i, data.constData(), sizeof(int)); + result = QString::number(i); + break; + } + + default: + qWarning("QSettings: unknown data %u type in windows registry", quint32(dataType)); + break; + } + + RegCloseKey(handle); +#else + Q_UNUSED(parentHandle); + Q_UNUSED(rSubkey) + Q_UNUSED(options); +#endif + + return result; +} + +QT_END_NAMESPACE + diff --git a/qmake/library/registry_p.h b/qmake/library/registry_p.h new file mode 100644 index 0000000000..f9e8bba016 --- /dev/null +++ b/qmake/library/registry_p.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the qmake application of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT_WINDOWS_REGISTRY_H +#define QT_WINDOWS_REGISTRY_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#ifdef Q_OS_WIN32 + #include +#else + typedef void* HKEY; +#endif + +#include + +QT_BEGIN_NAMESPACE + +/** + * Read a value from the Windows registry. + * + * If the key is not found, or the registry cannot be accessed (for example + * if this code is compiled for a platform other than Windows), a null + * string is returned. + * + * 32-bit code reads from the registry's 32 bit view (Wow6432Node), + * 64 bit code reads from the 64 bit view. + * Pass KEY_WOW64_32KEY to access the 32 bit view regardless of the + * application's architecture, KEY_WOW64_64KEY respectively. + */ +QString qt_readRegistryKey(HKEY parentHandle, const QString &rSubkey, + unsigned long options = 0); + +QT_END_NAMESPACE + +#endif // QT_WINDOWS_REGISTRY_H + -- cgit v1.2.3