diff --git a/src/gpgolconfig/CMakeLists.txt b/src/gpgolconfig/CMakeLists.txt index e7c34ec..24dbcff 100644 --- a/src/gpgolconfig/CMakeLists.txt +++ b/src/gpgolconfig/CMakeLists.txt @@ -1,41 +1,42 @@ # Copyright (C) 2018 Intevation GmbH # # This file is Free Software under the GNU GPL (v>=2) # and comes with ABSOLUTELY NO WARRANTY! # See LICENSE.txt for details. set(EXECUTABLE_NAME "gpgolconfig") set(EXECUTABLE_SRC main.cpp gpgolconfig-options.h gpgolconfig.cpp gpgolconfigpage.cpp gpgoldebugpage.cpp cryptoconfigpage.cpp ${CMAKE_SOURCE_DIR}/src/img/icon.rc ${CMAKE_SOURCE_DIR}/src/util/strhelp.c ${CMAKE_SOURCE_DIR}/src/util/w32-util.cpp + ${CMAKE_SOURCE_DIR}/src/util/w32-qt-util.cpp ${CMAKE_SOURCE_DIR}/src/util/w32-gettext.c ) qt5_add_resources(EXECUTABLE_SRC gpgolconfig.qrc) add_executable(${EXECUTABLE_NAME} ${_add_executable_params} ${EXECUTABLE_SRC} ) target_link_libraries(${EXECUTABLE_NAME} Qt5::Widgets KF5::WidgetsAddons KF5::Libkleo Gpgmepp QGpgme ) if (WIN32) set_target_properties(${EXECUTABLE_NAME} PROPERTIES LINK_FLAGS "-municode") endif(WIN32) install(TARGETS ${EXECUTABLE_NAME} DESTINATION bin) diff --git a/src/gpgolconfig/gpgolconfig.cpp b/src/gpgolconfig/gpgolconfig.cpp index e22ee8a..f0dc683 100644 --- a/src/gpgolconfig/gpgolconfig.cpp +++ b/src/gpgolconfig/gpgolconfig.cpp @@ -1,116 +1,117 @@ /* Copyright (C) 2018 by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "gpgolconfig.h" #include "w32-gettext.h" #include "w32-util.h" +#include "w32-qt-util.h" #include "gpgolconfigpage.h" #include "gpgoldebugpage.h" #include "cryptoconfigpage.h" #include #include #include #include #include #include #include #include #include #include GpgOLConfig::GpgOLConfig(const QCommandLineParser &parser): KPageDialog(nullptr) { setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint)); setWindowTitle(_("Configure GpgOL")); setWindowIcon(QIcon(":/gpgol-icon.svg")); const auto hwnd = parser.value(QStringLiteral("hwnd")); if (!hwnd.isEmpty()) { bool ok; WId id = (WId) hwnd.toInt(&ok); if (!ok) { qDebug() << "invalid hwnd value"; } else { W32::setupForeignParent(id, this, true); setModal(true); } } if (parser.isSet("gpgol-version")) { mVersion = parser.value("gpgol-version"); } else { mVersion = QStringLiteral("unknown version"); } setupGUI(); resize(800, 500); } void GpgOLConfig::setupGUI() { setFaceType(KPageDialog::List); QDialogButtonBox *buttonBox = new QDialogButtonBox(); buttonBox->setStandardButtons(QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Cancel | QDialogButtonBox::Ok); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Ok), KStandardGuiItem::ok()); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel()); KGuiItem::assign(buttonBox->button(QDialogButtonBox::RestoreDefaults), KStandardGuiItem::defaults()); setButtonBox(buttonBox); auto cryptoConfWidget = new CryptoConfigPage; auto gpgolConfWidget = new GpgOLConfigPage; auto gpgolDbgWidget = new GpgOLDebugPage; connect(buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, this, [this, cryptoConfWidget, gpgolConfWidget, gpgolDbgWidget] () { cryptoConfWidget->save(); gpgolConfWidget->save(); gpgolDbgWidget->save(); close(); }); connect(buttonBox->button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, this, [this, cryptoConfWidget, gpgolConfWidget, gpgolDbgWidget] () { if (currentPage()->widget() == cryptoConfWidget) { cryptoConfWidget->defaults(); } else if (currentPage()->widget() == gpgolConfWidget){ gpgolConfWidget->defaults(); } else if (currentPage()->widget() == gpgolDbgWidget){ gpgolDbgWidget->defaults(); } }); connect(buttonBox->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked, this, [this] () { close(); }); KPageWidgetItem *page = new KPageWidgetItem(gpgolConfWidget, _("GpgOL")); page->setHeader(QStringLiteral("%1 - %2%3").arg(_("Configure GpgOL")).arg( _("Version ")).arg(mVersion)); page->setIcon(QIcon(":/gpgol-icon.svg")); addPage(page); page = new KPageWidgetItem(cryptoConfWidget, QStringLiteral("%1\n%2").arg(_("GnuPG System")).arg(_("(Technical)"))); page->setHeader(_("Configuration of GnuPG System options")); page->setIcon(QIcon::fromTheme("document-encrypt")); addPage(page); page = new KPageWidgetItem(gpgolDbgWidget, _("Debug")); page->setHeader(_("Configuration of debug options")); page->setIcon(QIcon::fromTheme("tools-report-bug")); addPage(page); } diff --git a/src/gpgolkeyadder/CMakeLists.txt b/src/gpgolkeyadder/CMakeLists.txt index 8800fea..bc19f9c 100644 --- a/src/gpgolkeyadder/CMakeLists.txt +++ b/src/gpgolkeyadder/CMakeLists.txt @@ -1,36 +1,37 @@ # Copyright (C) 2018 Intevation GmbH # # This file is Free Software under the GNU GPL (v>=2) # and comes with ABSOLUTELY NO WARRANTY! # See LICENSE.txt for details. set(EXECUTABLE_NAME "gpgolkeyadder") set(EXECUTABLE_SRC main.cpp gpgolkeyadder-options.h gpgolkeyadder.cpp stdinreader.cpp ${CMAKE_SOURCE_DIR}/src/img/icon.rc ${CMAKE_SOURCE_DIR}/src/util/strhelp.c ${CMAKE_SOURCE_DIR}/src/util/w32-util.cpp + ${CMAKE_SOURCE_DIR}/src/util/w32-qt-util.cpp ${CMAKE_SOURCE_DIR}/src/util/w32-gettext.c ) qt5_add_resources(EXECUTABLE_SRC gpgolkeyadder.qrc) add_executable(${EXECUTABLE_NAME} ${_add_executable_params} ${EXECUTABLE_SRC} ) target_link_libraries(${EXECUTABLE_NAME} Qt5::Widgets Gpgmepp ) if (WIN32) set_target_properties(${EXECUTABLE_NAME} PROPERTIES LINK_FLAGS "-municode") endif(WIN32) install(TARGETS ${EXECUTABLE_NAME} DESTINATION bin) diff --git a/src/gpgolkeyadder/gpgolkeyadder.cpp b/src/gpgolkeyadder/gpgolkeyadder.cpp index dd76a82..6efc183 100644 --- a/src/gpgolkeyadder/gpgolkeyadder.cpp +++ b/src/gpgolkeyadder/gpgolkeyadder.cpp @@ -1,248 +1,249 @@ /* Copyright (C) 2018 by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "gpgolkeyadder.h" #include "w32-gettext.h" #include "w32-util.h" +#include "w32-qt-util.h" #include "stdinreader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include GpgOLKeyAdder::GpgOLKeyAdder(const QCommandLineParser &parser): QDialog(nullptr), mEdit(new QTextEdit) { setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint)); mName = parser.value(QStringLiteral("username")); setWindowTitle(_("GpgOL") + QStringLiteral(" - ") + _("Configure key for:") + QStringLiteral(" ") + mName); setWindowIcon(QIcon(":/gpgol-icon.svg")); const auto hwnd = parser.value(QStringLiteral("hwnd")); if (!hwnd.isEmpty()) { bool ok; WId id = (WId) hwnd.toInt(&ok); if (!ok) { qDebug() << "invalid hwnd value"; } else { W32::setupForeignParent(id, this, true); setModal(true); } } setupGUI(); // Deletes itself auto reader = new StdinReader; connect (reader, &StdinReader::stdinRead, this, [this] (const QByteArray &data) { if (data.size() > 1) { mEdit->setPlainText(QString::fromUtf8(data)); } }); reader->start(); } void GpgOLKeyAdder::setupGUI() { /* Setup Edit */ auto fixedFont = QFont("Monospace", 10); fixedFont.setStyleHint(QFont::TypeWriter); mEdit->setFont(fixedFont); resize(QFontMetrics(fixedFont).averageCharWidth() * 80, QFontMetrics(fixedFont).height() * 30); mEdit->setPlaceholderText(QString::fromUtf8(_("Paste a public key export here. It should look like:")) + QStringLiteral("\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\n" "mQENBEzJavsBCADG/guWL6AxGgngUxp/DcmoitJjaJMqcJkBtD3uKrW81Pbnm3LI\n" "...\n" "dCl8hHggB9x2\n" "=oShe\n" "-----END PGP PUBLIC KEY BLOCK-----")); mEdit->setUndoRedoEnabled(true); /* Setup buttons */ QDialogButtonBox *buttonBox = new QDialogButtonBox(); buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok); connect(buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, this, [this] () { checkAccept(); }); connect(buttonBox->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked, this, [this] () { qApp->quit(); }); auto okBtn = buttonBox->button(QDialogButtonBox::Ok); okBtn->setEnabled(false); connect(mEdit, &QTextEdit::textChanged, this, [this, okBtn] () { const auto text = mEdit->toPlainText().trimmed().toUtf8(); if (!text.size()) { okBtn->setEnabled(true); return; } GpgME::Data data(text.constData(), text.size(), false); okBtn->setEnabled(data.type() == GpgME::Data::PGPKey); }); /* Setup layout */ auto layout = new QVBoxLayout; setLayout(layout); layout->addWidget(mEdit); layout->addWidget(buttonBox); } static void save(const QByteArray &data) { if (!data.size()) { /* Empty is a special case which can mean that an * existing key should be removed. */ std::cout << "empty" << std::endl; } else { std::cout << data.constData() << std::endl; } qApp->quit(); } static QString prettyNameAndEMail(const QString &id, const QString &name, const QString &email, const QString &comment) { if (name.isEmpty()) { if (email.isEmpty()) { return QString(); } else if (comment.isEmpty()) { return QStringLiteral("<%1>").arg(email); } else { return QStringLiteral("(%2) <%1>").arg(email, comment); } } if (email.isEmpty()) { if (comment.isEmpty()) { return name; } else { return QStringLiteral("%1 (%2)").arg(name, comment); } } if (comment.isEmpty()) { return QStringLiteral("%1 <%2>").arg(name, email); } else { return QStringLiteral("%1 (%3) <%2>").arg(name, email, comment); } return QString(); } static QString prettyNameAndEMail(const char *id, const char *name_, const std::string &email_, const char *comment_) { return prettyNameAndEMail(QString::fromUtf8(id), QString::fromUtf8(name_), QString::fromStdString(email_), QString::fromUtf8(comment_)); } static QString prettyNameAndEMail(const GpgME::UserID &uid) { return prettyNameAndEMail(uid.id(), uid.name(), uid.addrSpec(), uid.comment()); } static QString time_t2string(time_t t) { QDateTime dt; dt.setTime_t(t); return QLocale().toString(dt, QLocale::ShortFormat); } void GpgOLKeyAdder::checkAccept() { const auto text = mEdit->toPlainText().trimmed().toUtf8(); if (text.isEmpty()) { save(text); // Save exits return; } GpgME::Data data(text.constData(), text.size(), false); const auto keys = data.toKeys(); if (!keys.size()) { QMessageBox::warning(this, QString::fromUtf8 (_("Error")), QStringLiteral("%1

").arg(QString::fromUtf8(_("Failed to parse any public key.")))); return; } QStringList keyInfos; for (const auto &key: keys) { if (key.isNull() || !key.numSubkeys()) { qDebug() << "Null key?"; continue; } if (key.hasSecret()) { QMessageBox::warning(this, QString::fromUtf8 (_("Error")), QStringLiteral("%1

").arg(QString::fromUtf8(_("Secret key detected."))) + QString::fromUtf8(_("You can only configure public keys in Outlook." " Import secret keys with Kleopatra."))); return; } if (key.isRevoked() || key.isExpired() || key.isInvalid() || key.isDisabled() || !key.canEncrypt()) { QMessageBox::warning(this, QString::fromUtf8 (_("Error")), QStringLiteral("%1

%2

").arg(QString::fromUtf8(_("Invalid key detected."))).arg( key.primaryFingerprint()) + QString::fromUtf8(_("The key is unusable for Outlook." " Please check Kleopatra for more information."))); return; } const auto subkey = key.subkey(0); QString info = QString::fromLatin1(key.primaryFingerprint()) + "
" + QString::fromUtf8(_("Created:")) + " " + time_t2string(subkey.creationTime()) + "
" + QString::fromUtf8(_("User Ids:")) + "
"; for (const auto &uid: key.userIDs()) { if (uid.isNull() || uid.isRevoked() || uid.isInvalid()) { continue; } info += "  " + prettyNameAndEMail(uid).toHtmlEscaped() + "
"; } keyInfos << info; } QString msg = QString::fromUtf8(_("You are about to configure the following %1 for:")).arg( (keyInfos.size() > 1 ? QString::fromUtf8(_("keys")) : QString::fromUtf8(_("key")))) + QStringLiteral("
\t\"%1\"

").arg(mName.toHtmlEscaped()) + keyInfos.join("

"); msg += "

" + QString::fromUtf8 (_("Continue?")); const auto ret = QMessageBox::question(this, QString::fromUtf8(_("Confirm keys")), msg, QMessageBox::Yes | QMessageBox::Abort, QMessageBox::Yes); if (ret == QMessageBox::Yes) { save(text); return; } } diff --git a/src/util/w32-qt-util.cpp b/src/util/w32-qt-util.cpp new file mode 100644 index 0000000..822b06a --- /dev/null +++ b/src/util/w32-qt-util.cpp @@ -0,0 +1,27 @@ +/* Copyright (C) 2018 by Andre Heinecke + * + * This file is Free Software under the GNU GPL (v>=2) + * and comes with ABSOLUTELY NO WARRANTY! + * See LICENSE.txt for details. + */ +#include +#include + +#include "w32-qt-util.h" + +void W32::setupForeignParent(WId id, QWidget *widget, bool modal) +{ + if (!widget || !id) { + return; + } + + auto foreignWindow = QWindow::fromWinId(id); + widget->winId(); + auto parentHandle = widget->windowHandle(); + if (parentHandle && foreignWindow) { + parentHandle->setTransientParent(foreignWindow); + if (modal) { + widget->setWindowModality(Qt::WindowModal); + } + } +} diff --git a/src/util/w32-qt-util.h b/src/util/w32-qt-util.h new file mode 100644 index 0000000..1846549 --- /dev/null +++ b/src/util/w32-qt-util.h @@ -0,0 +1,16 @@ +#ifndef W32_QT_UTIL_H +#define W32_QT_UTIL_H +/* Copyright (C) 2018 by Andre Heinecke + * + * This file is Free Software under the GNU GPL (v>=2) + * and comes with ABSOLUTELY NO WARRANTY! + * See LICENSE.txt for details. + */ + +#include + +namespace W32 +{ +void setupForeignParent(WId id, QWidget *widget, bool modal); +} // namespace W32 +#endif //W32-QT-UTIL_H diff --git a/src/util/w32-util.cpp b/src/util/w32-util.cpp index 2744511..6ed5c43 100644 --- a/src/util/w32-util.cpp +++ b/src/util/w32-util.cpp @@ -1,230 +1,240 @@ /* Copyright (C) 2018 by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include #include "w32-util.h" #include #ifdef _WIN32 # include #endif #include #include #define SLDIR "\\share\\locale" namespace W32 { -static bool s_use_w64_registry; - std::string getGpg4winLocaleDir() { const auto instdir = getGpg4winDir(); if (instdir.empty()) { return std::string(); } return instdir + SLDIR; } std::string getGpg4winDir() { const auto tmp = readRegStr(nullptr, GPG4WIN_REGKEY_3, "Install Directory"); if (tmp.empty()) { return std::string(); } if (!access(tmp.c_str(), R_OK)) { return tmp; } else { fprintf (stderr, "Failed to access: %s\n", tmp.c_str()); } return std::string(); } /* Helper for read_w32_registry_string(). */ #ifdef _WIN32 static HKEY get_root_key(const char *root) { HKEY root_key; if( !root ) root_key = HKEY_CURRENT_USER; else if( !strcmp( root, "HKEY_CLASSES_ROOT" ) ) root_key = HKEY_CLASSES_ROOT; else if( !strcmp( root, "HKEY_CURRENT_USER" ) ) root_key = HKEY_CURRENT_USER; else if( !strcmp( root, "HKEY_LOCAL_MACHINE" ) ) root_key = HKEY_LOCAL_MACHINE; else if( !strcmp( root, "HKEY_USERS" ) ) root_key = HKEY_USERS; else if( !strcmp( root, "HKEY_PERFORMANCE_DATA" ) ) root_key = HKEY_PERFORMANCE_DATA; else if( !strcmp( root, "HKEY_CURRENT_CONFIG" ) ) root_key = HKEY_CURRENT_CONFIG; else return nullptr; return root_key; } #endif #if defined(_WIN64) #define CROSS_ACCESS KEY_WOW64_32KEY #else #define CROSS_ACCESS KEY_WOW64_64KEY #endif +#ifdef _WIN32 std::string _readRegStr (HKEY root_key, const char *dir, const char *name, bool alternate) { -#ifndef _WIN32 - (void) root_key; (void)alternate; (void)dir; (void)name; - return std::string(); -#else HKEY key_handle; DWORD n1, nbytes, type; std::string ret; DWORD flags = KEY_READ; if (alternate) { flags |= CROSS_ACCESS; } if (RegOpenKeyExA(root_key, dir, 0, flags, &key_handle)) { return ret; } nbytes = 1; if (RegQueryValueExA(key_handle, name, 0, nullptr, nullptr, &nbytes)) { RegCloseKey (key_handle); return ret; } n1 = nbytes+1; char result[n1]; if (RegQueryValueExA(key_handle, name, 0, &type, (LPBYTE)result, &n1)) { RegCloseKey(key_handle); return ret; } RegCloseKey(key_handle); result[nbytes] = 0; /* make sure it is really a string */ ret = result; if (type == REG_EXPAND_SZ && strchr (result, '%')) { n1 += 1000; char tmp[n1 +1]; nbytes = ExpandEnvironmentStringsA(ret.c_str(), tmp, n1); if (nbytes && nbytes > n1) { n1 = nbytes; char tmp2[n1 +1]; nbytes = ExpandEnvironmentStringsA(result, tmp2, n1); if (nbytes && nbytes > n1) { /* oops - truncated, better don't expand at all */ return ret; } tmp2[nbytes] = 0; ret = tmp2; } else if (nbytes) { /* okay, reduce the length */ tmp[nbytes] = 0; ret = tmp; } } return ret; - -#endif } +#endif std::string readRegStr (const char *root, const char *dir, const char *name) { #ifndef _WIN32 (void)root; (void)dir; (void)name; return std::string(); #else HKEY root_key; std::string ret; if (!(root_key = get_root_key(root))) { return ret; } ret = _readRegStr (root_key, dir, name, false); if (ret.empty()) { // Try local machine as fallback. qDebug() << "Fallback to HKLM for" << dir << name; ret = _readRegStr (HKEY_LOCAL_MACHINE, dir, name, false); if (ret.empty()) { // Try alternative registry view as fallback qDebug() << "Fallback to HKLM alternative for" << dir << name; ret = _readRegStr (HKEY_LOCAL_MACHINE, dir, name, true); } } qDebug() << "Returning:" << (ret.empty() ? "empty" : ret.c_str()); return ret; #endif } bool writeRegStr(const char *root, const char *path, const char *key, const char *val) { #ifndef _WIN32 (void) root; (void) path; (void) key; (void) val; return false; #else HKEY h, hk; int type; int ec; hk = get_root_key (root); if (!hk) { fprintf(stderr, "Failed to find root key.\n"); } DWORD flags = KEY_ALL_ACCESS; ec = RegCreateKeyExA(hk, path, 0, NULL, REG_OPTION_NON_VOLATILE, flags, NULL, &h, NULL); if (ec != ERROR_SUCCESS) { fprintf (stderr, "creating/opening registry key `%s' failed\n", path); return false; } type = strchr (val, '%')? REG_EXPAND_SZ : REG_SZ; ec = RegSetValueExA(h, key, 0, type, (const BYTE*)val, strlen (val)); if (ec != ERROR_SUCCESS) { fprintf (stderr, "saving registry key `%s'->`%s' failed\n", path, key); RegCloseKey(h); return false; } RegCloseKey(h); return true; #endif } -void setupForeignParent(WId id, QWidget *widget, bool modal) -{ - if (!widget || !id) { - return; - } - auto foreignWindow = QWindow::fromWinId(id); - widget->winId(); - auto parentHandle = widget->windowHandle(); - if (parentHandle && foreignWindow) { - parentHandle->setTransientParent(foreignWindow); - if (modal) { - widget->setWindowModality(Qt::WindowModal); +bool isElevated() +{ +#ifdef _WIN32 + int ret = 0; + HANDLE hToken = NULL; + if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken)) + { + DWORD elevation; + DWORD cbSize = sizeof (DWORD); + if (GetTokenInformation (hToken, TokenElevation, &elevation, + sizeof (TokenElevation), &cbSize)) + { + ret = elevation; } } + /* Elevation will be true and ElevationType TokenElevationTypeFull even + if the token is a user token created by SAFER so we additionally + check the integrity level of the token which will only be high in + the real elevated process and medium otherwise. */ + ret = ret && has_high_integrity (hToken); + + if (hToken) + CloseHandle (hToken); + + return ret; +#else + return false; +#endif } + + }// namespace diff --git a/src/util/w32-util.h b/src/util/w32-util.h index 02d47bc..998ae95 100644 --- a/src/util/w32-util.h +++ b/src/util/w32-util.h @@ -1,59 +1,56 @@ /* Copyright (C) 2018 by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include -#include - /* The Registry key used by Gpg4win. */ #ifdef _WIN64 # define GPG4WIN_REGKEY_2 "Software\\Wow6432Node\\GNU\\GnuPG" #else # define GPG4WIN_REGKEY_2 "Software\\GNU\\GnuPG" #endif #ifdef _WIN64 # define GPG4WIN_REGKEY_3 "Software\\Wow6432Node\\Gpg4win" #else # define GPG4WIN_REGKEY_3 "Software\\Gpg4win" #endif #define GPGOL_REG_PATH "Software\\GNU\\GpgOL" namespace W32 { /* Get the locale dir of Gpg4win. */ std::string getGpg4winLocaleDir(); /** Get the Gpg4win Install directory. * * Looks for the Gpg4win 3.x registry key. * And checks that the directory can be read. * * @returns an empty string if no dir could be found. * **/ std::string getGpg4winDir(); /** Read a registry string value. If root is null first * HKEY_CURRENT_USER is searched and then it falls back * to HKEY_LOCAL_MACHINE . */ std::string readRegStr(const char *root, const char *path, const char *key); bool writeRegStr(const char *root, const char *path, const char *key, const char *val); -void setupForeignParent(WId id, QWidget *widget, bool modal); - /** Call this to switch to the W64 registry. */ void setW64RegistryMode(bool value); +bool isElevated(); } // namespace W32