qmake: add $$read_registry() function

Fixes: QTCREATORBUG-21973
Written-by: Oswald Buddenhagen <oswald.buddenhagen@qt.io>
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
(cherry-picked from qtbase/f89ac0101ad4a6cb5339a3bfe132aad897eafc9d)
Change-Id: I6f67eec7c715686074dd3bdc121170c26daf56da
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
This commit is contained in:
Christian Kandeler
2019-02-18 14:22:39 +01:00
parent 29492ecf24
commit 08e1fbbbfa
6 changed files with 268 additions and 2 deletions

View File

@@ -19,6 +19,10 @@ Project {
"QMAKE_LIBRARY",
"QMAKE_BUILTIN_PRFS",
])
Properties {
condition: qbs.targetOS.contains("windows")
cpp.dynamicLibraries: "advapi32"
}
Export {
Depends { name: "ProParser" }
@@ -48,6 +52,8 @@ Project {
"qmakeparser.h",
"qmakevfs.cpp",
"qmakevfs.h",
"registry.cpp",
"registry_p.h",
]
}

View File

@@ -15,6 +15,7 @@ HEADERS += \
proitems.h \
prowriter.h \
qmakevfs.h \
registry_p.h \
ioutils.h
SOURCES += \
@@ -26,6 +27,7 @@ SOURCES += \
proitems.cpp \
prowriter.cpp \
qmakevfs.cpp \
registry.cpp \
ioutils.cpp
RESOURCES += proparser.qrc

View File

@@ -31,6 +31,10 @@
#include "qmakevfs.h"
#include "ioutils.h"
#ifdef Q_OS_WIN
# include "registry_p.h"
#endif
#include <qbytearray.h>
#include <qdir.h>
#include <qfile.h>
@@ -88,7 +92,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 {
@@ -153,6 +157,7 @@ void QMakeEvaluator::initFunctionStatics()
{ "system_quote", E_SYSTEM_QUOTE },
{ "shell_quote", E_SHELL_QUOTE },
{ "getenv", E_GETENV },
{ "read_registry", E_READ_REGISTRY },
};
statics.expands.reserve((int)(sizeof(expandInits)/sizeof(expandInits[0])));
for (unsigned i = 0; i < sizeof(expandInits)/sizeof(expandInits[0]); ++i)
@@ -1265,6 +1270,41 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
ret << val;
}
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.toQString()));
goto rrfail;
}
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.toQString()));
goto rrfail;
}
}
ret << ProString(qt_readRegistryKey(tree, args.at(1).toQString(m_tmp1), flags));
}
rrfail:
break;
#endif
default:
evalError(fL1S("Function '%1' is not implemented.").arg(func.toQString(m_tmp1)));
break;

View File

@@ -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 <QtCore/qstringlist.h>
#include "registry_p.h"
namespace QMakeInternal {
#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<unsigned char*>(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;
}
} // namespace QMakeInternal

View File

@@ -0,0 +1,55 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** 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.
**
****************************************************************************/
#pragma once
#include <QtCore/qglobal.h>
#ifdef Q_OS_WIN32
#include <QtCore/qt_windows.h>
#else
typedef void* HKEY;
#endif
#include <QtCore/qstring.h>
namespace QMakeInternal {
/**
* 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);
} // namespace QMakeInternal

View File

@@ -18,7 +18,8 @@ QtcAutotest {
"qmakeevaluator.h", "qmakeevaluator_p.h", "qmakeevaluator.cpp",
"qmakeglobals.h", "qmakeglobals.cpp",
"qmakeparser.h", "qmakeparser.cpp",
"qmakevfs.h", "qmakevfs.cpp"
"qmakevfs.h", "qmakevfs.cpp",
"registry_p.h", "registry.cpp",
]
}
Group {
@@ -27,4 +28,8 @@ QtcAutotest {
}
cpp.includePaths: base.concat([proParserGroup.prefix])
cpp.defines: base.concat("QT_USE_FAST_OPERATOR_PLUS")
Properties {
condition: qbs.targetOS.contains("windows")
cpp.dynamicLibraries: "advapi32"
}
}