| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file LICENSE.rst or https://cmake.org/licensing for details. */
- #include "cmConfigure.h" // IWYU pragma: keep
- #include "cmWindowsRegistry.h"
- #include <cctype>
- #include <cstddef>
- #include <type_traits>
- #include <unordered_map>
- #include <utility>
- #include <cmext/string_view>
- #include "cmsys/RegularExpression.hxx"
- #if defined(_WIN32) && !defined(__CYGWIN__)
- # include <algorithm>
- # include <cstring>
- # include <exception>
- # include <iterator>
- # include <vector>
- # include <cm/memory>
- # include <windows.h>
- # include "cmMakefile.h"
- # include "cmStringAlgorithms.h"
- # include "cmValue.h"
- #endif
- namespace {
- // Case-independent string comparison
- int Strucmp(cm::string_view l, cm::string_view r)
- {
- if (l.empty() && r.empty()) {
- return 0;
- }
- if (l.empty() || r.empty()) {
- return static_cast<int>(l.size() - r.size());
- }
- int lc;
- int rc;
- cm::string_view::size_type li = 0;
- cm::string_view::size_type ri = 0;
- do {
- lc = std::tolower(l[li++]);
- rc = std::tolower(r[ri++]);
- } while (lc == rc && li < l.size() && ri < r.size());
- return lc == rc ? static_cast<int>(l.size() - r.size()) : lc - rc;
- }
- #if defined(_WIN32) && !defined(__CYGWIN__)
- bool Is64BitWindows()
- {
- # if defined(_WIN64)
- // 64-bit programs run only on Win64
- return true;
- # else
- // 32-bit programs run on both 32-bit and 64-bit Windows, so we must check.
- BOOL isWow64 = false;
- return IsWow64Process(GetCurrentProcess(), &isWow64) && isWow64;
- # endif
- }
- // Helper to translate Windows registry value type to enum ValueType
- cm::optional<cmWindowsRegistry::ValueType> ToValueType(DWORD type)
- {
- using ValueType = cmWindowsRegistry::ValueType;
- static std::unordered_map<DWORD, ValueType> ValueTypes{
- { REG_SZ, ValueType::Reg_SZ },
- { REG_EXPAND_SZ, ValueType::Reg_EXPAND_SZ },
- { REG_MULTI_SZ, ValueType::Reg_MULTI_SZ },
- { REG_DWORD, ValueType::Reg_DWORD },
- { REG_QWORD, ValueType::Reg_QWORD }
- };
- auto it = ValueTypes.find(type);
- return it == ValueTypes.end()
- ? cm::nullopt
- : cm::optional<cmWindowsRegistry::ValueType>{ it->second };
- }
- // class registry_exception
- class registry_error : public std::exception
- {
- public:
- registry_error(std::string msg)
- : What(std::move(msg))
- {
- }
- ~registry_error() override = default;
- char const* what() const noexcept override { return What.c_str(); }
- private:
- std::string What;
- };
- // Class KeyHandler
- class KeyHandler
- {
- public:
- using View = cmWindowsRegistry::View;
- using ValueTypeSet = cmWindowsRegistry::ValueTypeSet;
- KeyHandler(HKEY hkey)
- : Handler(hkey)
- {
- }
- ~KeyHandler() { RegCloseKey(this->Handler); }
- static KeyHandler OpenKey(cm::string_view rootKey, cm::string_view subKey,
- View view);
- static KeyHandler OpenKey(cm::string_view key, View view);
- std::string ReadValue(
- cm::string_view name,
- ValueTypeSet supportedTypes = cmWindowsRegistry::AllTypes,
- cm::string_view separator = "\0"_s);
- std::vector<std::string> GetValueNames();
- std::vector<std::string> GetSubKeys();
- private:
- static std::string FormatSystemError(LSTATUS status);
- static std::wstring ToWide(cm::string_view str);
- static std::string ToNarrow(wchar_t const* str, int size = -1);
- HKEY Handler;
- };
- KeyHandler KeyHandler::OpenKey(cm::string_view rootKey, cm::string_view subKey,
- View view)
- {
- if (view == View::Reg64 && !Is64BitWindows()) {
- throw registry_error("No 64bit registry on Windows32.");
- }
- HKEY hRootKey;
- if (rootKey == "HKCU"_s || rootKey == "HKEY_CURRENT_USER"_s) {
- hRootKey = HKEY_CURRENT_USER;
- } else if (rootKey == "HKLM"_s || rootKey == "HKEY_LOCAL_MACHINE"_s) {
- hRootKey = HKEY_LOCAL_MACHINE;
- } else if (rootKey == "HKCR"_s || rootKey == "HKEY_CLASSES_ROOT"_s) {
- hRootKey = HKEY_CLASSES_ROOT;
- } else if (rootKey == "HKCC"_s || rootKey == "HKEY_CURRENT_CONFIG"_s) {
- hRootKey = HKEY_CURRENT_CONFIG;
- } else if (rootKey == "HKU"_s || rootKey == "HKEY_USERS"_s) {
- hRootKey = HKEY_USERS;
- } else {
- throw registry_error(cmStrCat(rootKey, ": invalid root key."));
- }
- // Update path format
- auto key = ToWide(subKey);
- std::replace(key.begin(), key.end(), L'/', L'\\');
- REGSAM options = KEY_READ;
- if (Is64BitWindows()) {
- options |= view == View::Reg64 ? KEY_WOW64_64KEY : KEY_WOW64_32KEY;
- }
- HKEY hKey;
- LSTATUS status;
- if ((status = RegOpenKeyExW(hRootKey, key.c_str(), 0, options, &hKey)) !=
- ERROR_SUCCESS) {
- throw registry_error(FormatSystemError(status));
- }
- return KeyHandler(hKey);
- }
- KeyHandler KeyHandler::OpenKey(cm::string_view key, View view)
- {
- auto start = key.find_first_of("\\/"_s);
- return OpenKey(key.substr(0, start),
- start == cm::string_view::npos ? cm::string_view{ ""_s }
- : key.substr(start + 1),
- view);
- }
- std::string KeyHandler::FormatSystemError(LSTATUS status)
- {
- std::string formattedMessage{ "Windows Registry: unexpected error." };
- LPWSTR message = nullptr;
- DWORD size = 1024;
- if (FormatMessageW(
- FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, nullptr,
- status, 0, reinterpret_cast<LPWSTR>(&message), size, nullptr) != 0) {
- try {
- formattedMessage = cmTrimWhitespace(ToNarrow(message));
- } catch (...) {
- // ignore any exception because this method can be called
- // as part of the raise of an exception
- }
- }
- LocalFree(message);
- return formattedMessage;
- }
- std::wstring KeyHandler::ToWide(cm::string_view str)
- {
- std::wstring wstr;
- if (str.empty()) {
- return wstr;
- }
- auto const wlength =
- MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(),
- int(str.size()), nullptr, 0);
- if (wlength > 0) {
- auto wdata = cm::make_unique<wchar_t[]>(wlength);
- auto const r =
- MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(),
- int(str.size()), wdata.get(), wlength);
- if (r > 0) {
- wstr = std::wstring(wdata.get(), wlength);
- } else {
- throw registry_error(FormatSystemError(GetLastError()));
- }
- } else {
- throw registry_error(FormatSystemError(GetLastError()));
- }
- return wstr;
- }
- std::string KeyHandler::ToNarrow(wchar_t const* wstr, int size)
- {
- std::string str;
- if (size == 0 || (size == -1 && wstr[0] == L'\0')) {
- return str;
- }
- auto const length =
- WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, wstr, size,
- nullptr, 0, nullptr, nullptr);
- if (length > 0) {
- auto data = cm::make_unique<char[]>(length);
- auto const r =
- WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, wstr, size,
- data.get(), length, nullptr, nullptr);
- if (r > 0) {
- if (size == -1) {
- str = std::string(data.get());
- } else {
- str = std::string(data.get(), length);
- }
- } else {
- throw registry_error(FormatSystemError(GetLastError()));
- }
- } else {
- throw registry_error(FormatSystemError(GetLastError()));
- }
- return str;
- }
- std::string KeyHandler::ReadValue(cm::string_view name,
- ValueTypeSet supportedTypes,
- cm::string_view separator)
- {
- LSTATUS status;
- DWORD size;
- // pick-up maximum size for value
- if ((status = RegQueryInfoKeyW(this->Handler, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr,
- &size, nullptr, nullptr)) != ERROR_SUCCESS) {
- throw registry_error(this->FormatSystemError(status));
- }
- auto data = cm::make_unique<BYTE[]>(size);
- DWORD type;
- auto valueName = this->ToWide(name);
- if ((status = RegQueryValueExW(this->Handler, valueName.c_str(), nullptr,
- &type, data.get(), &size)) != ERROR_SUCCESS) {
- throw registry_error(this->FormatSystemError(status));
- }
- auto valueType = ToValueType(type);
- if (!valueType || !supportedTypes.contains(*valueType)) {
- throw registry_error(cmStrCat(type, ": unsupported type."));
- }
- switch (type) {
- case REG_SZ:
- return this->ToNarrow(reinterpret_cast<wchar_t*>(data.get()));
- break;
- case REG_EXPAND_SZ: {
- auto expandSize = ExpandEnvironmentStringsW(
- reinterpret_cast<wchar_t*>(data.get()), nullptr, 0);
- auto expandData = cm::make_unique<wchar_t[]>(expandSize + 1);
- if (ExpandEnvironmentStringsW(reinterpret_cast<wchar_t*>(data.get()),
- expandData.get(), expandSize + 1) == 0) {
- throw registry_error(this->FormatSystemError(GetLastError()));
- } else {
- return this->ToNarrow(expandData.get());
- }
- } break;
- case REG_DWORD:
- return std::to_string(*reinterpret_cast<std::uint32_t*>(data.get()));
- break;
- case REG_QWORD:
- return std::to_string(*reinterpret_cast<std::uint64_t*>(data.get()));
- break;
- case REG_MULTI_SZ: {
- // replace separator with semicolon
- auto sep = this->ToWide(separator)[0];
- std::replace(reinterpret_cast<wchar_t*>(data.get()),
- reinterpret_cast<wchar_t*>(data.get()) +
- (size / sizeof(wchar_t)) - 1,
- sep, L';');
- return this->ToNarrow(reinterpret_cast<wchar_t*>(data.get()));
- } break;
- default:
- throw registry_error(cmStrCat(type, ": unsupported type."));
- }
- }
- std::vector<std::string> KeyHandler::GetValueNames()
- {
- LSTATUS status;
- DWORD maxSize;
- // pick-up maximum size for value names
- if ((status = RegQueryInfoKeyW(
- this->Handler, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, &maxSize, nullptr, nullptr, nullptr)) != ERROR_SUCCESS) {
- throw registry_error(this->FormatSystemError(status));
- }
- // increment size for final null
- auto data = cm::make_unique<wchar_t[]>(++maxSize);
- DWORD index = 0;
- DWORD size = maxSize;
- std::vector<std::string> valueNames;
- while ((status = RegEnumValueW(this->Handler, index, data.get(), &size,
- nullptr, nullptr, nullptr, nullptr)) ==
- ERROR_SUCCESS) {
- auto name = this->ToNarrow(data.get());
- valueNames.push_back(name.empty() ? "(default)" : name);
- size = maxSize;
- ++index;
- }
- if (status != ERROR_NO_MORE_ITEMS) {
- throw registry_error(this->FormatSystemError(status));
- }
- return valueNames;
- }
- std::vector<std::string> KeyHandler::GetSubKeys()
- {
- LSTATUS status;
- DWORD size;
- // pick-up maximum size for subkeys
- if ((status = RegQueryInfoKeyW(
- this->Handler, nullptr, nullptr, nullptr, nullptr, &size, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr)) != ERROR_SUCCESS) {
- throw registry_error(this->FormatSystemError(status));
- }
- // increment size for final null
- auto data = cm::make_unique<wchar_t[]>(++size);
- DWORD index = 0;
- std::vector<std::string> subKeys;
- while ((status = RegEnumKeyW(this->Handler, index, data.get(), size)) ==
- ERROR_SUCCESS) {
- subKeys.push_back(this->ToNarrow(data.get()));
- ++index;
- }
- if (status != ERROR_NO_MORE_ITEMS) {
- throw registry_error(this->FormatSystemError(status));
- }
- return subKeys;
- }
- #endif
- // ExpressionParser: Helper to parse expression holding multiple
- // registry specifications
- class ExpressionParser
- {
- public:
- ExpressionParser(cm::string_view expression)
- : Expression(expression)
- , Separator(";"_s)
- , RegistryFormat{
- "\\[({.+})?(HKCU|HKEY_CURRENT_USER|HKLM|HKEY_LOCAL_MACHINE|HKCR|HKEY_"
- "CLASSES_"
- "ROOT|HKCC|HKEY_CURRENT_CONFIG|HKU|HKEY_USERS)[/\\]?([^]]*)\\]"
- }
- {
- }
- bool Find()
- {
- // reset result members
- this->RootKey = cm::string_view{};
- this->SubKey = cm::string_view{};
- this->ValueName = cm::string_view{};
- auto result = this->RegistryFormat.find(this->Expression);
- if (result) {
- auto separator = cm::string_view{
- this->Expression.data() + this->RegistryFormat.start(1),
- this->RegistryFormat.end(1) - this->RegistryFormat.start(1)
- };
- if (separator.empty()) {
- separator = this->Separator;
- } else {
- separator = separator.substr(1, separator.length() - 2);
- }
- this->RootKey = cm::string_view{
- this->Expression.data() + this->RegistryFormat.start(2),
- this->RegistryFormat.end(2) - this->RegistryFormat.start(2)
- };
- this->SubKey = cm::string_view{
- this->Expression.data() + this->RegistryFormat.start(3),
- this->RegistryFormat.end(3) - this->RegistryFormat.start(3)
- };
- auto pos = this->SubKey.find(separator);
- if (pos != cm::string_view::npos) {
- // split in ValueName and SubKey
- this->ValueName = this->SubKey.substr(pos + separator.size());
- if (Strucmp(this->ValueName, "(default)") == 0) {
- // handle magic name for default value
- this->ValueName = ""_s;
- }
- this->SubKey = this->SubKey.substr(0, pos);
- } else {
- this->ValueName = ""_s;
- }
- }
- return result;
- }
- #if defined(_WIN32) && !defined(__CYGWIN__)
- void Replace(std::string const& value)
- {
- this->Expression.replace(
- this->RegistryFormat.start(),
- this->RegistryFormat.end() - this->RegistryFormat.start(), value);
- }
- cm::string_view GetRootKey() const { return this->RootKey; }
- cm::string_view GetSubKey() const { return this->SubKey; }
- cm::string_view GetValueName() const { return this->ValueName; }
- std::string const& GetExpression() const { return this->Expression; }
- #endif
- private:
- std::string Expression;
- cm::string_view Separator;
- cmsys::RegularExpression RegistryFormat;
- cm::string_view RootKey;
- cm::string_view SubKey;
- cm::string_view ValueName;
- };
- }
- // class cmWindowsRegistry
- cmWindowsRegistry::ValueTypeSet const cmWindowsRegistry::SimpleTypes =
- cmWindowsRegistry::ValueTypeSet{ cmWindowsRegistry::ValueType::Reg_SZ,
- cmWindowsRegistry::ValueType::Reg_EXPAND_SZ,
- cmWindowsRegistry::ValueType::Reg_DWORD,
- cmWindowsRegistry::ValueType::Reg_QWORD };
- cmWindowsRegistry::ValueTypeSet const cmWindowsRegistry::AllTypes =
- cmWindowsRegistry::SimpleTypes + cmWindowsRegistry::ValueType::Reg_MULTI_SZ;
- cmWindowsRegistry::cmWindowsRegistry(cmMakefile& makefile,
- ValueTypeSet const& supportedTypes)
- #if defined(_WIN32) && !defined(__CYGWIN__)
- : SupportedTypes(supportedTypes)
- #else
- : LastError("No Registry on this platform.")
- #endif
- {
- #if defined(_WIN32) && !defined(__CYGWIN__)
- if (cmValue targetSize = makefile.GetDefinition("CMAKE_SIZEOF_VOID_P")) {
- this->TargetSize = targetSize == "8" ? 64 : 32;
- }
- #else
- (void)makefile;
- (void)supportedTypes;
- #endif
- }
- cm::optional<cmWindowsRegistry::View> cmWindowsRegistry::ToView(
- cm::string_view name)
- {
- static std::unordered_map<cm::string_view, cmWindowsRegistry::View>
- ViewDefinitions{
- { "BOTH"_s, View::Both }, { "HOST"_s, View::Host },
- { "TARGET"_s, View::Target }, { "32"_s, View::Reg32 },
- { "64"_s, View::Reg64 }, { "32_64"_s, View::Reg32_64 },
- { "64_32"_s, View::Reg64_32 }
- };
- auto it = ViewDefinitions.find(name);
- return it == ViewDefinitions.end()
- ? cm::nullopt
- : cm::optional<cmWindowsRegistry::View>{ it->second };
- }
- // define hash structure required by std::unordered_map
- namespace std {
- template <>
- struct hash<cmWindowsRegistry::View>
- {
- size_t operator()(cmWindowsRegistry::View v) const noexcept
- {
- return static_cast<
- typename underlying_type<cmWindowsRegistry::View>::type>(v);
- }
- };
- }
- cm::string_view cmWindowsRegistry::FromView(View view)
- {
- static std::unordered_map<cmWindowsRegistry::View, cm::string_view>
- ViewDefinitions{
- { View::Both, "BOTH"_s }, { View::Host, "HOST"_s },
- { View::Target, "TARGET"_s }, { View::Reg32, "32"_s },
- { View::Reg64, "64"_s }, { View::Reg32_64, "32_64"_s },
- { View::Reg64_32, "64_32"_s }
- };
- auto it = ViewDefinitions.find(view);
- return it == ViewDefinitions.end() ? ""_s : it->second;
- }
- cm::string_view cmWindowsRegistry::GetLastError() const
- {
- return this->LastError;
- }
- #if defined(_WIN32) && !defined(__CYGWIN__)
- std::vector<cmWindowsRegistry::View> cmWindowsRegistry::ComputeViews(View view)
- {
- switch (view) {
- case View::Both:
- switch (this->TargetSize) {
- case 64:
- return std::vector<View>{ View::Reg64, View::Reg32 };
- break;
- case 32:
- return Is64BitWindows()
- ? std::vector<View>{ View::Reg32, View::Reg64 }
- : std::vector<View>{ View::Reg32 };
- break;
- default:
- // No language specified, fallback to host architecture
- return Is64BitWindows()
- ? std::vector<View>{ View::Reg64, View::Reg32 }
- : std::vector<View>{ View::Reg32 };
- break;
- }
- break;
- case View::Target:
- switch (this->TargetSize) {
- case 64:
- return std::vector<View>{ View::Reg64 };
- break;
- case 32:
- return std::vector<View>{ View::Reg32 };
- break;
- default:
- break;
- }
- CM_FALLTHROUGH;
- case View::Host:
- return std::vector<View>{ Is64BitWindows() ? View::Reg64 : View::Reg32 };
- break;
- case View::Reg64_32:
- return Is64BitWindows() ? std::vector<View>{ View::Reg64, View::Reg32 }
- : std::vector<View>{ View::Reg32 };
- break;
- case View::Reg32_64:
- return Is64BitWindows() ? std::vector<View>{ View::Reg32, View::Reg64 }
- : std::vector<View>{ View::Reg32 };
- break;
- default:
- return std::vector<View>{ view };
- break;
- }
- }
- #endif
- cm::optional<std::string> cmWindowsRegistry::ReadValue(
- cm::string_view key, cm::string_view name, View view,
- cm::string_view separator)
- {
- #if defined(_WIN32) && !defined(__CYGWIN__)
- // compute list of registry views
- auto views = this->ComputeViews(view);
- if (Strucmp(name, "(default)") == 0) {
- // handle magic name for default value
- name = ""_s;
- }
- if (separator.empty()) {
- separator = "\0"_s;
- }
- for (auto v : views) {
- try {
- this->LastError.clear();
- auto handler = KeyHandler::OpenKey(key, v);
- return handler.ReadValue(name, this->SupportedTypes, separator);
- } catch (registry_error const& e) {
- this->LastError = e.what();
- continue;
- }
- }
- #else
- (void)key;
- (void)name;
- (void)view;
- (void)separator;
- #endif
- return cm::nullopt;
- }
- cm::optional<std::vector<std::string>> cmWindowsRegistry::GetValueNames(
- cm::string_view key, View view)
- {
- #if defined(_WIN32) && !defined(__CYGWIN__)
- this->LastError.clear();
- // compute list of registry views
- auto views = this->ComputeViews(view);
- std::vector<std::string> valueNames;
- bool querySuccessful = false;
- for (auto v : views) {
- try {
- auto handler = KeyHandler::OpenKey(key, v);
- auto list = handler.GetValueNames();
- std::move(list.begin(), list.end(), std::back_inserter(valueNames));
- querySuccessful = true;
- } catch (registry_error const& e) {
- this->LastError = e.what();
- continue;
- }
- }
- if (!valueNames.empty()) {
- // value names must be unique and sorted
- std::sort(valueNames.begin(), valueNames.end());
- valueNames.erase(std::unique(valueNames.begin(), valueNames.end()),
- valueNames.end());
- }
- if (querySuccessful) {
- // At least one query was successful, so clean-up any error message
- this->LastError.clear();
- return valueNames;
- }
- #else
- (void)key;
- (void)view;
- #endif
- return cm::nullopt;
- }
- cm::optional<std::vector<std::string>> cmWindowsRegistry::GetSubKeys(
- cm::string_view key, View view)
- {
- #if defined(_WIN32) && !defined(__CYGWIN__)
- this->LastError.clear();
- // compute list of registry views
- auto views = this->ComputeViews(view);
- std::vector<std::string> subKeys;
- bool querySuccessful = false;
- for (auto v : views) {
- try {
- auto handler = KeyHandler::OpenKey(key, v);
- auto list = handler.GetSubKeys();
- std::move(list.begin(), list.end(), std::back_inserter(subKeys));
- querySuccessful = true;
- } catch (registry_error const& e) {
- this->LastError = e.what();
- continue;
- }
- }
- if (!subKeys.empty()) {
- // keys must be unique and sorted
- std::sort(subKeys.begin(), subKeys.end());
- subKeys.erase(std::unique(subKeys.begin(), subKeys.end()), subKeys.end());
- }
- if (querySuccessful) {
- // At least one query was successful, so clean-up any error message
- this->LastError.clear();
- return subKeys;
- }
- #else
- (void)key;
- (void)view;
- #endif
- return cm::nullopt;
- }
- cm::optional<std::vector<std::string>> cmWindowsRegistry::ExpandExpression(
- cm::string_view expression, View view, cm::string_view separator)
- {
- #if defined(_WIN32) && !defined(__CYGWIN__)
- static std::string NOTFOUND{ "/REGISTRY-NOTFOUND" };
- this->LastError.clear();
- // compute list of registry views
- auto views = this->ComputeViews(view);
- std::vector<std::string> result;
- for (auto v : views) {
- ExpressionParser parser(expression);
- while (parser.Find()) {
- try {
- auto handler =
- KeyHandler::OpenKey(parser.GetRootKey(), parser.GetSubKey(), v);
- auto data = handler.ReadValue(parser.GetValueName(),
- this->SupportedTypes, separator);
- parser.Replace(data);
- } catch (registry_error const& e) {
- this->LastError = e.what();
- parser.Replace(NOTFOUND);
- continue;
- }
- }
- result.emplace_back(parser.GetExpression());
- if (expression == parser.GetExpression()) {
- // there no substitutions, so can ignore other views
- break;
- }
- }
- return result;
- #else
- (void)view;
- (void)separator;
- ExpressionParser parser(expression);
- if (parser.Find()) {
- // expression holds unsupported registry access
- // so the expression cannot be used on this platform
- return cm::nullopt;
- }
- return std::vector<std::string>{ std::string{ expression } };
- #endif
- }
|