mirror of
https://github.com/Kitware/CMake.git
synced 2025-05-08 22:37:04 +08:00
cmake_host_system_information: query windows registry
Fixes: #21240, #23367
This commit is contained in:
parent
591426f5a0
commit
17ff86547e
@ -1,9 +1,23 @@
|
|||||||
cmake_host_system_information
|
cmake_host_system_information
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
Query host system specific information.
|
Query various host system information.
|
||||||
|
|
||||||
.. code-block:: cmake
|
Synopsis
|
||||||
|
^^^^^^^^
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
`Query host system specific information`_
|
||||||
|
cmake_host_system_information(RESULT <variable> QUERY <key> ...)
|
||||||
|
|
||||||
|
`Query Windows registry`_
|
||||||
|
cmake_host_system_information(RESULT <variable> QUERY WINDOWS_REGISTRY <key> ...)
|
||||||
|
|
||||||
|
Query host system specific information
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
cmake_host_system_information(RESULT <variable> QUERY <key> ...)
|
cmake_host_system_information(RESULT <variable> QUERY <key> ...)
|
||||||
|
|
||||||
@ -180,7 +194,7 @@ distribution-specific files`_ to collect OS identification data and map it
|
|||||||
into `man 5 os-release`_ variables.
|
into `man 5 os-release`_ variables.
|
||||||
|
|
||||||
Fallback Interface Variables
|
Fallback Interface Variables
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
""""""""""""""""""""""""""""
|
||||||
|
|
||||||
.. variable:: CMAKE_GET_OS_RELEASE_FALLBACK_SCRIPTS
|
.. variable:: CMAKE_GET_OS_RELEASE_FALLBACK_SCRIPTS
|
||||||
|
|
||||||
@ -246,3 +260,135 @@ Example:
|
|||||||
|
|
||||||
.. _man 5 os-release: https://www.freedesktop.org/software/systemd/man/os-release.html
|
.. _man 5 os-release: https://www.freedesktop.org/software/systemd/man/os-release.html
|
||||||
.. _various distribution-specific files: http://linuxmafia.com/faq/Admin/release-files.html
|
.. _various distribution-specific files: http://linuxmafia.com/faq/Admin/release-files.html
|
||||||
|
|
||||||
|
Query Windows registry
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
.. versionadded:: 3.24
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT <variable>
|
||||||
|
QUERY WINDOWS_REGISTRY <key> [VALUE_NAMES|SUBKEYS|VALUE <name>]
|
||||||
|
[VIEW (64|32|64_32|32_64|HOST|TARGET|BOTH)]
|
||||||
|
[SEPARATOR <separator>]
|
||||||
|
[ERROR_VARIABLE <result>])
|
||||||
|
|
||||||
|
Performs query operations on local computer registry subkey. Returns a list of
|
||||||
|
subkeys or value names that are located under the specified subkey in the
|
||||||
|
registry or the data of the specified value name. The result of the queried
|
||||||
|
entity is stored in ``<variable>``.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Querying registry for any other platforms than ``Windows``, including
|
||||||
|
``CYGWIN``, will always returns an empty string and sets an error message in
|
||||||
|
the variable specified with sub-option ``ERROR_VARIABLE``.
|
||||||
|
|
||||||
|
``<key>`` specify the full path of a subkey on the local computer. The
|
||||||
|
``<key>`` must include a valid root key. Valid root keys for the local computer
|
||||||
|
are:
|
||||||
|
|
||||||
|
* ``HKLM`` or ``HKEY_LOCAL_MACHINE``
|
||||||
|
* ``HKCU`` or ``HKEY_CURRENT_USER``
|
||||||
|
* ``HKCR`` or ``HKEY_CLASSES_ROOT``
|
||||||
|
* ``HKU`` or ``HKEY_USERS``
|
||||||
|
* ``HKCC`` or ``HKEY_CURRENT_CONFIG``
|
||||||
|
|
||||||
|
And, optionally, the path to a subkey under the specified root key. The path
|
||||||
|
separator can be the slash or the backslash. ``<key>`` is not case sensitive.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
.. code-block:: cmake
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "HKLM")
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Kitware")
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "HKCU\\SOFTWARE\\Kitware")
|
||||||
|
|
||||||
|
``VALUE_NAMES``
|
||||||
|
Request the list of value names defined under ``<key>``. If a default value
|
||||||
|
is defined, it will be identified with the special name ``(default)``.
|
||||||
|
|
||||||
|
``SUBKEYS``
|
||||||
|
Request the list of subkeys defined under ``<key>``.
|
||||||
|
|
||||||
|
``VALUE <name>``
|
||||||
|
Request the data stored in value named ``<name>``. If ``VALUE`` is not
|
||||||
|
specified or argument is the special name ``(default)``, the content of the
|
||||||
|
default value, if any, will be returned.
|
||||||
|
|
||||||
|
.. code-block:: cmake
|
||||||
|
|
||||||
|
# query default value for HKLM/SOFTWARE/Kitware key
|
||||||
|
cmake_host_system_information(RESULT result
|
||||||
|
QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Kitware")
|
||||||
|
|
||||||
|
# query default value for HKLM/SOFTWARE/Kitware key using special value name
|
||||||
|
cmake_host_system_information(RESULT result
|
||||||
|
QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Kitware"
|
||||||
|
VALUE "(default)")
|
||||||
|
|
||||||
|
Supported types are:
|
||||||
|
|
||||||
|
* ``REG_SZ``.
|
||||||
|
* ``REG_EXPAND_SZ``. The returned data is expanded.
|
||||||
|
* ``REG_MULTI_SZ``. The returned is expressed as a CMake list. See also
|
||||||
|
``SEPARATOR`` sub-option.
|
||||||
|
* ``REG_DWORD``.
|
||||||
|
* ``REG_QWORD``.
|
||||||
|
|
||||||
|
For all other types, an empty string is returned.
|
||||||
|
|
||||||
|
``VIEW``
|
||||||
|
Specify which registry views must be queried. When not specified, ``BOTH``
|
||||||
|
view is used.
|
||||||
|
|
||||||
|
``64``
|
||||||
|
Query the 64bit registry. On ``32bit Windows``, returns always an empty
|
||||||
|
string.
|
||||||
|
|
||||||
|
``32``
|
||||||
|
Query the 32bit registry.
|
||||||
|
|
||||||
|
``64_32``
|
||||||
|
For ``VALUE`` sub-option or default value, query the registry using view
|
||||||
|
``64``, and if the request failed, query the registry using view ``32``.
|
||||||
|
For ``VALUE_NAMES`` and ``SUBKEYS`` sub-options, query both views (``64``
|
||||||
|
and ``32``) and merge the results (sorted and duplicates removed).
|
||||||
|
|
||||||
|
``32_64``
|
||||||
|
For ``VALUE`` sub-option or default value, query the registry using view
|
||||||
|
``32``, and if the request failed, query the registry using view ``64``.
|
||||||
|
For ``VALUE_NAMES`` and ``SUBKEYS`` sub-options, query both views (``32``
|
||||||
|
and ``64``) and merge the results (sorted and duplicates removed).
|
||||||
|
|
||||||
|
``HOST``
|
||||||
|
Query the registry matching the architecture of the host: ``64`` on ``64bit
|
||||||
|
Windows`` and ``32`` on ``32bit Windows``.
|
||||||
|
|
||||||
|
``TARGET``
|
||||||
|
Query the registry matching the architecture specified by
|
||||||
|
:variable:`CMAKE_SIZEOF_VOID_P` variable. If not defined, fallback to
|
||||||
|
``HOST`` view.
|
||||||
|
|
||||||
|
``BOTH``
|
||||||
|
Query both views (``32`` and ``64``). The order depends of the following
|
||||||
|
rules: If :variable:`CMAKE_SIZEOF_VOID_P` variable is defined. Use the
|
||||||
|
following view depending of the content of this variable:
|
||||||
|
|
||||||
|
* ``8``: ``64_32``
|
||||||
|
* ``4``: ``32_64``
|
||||||
|
|
||||||
|
If :variable:`CMAKE_SIZEOF_VOID_P` variable is not defined, rely on
|
||||||
|
architecture of the host:
|
||||||
|
|
||||||
|
* ``64bit``: ``64_32``
|
||||||
|
* ``32bit``: ``32``
|
||||||
|
|
||||||
|
``SEPARATOR``
|
||||||
|
Specify the separator character for ``REG_MULTI_SZ`` type. When not
|
||||||
|
specified, the character ``\0`` is used.
|
||||||
|
|
||||||
|
``ERROR_VARIABLE <result>``
|
||||||
|
Returns any error raised during query operation. In case of success, the
|
||||||
|
variable holds an empty string.
|
||||||
|
5
Help/release/dev/chsi-query-windows-registry.rst
Normal file
5
Help/release/dev/chsi-query-windows-registry.rst
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
chsi-query-windows-registry
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
* :command:`cmake_host_system_information` command gains the capability, on
|
||||||
|
``Windows`` platform, to query the registry.
|
@ -460,6 +460,8 @@ set(SRCS
|
|||||||
cmVariableWatch.h
|
cmVariableWatch.h
|
||||||
cmVersion.cxx
|
cmVersion.cxx
|
||||||
cmVersion.h
|
cmVersion.h
|
||||||
|
cmWindowsRegistry.cxx
|
||||||
|
cmWindowsRegistry.h
|
||||||
cmWorkerPool.cxx
|
cmWorkerPool.cxx
|
||||||
cmWorkerPool.h
|
cmWorkerPool.h
|
||||||
cmWorkingDirectory.cxx
|
cmWorkingDirectory.cxx
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <cm/optional>
|
#include <cm/optional>
|
||||||
@ -19,10 +20,13 @@
|
|||||||
#include "cmsys/Glob.hxx"
|
#include "cmsys/Glob.hxx"
|
||||||
#include "cmsys/SystemInformation.hxx"
|
#include "cmsys/SystemInformation.hxx"
|
||||||
|
|
||||||
|
#include "cmArgumentParser.h"
|
||||||
#include "cmExecutionStatus.h"
|
#include "cmExecutionStatus.h"
|
||||||
#include "cmMakefile.h"
|
#include "cmMakefile.h"
|
||||||
|
#include "cmRange.h"
|
||||||
#include "cmStringAlgorithms.h"
|
#include "cmStringAlgorithms.h"
|
||||||
#include "cmSystemTools.h"
|
#include "cmSystemTools.h"
|
||||||
|
#include "cmWindowsRegistry.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# include "cmAlgorithms.h"
|
# include "cmAlgorithms.h"
|
||||||
@ -459,6 +463,105 @@ cm::optional<std::string> GetValueChained(GetterFn current, Next... chain)
|
|||||||
}
|
}
|
||||||
return GetValueChained(chain...);
|
return GetValueChained(chain...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Range>
|
||||||
|
bool QueryWindowsRegistry(Range args, cmExecutionStatus& status,
|
||||||
|
std::string const& variable)
|
||||||
|
{
|
||||||
|
using View = cmWindowsRegistry::View;
|
||||||
|
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 }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (args.empty()) {
|
||||||
|
status.SetError("missing <key> specification.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::string const& key = *args.begin();
|
||||||
|
|
||||||
|
struct Arguments
|
||||||
|
{
|
||||||
|
std::string ValueName;
|
||||||
|
bool ValueNames = false;
|
||||||
|
bool SubKeys = false;
|
||||||
|
std::string View;
|
||||||
|
std::string Separator;
|
||||||
|
std::string ErrorVariable;
|
||||||
|
};
|
||||||
|
cmArgumentParser<Arguments> parser;
|
||||||
|
parser.Bind("VALUE"_s, &Arguments::ValueName)
|
||||||
|
.Bind("VALUE_NAMES"_s, &Arguments::ValueNames)
|
||||||
|
.Bind("SUBKEYS"_s, &Arguments::SubKeys)
|
||||||
|
.Bind("VIEW"_s, &Arguments::View)
|
||||||
|
.Bind("SEPARATOR"_s, &Arguments::Separator)
|
||||||
|
.Bind("ERROR_VARIABLE"_s, &Arguments::ErrorVariable);
|
||||||
|
std::vector<std::string> invalidArgs;
|
||||||
|
std::vector<std::string> keywordsMissingValue;
|
||||||
|
|
||||||
|
Arguments const arguments =
|
||||||
|
parser.Parse(args.advance(1), &invalidArgs, &keywordsMissingValue);
|
||||||
|
if (!invalidArgs.empty()) {
|
||||||
|
status.SetError(cmStrCat("given invalid argument(s) \"",
|
||||||
|
cmJoin(invalidArgs, ", "_s), "\"."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!keywordsMissingValue.empty()) {
|
||||||
|
status.SetError(cmStrCat("missing expected value for argument(s) \"",
|
||||||
|
cmJoin(keywordsMissingValue, ", "_s), "\"."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((!arguments.ValueName.empty() &&
|
||||||
|
(arguments.ValueNames || arguments.SubKeys)) ||
|
||||||
|
(arguments.ValueName.empty() && arguments.ValueNames &&
|
||||||
|
arguments.SubKeys)) {
|
||||||
|
status.SetError("given mutually exclusive sub-options \"VALUE\", "
|
||||||
|
"\"VALUE_NAMES\" or \"SUBKEYS\".");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!arguments.View.empty() &&
|
||||||
|
ViewDefinitions.find(arguments.View) == ViewDefinitions.end()) {
|
||||||
|
status.SetError(
|
||||||
|
cmStrCat("given invalid value for \"VIEW\": ", arguments.View, '.'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& makefile = status.GetMakefile();
|
||||||
|
|
||||||
|
makefile.AddDefinition(variable, ""_s);
|
||||||
|
|
||||||
|
auto view =
|
||||||
|
arguments.View.empty() ? View::Both : ViewDefinitions[arguments.View];
|
||||||
|
cmWindowsRegistry registry(makefile);
|
||||||
|
if (arguments.ValueNames) {
|
||||||
|
auto result = registry.GetValueNames(key, view);
|
||||||
|
if (result) {
|
||||||
|
makefile.AddDefinition(variable, cmJoin(*result, ";"_s));
|
||||||
|
}
|
||||||
|
} else if (arguments.SubKeys) {
|
||||||
|
auto result = registry.GetSubKeys(key, view);
|
||||||
|
if (result) {
|
||||||
|
makefile.AddDefinition(variable, cmJoin(*result, ";"_s));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto result =
|
||||||
|
registry.ReadValue(key, arguments.ValueName, view, arguments.Separator);
|
||||||
|
if (result) {
|
||||||
|
makefile.AddDefinition(variable, *result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return error message if requested
|
||||||
|
if (!arguments.ErrorVariable.empty()) {
|
||||||
|
makefile.AddDefinition(arguments.ErrorVariable, registry.GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// END Private functions
|
// END Private functions
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
@ -481,6 +584,11 @@ bool cmCMakeHostSystemInformationCommand(std::vector<std::string> const& args,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (args[current_index + 1] == "WINDOWS_REGISTRY"_s) {
|
||||||
|
return QueryWindowsRegistry(cmMakeRange(args).advance(current_index + 2),
|
||||||
|
status, variable);
|
||||||
|
}
|
||||||
|
|
||||||
static cmsys::SystemInformation info;
|
static cmsys::SystemInformation info;
|
||||||
static auto initialized = false;
|
static auto initialized = false;
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
|
442
Source/cmWindowsRegistry.cxx
Normal file
442
Source/cmWindowsRegistry.cxx
Normal file
@ -0,0 +1,442 @@
|
|||||||
|
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||||
|
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||||
|
|
||||||
|
#include "cmWindowsRegistry.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
# include <algorithm>
|
||||||
|
# include <cstdint>
|
||||||
|
# include <exception>
|
||||||
|
# include <iterator>
|
||||||
|
# include <utility>
|
||||||
|
# include <vector>
|
||||||
|
|
||||||
|
# include <cm/memory>
|
||||||
|
# include <cmext/string_view>
|
||||||
|
|
||||||
|
# include <windows.h>
|
||||||
|
|
||||||
|
# include "cmsys/Encoding.hxx"
|
||||||
|
# include "cmsys/SystemTools.hxx"
|
||||||
|
|
||||||
|
# include "cmMakefile.h"
|
||||||
|
# include "cmStringAlgorithms.h"
|
||||||
|
# include "cmValue.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
namespace {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// class registry_exception
|
||||||
|
class registry_error : public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
registry_error(std::string msg)
|
||||||
|
: What(std::move(msg))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
~registry_error() override = default;
|
||||||
|
|
||||||
|
const char* what() const noexcept override { return What.c_str(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string What;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Class KeyHandler
|
||||||
|
class KeyHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using View = cmWindowsRegistry::View;
|
||||||
|
|
||||||
|
KeyHandler(HKEY hkey)
|
||||||
|
: Handler(hkey)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
~KeyHandler() { RegCloseKey(this->Handler); }
|
||||||
|
|
||||||
|
static KeyHandler OpenKey(cm::string_view key, View view);
|
||||||
|
|
||||||
|
std::string ReadValue(cm::string_view name, cm::string_view separator);
|
||||||
|
|
||||||
|
std::vector<std::string> GetValueNames();
|
||||||
|
std::vector<std::string> GetSubKeys();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::string FormatSystemError(LSTATUS status);
|
||||||
|
|
||||||
|
HKEY Handler;
|
||||||
|
};
|
||||||
|
|
||||||
|
KeyHandler KeyHandler::OpenKey(cm::string_view key, View view)
|
||||||
|
{
|
||||||
|
if (view == View::Reg64 && !Is64BitWindows()) {
|
||||||
|
throw registry_error("No 64bit registry on Windows32.");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto start = key.find_first_of("\\/"_s);
|
||||||
|
auto rootKey = key.substr(0, start);
|
||||||
|
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."));
|
||||||
|
}
|
||||||
|
std::wstring subKey;
|
||||||
|
if (start != cm::string_view::npos) {
|
||||||
|
subKey = cmsys::Encoding::ToWide(key.substr(start + 1).data());
|
||||||
|
}
|
||||||
|
// Update path format
|
||||||
|
std::replace(subKey.begin(), subKey.end(), L'/', L'\\');
|
||||||
|
|
||||||
|
REGSAM options = KEY_READ;
|
||||||
|
if (Is64BitWindows()) {
|
||||||
|
options |= view == View::Reg64 ? KEY_WOW64_64KEY : KEY_WOW64_32KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
HKEY hKey;
|
||||||
|
if (LSTATUS status = RegOpenKeyExW(hRootKey, subKey.c_str(), 0, options,
|
||||||
|
&hKey) != ERROR_SUCCESS) {
|
||||||
|
throw registry_error(FormatSystemError(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
return KeyHandler(hKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string KeyHandler::FormatSystemError(LSTATUS status)
|
||||||
|
{
|
||||||
|
std::string formattedMessage;
|
||||||
|
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) {
|
||||||
|
formattedMessage = "Windows Registry: unexpected error.";
|
||||||
|
} else {
|
||||||
|
formattedMessage = cmTrimWhitespace(cmsys::Encoding::ToNarrow(message));
|
||||||
|
}
|
||||||
|
LocalFree(message);
|
||||||
|
|
||||||
|
return formattedMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string KeyHandler::ReadValue(cm::string_view name,
|
||||||
|
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 = cmsys::Encoding::ToWide(name.data());
|
||||||
|
if ((status = RegQueryValueExW(this->Handler, valueName.c_str(), nullptr,
|
||||||
|
&type, data.get(), &size)) != ERROR_SUCCESS) {
|
||||||
|
throw registry_error(this->FormatSystemError(status));
|
||||||
|
}
|
||||||
|
switch (type) {
|
||||||
|
case REG_SZ:
|
||||||
|
return cmsys::Encoding::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 cmsys::Encoding::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 = cmsys::Encoding::ToWide(separator.data())[0];
|
||||||
|
std::replace(reinterpret_cast<wchar_t*>(data.get()),
|
||||||
|
reinterpret_cast<wchar_t*>(data.get()) +
|
||||||
|
(size / sizeof(wchar_t)) - 1,
|
||||||
|
sep, L';');
|
||||||
|
return cmsys::Encoding::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 = cmsys::Encoding::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(cmsys::Encoding::ToNarrow(data.get()));
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
if (status != ERROR_NO_MORE_ITEMS) {
|
||||||
|
throw registry_error(this->FormatSystemError(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
return subKeys;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// class cmWindowsRegistry
|
||||||
|
cmWindowsRegistry::cmWindowsRegistry(cmMakefile& makefile)
|
||||||
|
#if !defined(_WIN32) || defined(__CYGWIN__)
|
||||||
|
: 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;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (cmsys::SystemTools::Strucmp(name.data(), "(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, separator);
|
||||||
|
} catch (const registry_error& 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 (const registry_error& 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 (const registry_error& 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;
|
||||||
|
}
|
55
Source/cmWindowsRegistry.h
Normal file
55
Source/cmWindowsRegistry.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||||
|
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cm/optional>
|
||||||
|
#include <cm/string_view>
|
||||||
|
#include <cmext/string_view>
|
||||||
|
|
||||||
|
class cmMakefile;
|
||||||
|
|
||||||
|
class cmWindowsRegistry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cmWindowsRegistry(cmMakefile&);
|
||||||
|
|
||||||
|
enum class View
|
||||||
|
{
|
||||||
|
Both,
|
||||||
|
Target,
|
||||||
|
Host,
|
||||||
|
Reg64_32,
|
||||||
|
Reg32_64,
|
||||||
|
Reg32,
|
||||||
|
Reg64
|
||||||
|
};
|
||||||
|
|
||||||
|
cm::optional<std::string> ReadValue(cm::string_view key,
|
||||||
|
View view = View::Both,
|
||||||
|
cm::string_view separator = "\0"_s)
|
||||||
|
{
|
||||||
|
return this->ReadValue(key, ""_s, view, separator);
|
||||||
|
}
|
||||||
|
cm::optional<std::string> ReadValue(cm::string_view key,
|
||||||
|
cm::string_view name,
|
||||||
|
View view = View::Both,
|
||||||
|
cm::string_view separator = "\0"_s);
|
||||||
|
|
||||||
|
cm::optional<std::vector<std::string>> GetValueNames(cm::string_view key,
|
||||||
|
View view = View::Both);
|
||||||
|
cm::optional<std::vector<std::string>> GetSubKeys(cm::string_view key,
|
||||||
|
View view = View::Both);
|
||||||
|
|
||||||
|
cm::string_view GetLastError() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
std::vector<View> ComputeViews(View view);
|
||||||
|
|
||||||
|
int TargetSize = 0;
|
||||||
|
#endif
|
||||||
|
std::string LastError;
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
1
|
@ -0,0 +1,4 @@
|
|||||||
|
CMake Error at Registry_BadKey1.cmake:[0-9]+ \(message\):
|
||||||
|
WRONG_ROOT: invalid root key.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:[0-9]+ \(include\)
|
@ -0,0 +1,4 @@
|
|||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY WRONG_ROOT/SUBKEY ERROR_VARIABLE error)
|
||||||
|
if (NOT error STREQUAL "")
|
||||||
|
message(FATAL_ERROR "${error}")
|
||||||
|
endif()
|
@ -0,0 +1 @@
|
|||||||
|
1
|
@ -0,0 +1,4 @@
|
|||||||
|
CMake Error at Registry_BadKey2.cmake:[0-9]+ \(message\):
|
||||||
|
HKLM-SUBKEY: invalid root key.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:[0-9]+ \(include\)
|
@ -0,0 +1,4 @@
|
|||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY HKLM-SUBKEY ERROR_VARIABLE error)
|
||||||
|
if (NOT error STREQUAL "")
|
||||||
|
message(FATAL_ERROR "${error}")
|
||||||
|
endif()
|
@ -0,0 +1 @@
|
|||||||
|
1
|
@ -0,0 +1,4 @@
|
|||||||
|
CMake Error at Registry_BadQuery1.cmake:[0-9]+ \(cmake_host_system_information\):
|
||||||
|
cmake_host_system_information given invalid argument\(s\) "BAD_OPTION".
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:[0-9]+ \(include\)
|
@ -0,0 +1 @@
|
|||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY HKLM/SOFTWARE BAD_OPTION)
|
@ -0,0 +1 @@
|
|||||||
|
1
|
@ -0,0 +1,5 @@
|
|||||||
|
CMake Error at Registry_BadQuery2.cmake:[0-9]+ \(cmake_host_system_information\):
|
||||||
|
cmake_host_system_information missing expected value for argument\(s\)
|
||||||
|
"VALUE".
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:[0-9]+ \(include\)
|
@ -0,0 +1 @@
|
|||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY HKLM/SOFTWARE VALUE)
|
@ -0,0 +1 @@
|
|||||||
|
1
|
@ -0,0 +1,5 @@
|
|||||||
|
CMake Error at Registry_BadView1.cmake:[0-9]+ \(cmake_host_system_information\):
|
||||||
|
cmake_host_system_information missing expected value for argument\(s\)
|
||||||
|
"VIEW".
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:[0-9]+ \(include\)
|
@ -0,0 +1 @@
|
|||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY HKLM/SOFTWARE VIEW)
|
@ -0,0 +1 @@
|
|||||||
|
1
|
@ -0,0 +1,4 @@
|
|||||||
|
CMake Error at Registry_BadView2.cmake:[0-9]+ \(cmake_host_system_information\):
|
||||||
|
cmake_host_system_information given invalid value for "VIEW": BAD_VIEW.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:[0-9]+ \(include\)
|
@ -0,0 +1 @@
|
|||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY HKLM/SOFTWARE VIEW BAD_VIEW)
|
@ -0,0 +1 @@
|
|||||||
|
1
|
@ -0,0 +1,4 @@
|
|||||||
|
CMake Error at Registry_BadView3.cmake:[0-9]+ \(cmake_host_system_information\):
|
||||||
|
cmake_host_system_information given invalid argument\(s\) "64".
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:[0-9]+ \(include\)
|
@ -0,0 +1 @@
|
|||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY HKLM/SOFTWARE VIEW 32 64)
|
@ -0,0 +1 @@
|
|||||||
|
1
|
@ -0,0 +1,4 @@
|
|||||||
|
CMake Error at Registry_NoArgs.cmake:[0-9]+ \(cmake_host_system_information\):
|
||||||
|
cmake_host_system_information missing <key> specification.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:[0-9]+ \(include\)
|
@ -0,0 +1 @@
|
|||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY)
|
@ -0,0 +1,232 @@
|
|||||||
|
|
||||||
|
# check Windows architecture
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "HKCU" SUBKEYS VIEW 64 ERROR_VARIABLE status)
|
||||||
|
if (status STREQUAL "")
|
||||||
|
set(HOST_64BIT TRUE)
|
||||||
|
else()
|
||||||
|
set(HOST_64BIT FALSE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# helper function for test validation
|
||||||
|
function(CHECK key result status expression)
|
||||||
|
if(status STREQUAL "")
|
||||||
|
cmake_language(EVAL CODE
|
||||||
|
"if (NOT (${expression}))
|
||||||
|
message(SEND_ERROR \"wrong value for key '${key}': '${result}'\")
|
||||||
|
endif()")
|
||||||
|
else()
|
||||||
|
message(SEND_ERROR "query failed for key '${key}': '${status}'")
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
|
||||||
|
# HKCU/Software/Classes/CLSID/CMake-Tests/chsi-registry: Query default value
|
||||||
|
set(KEY "HKCU/Software/Classes/CLSID/CMake-Tests/chsi-registry")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" ERROR_VARIABLE status)
|
||||||
|
check("${KEY}" "${result}" "${status}"
|
||||||
|
"(HOST_64BIT AND result STREQUAL \"default 64bit\")
|
||||||
|
OR (NOT HOST_64BIT AND result STREQUAL \"default 32bit\")")
|
||||||
|
# query value using special name should be identical to default value
|
||||||
|
cmake_host_system_information(RESULT result2 QUERY WINDOWS_REGISTRY "${KEY}" VALUE "(default)" ERROR_VARIABLE status)
|
||||||
|
check("${KEY}{(default)}" "${result2}" "${status}" "result2 STREQUAL result")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VIEW HOST ERROR_VARIABLE status)
|
||||||
|
check("${KEY}" "${result}" "${status}"
|
||||||
|
"(HOST_64BIT AND result STREQUAL \"default 64bit\")
|
||||||
|
OR (NOT HOST_64BIT AND result STREQUAL \"default 32bit\")")
|
||||||
|
# VIEW TARGET should have same value as VIEW HOST
|
||||||
|
cmake_host_system_information(RESULT result2 QUERY WINDOWS_REGISTRY "${KEY}" VIEW TARGET ERROR_VARIABLE status)
|
||||||
|
check("${KEY}" "${result2}" "${status}" "result2 STREQUAL result")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VIEW 64 ERROR_VARIABLE status)
|
||||||
|
check("${KEY}" "${result}" "${status}" "result STREQUAL \"default 64bit\"")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VIEW 32 ERROR_VARIABLE status)
|
||||||
|
check("${KEY}" "${result}" "${status}" "result STREQUAL \"default 32bit\"")
|
||||||
|
|
||||||
|
# reg 64bit is read first
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VIEW 64_32 ERROR_VARIABLE status)
|
||||||
|
check("${KEY}" "${result}" "${status}" "result STREQUAL \"default 64bit\"")
|
||||||
|
|
||||||
|
# reg 32bit is read first
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VIEW 32_64 ERROR_VARIABLE status)
|
||||||
|
check("${KEY}" "${result}" "${status}" "result STREQUAL \"default 32bit\"")
|
||||||
|
|
||||||
|
|
||||||
|
# HKCU/Software/CMake-Tests/chsi-registry: Query named value
|
||||||
|
set(KEY "HKCU/Software/Classes/CLSID/CMake-Tests/chsi-registry")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE BYTE_SIZE
|
||||||
|
ERROR_VARIABLE status)
|
||||||
|
check("${KEY}{BYTE_SIZE}" "${result}" "${status}"
|
||||||
|
"(HOST_64BIT AND result STREQUAL \"64bit\")
|
||||||
|
OR (NOT HOST_64BIT AND result STREQUAL \"32bit\")")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE BYTE_SIZE
|
||||||
|
VIEW HOST ERROR_VARIABLE status)
|
||||||
|
check("${KEY}{BYTE_SIZE}" "${result}" "${status}"
|
||||||
|
"(HOST_64BIT AND result STREQUAL \"64bit\")
|
||||||
|
OR (NOT HOST_64BIT AND result STREQUAL \"32bit\")")
|
||||||
|
# VIEW TARGET should have same value as VIEW HOST
|
||||||
|
cmake_host_system_information(RESULT result2 QUERY WINDOWS_REGISTRY "${KEY}" VALUE BYTE_SIZE
|
||||||
|
VIEW TARGET ERROR_VARIABLE status)
|
||||||
|
check("${KEY}{BYTE_SIZE}" "${result2}" "${status}" "result2 STREQUAL result")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE BYTE_SIZE
|
||||||
|
VIEW 64 ERROR_VARIABLE status)
|
||||||
|
check("${KEY}{BYTE_SIZE}" "${result}" "${status}" "result STREQUAL \"64bit\"")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE BYTE_SIZE
|
||||||
|
VIEW 32 ERROR_VARIABLE status)
|
||||||
|
check("${KEY}{BYTE_SIZE}" "${result}" "${status}" "result STREQUAL \"32bit\"")
|
||||||
|
|
||||||
|
# reg 64bit is read first
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE BYTE_SIZE
|
||||||
|
VIEW 64_32 ERROR_VARIABLE status)
|
||||||
|
check("${KEY}{BYTE_SIZE}" "${result}" "${status}" "result STREQUAL \"64bit\"")
|
||||||
|
|
||||||
|
# reg 32bit is read first
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE BYTE_SIZE
|
||||||
|
VIEW 32_64 ERROR_VARIABLE status)
|
||||||
|
check("${KEY}{BYTE_SIZE}" "${result}" "${status}" "result STREQUAL \"32bit\"")
|
||||||
|
|
||||||
|
|
||||||
|
# HKCU/Software/CMake-Tests/chsi-registry: check retrieval of various types
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE VALUE_SZ ERROR_VARIABLE status)
|
||||||
|
check("${KEY}{VALUE_SZ}" "${result}" "${status}" "result STREQUAL \"data with space\"")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE VALUE_EXPAND_SZ ERROR_VARIABLE status)
|
||||||
|
check("${KEY}{VALUE_EXPAND_SZ}" "${result}" "${status}"
|
||||||
|
"(NOT result STREQUAL \"PATH=%PATH%\") AND (result MATCHES \"^PATH=\")")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE VALUE_MULTI_SZ ERROR_VARIABLE status)
|
||||||
|
check("${KEY}{VALUE_MULTI_SZ}" "${result}" "${status}" "result STREQUAL \"data1;data2\"")
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE VALUE2_MULTI_SZ
|
||||||
|
SEPARATOR "|" ERROR_VARIABLE status)
|
||||||
|
check("${KEY}{VALUE2_MULTI_SZ}" "${result}" "${status}" "result STREQUAL \"data1;data2\"")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE VALUE_DWORD ERROR_VARIABLE status)
|
||||||
|
check("${KEY}{VALUE_DWORD}" "${result}" "${status}" "result EQUAL \"129\"")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE VALUE_QWORD ERROR_VARIABLE status)
|
||||||
|
check("${KEY}{VALUE_QWORD}" "${result}" "${status}" "result EQUAL \"513\"")
|
||||||
|
|
||||||
|
|
||||||
|
# HKCU/Software/CMake-Tests/chsi-registry: check retrieval of value names
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE_NAMES
|
||||||
|
ERROR_VARIABLE status)
|
||||||
|
check("${KEY}[VALUE_NAMES]" "${result}" "${status}" "result STREQUAL \"(default);BYTE_SIZE;VALUE2_MULTI_SZ;VALUE2_SZ;VALUE_DWORD;VALUE_EXPAND_SZ;VALUE_MULTI_SZ;VALUE_QWORD;VALUE_SZ\"")
|
||||||
|
# VIEW BOTH should have same result as default view
|
||||||
|
cmake_host_system_information(RESULT result2 QUERY WINDOWS_REGISTRY "${KEY}" VALUE_NAMES
|
||||||
|
VIEW BOTH ERROR_VARIABLE status)
|
||||||
|
check("${KEY}[VALUE_NAMES]" "${result2}" "${status}" "result STREQUAL \"(default);BYTE_SIZE;VALUE2_MULTI_SZ;VALUE2_SZ;VALUE_DWORD;VALUE_EXPAND_SZ;VALUE_MULTI_SZ;VALUE_QWORD;VALUE_SZ\"")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE_NAMES
|
||||||
|
VIEW HOST ERROR_VARIABLE status)
|
||||||
|
check("${KEY}[VALUE_NAMES]" "${result}" "${status}"
|
||||||
|
"(HOST_64BIT AND result STREQUAL \"(default);BYTE_SIZE;VALUE2_MULTI_SZ;VALUE_DWORD;VALUE_EXPAND_SZ;VALUE_MULTI_SZ;VALUE_QWORD;VALUE_SZ\")
|
||||||
|
OR (NOT HOST_64BIT AND result STREQUAL \"(default);BYTE_SIZE;VALUE2_SZ\")")
|
||||||
|
# VIEW TARGET should have same result as VIEW HOST
|
||||||
|
cmake_host_system_information(RESULT result2 QUERY WINDOWS_REGISTRY "${KEY}" VALUE_NAMES
|
||||||
|
VIEW TARGET ERROR_VARIABLE status)
|
||||||
|
check("${KEY}[VALUE_NAMES]" "${result2}" "${status}"
|
||||||
|
"(HOST_64BIT AND result STREQUAL \"(default);BYTE_SIZE;VALUE2_MULTI_SZ;VALUE_DWORD;VALUE_EXPAND_SZ;VALUE_MULTI_SZ;VALUE_QWORD;VALUE_SZ\")
|
||||||
|
OR (NOT HOST_64BIT AND result STREQUAL \"(default);BYTE_SIZE;VALUE2_SZ\")")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE_NAMES
|
||||||
|
VIEW 64 ERROR_VARIABLE status)
|
||||||
|
check("${KEY}[VALUE_NAMES]" "${result}" "${status}"
|
||||||
|
"result STREQUAL \"(default);BYTE_SIZE;VALUE2_MULTI_SZ;VALUE_DWORD;VALUE_EXPAND_SZ;VALUE_MULTI_SZ;VALUE_QWORD;VALUE_SZ\"")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE_NAMES
|
||||||
|
VIEW 32 ERROR_VARIABLE status)
|
||||||
|
check("${KEY}[VALUE_NAMES]" "${result}" "${status}" "result STREQUAL \"(default);BYTE_SIZE;VALUE2_SZ\"")
|
||||||
|
|
||||||
|
# reg 64bit is read first
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE_NAMES
|
||||||
|
VIEW 64_32 ERROR_VARIABLE status)
|
||||||
|
check("${KEY}[VALUE_NAMES]" "${result}" "${status}"
|
||||||
|
"result STREQUAL \"(default);BYTE_SIZE;VALUE2_MULTI_SZ;VALUE2_SZ;VALUE_DWORD;VALUE_EXPAND_SZ;VALUE_MULTI_SZ;VALUE_QWORD;VALUE_SZ\"")
|
||||||
|
|
||||||
|
# reg 32bit is read first. Result is the same as with view 64_32
|
||||||
|
cmake_host_system_information(RESULT result2 QUERY WINDOWS_REGISTRY "${KEY}" VALUE_NAMES
|
||||||
|
VIEW 32_64 ERROR_VARIABLE status)
|
||||||
|
check("${KEY}[VALUE_NAMES]" "${result2}" "${status}" "result2 STREQUAL result")
|
||||||
|
|
||||||
|
|
||||||
|
# HKCU/Software/CMake-Tests/chsi-registry: check retrieval of sub keys
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" SUBKEYS
|
||||||
|
ERROR_VARIABLE status)
|
||||||
|
check("${KEY}[SUBKEYS]" "${result}" "${status}" "result STREQUAL \"subkey1;subkey2;subkey3\"")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" SUBKEYS
|
||||||
|
VIEW HOST ERROR_VARIABLE status)
|
||||||
|
check("${KEY}[SUBKEYS]" "${result}" "${status}"
|
||||||
|
"(HOST_64BIT AND result STREQUAL \"subkey1;subkey2\")
|
||||||
|
OR (NOT HOST_64BIT AND result STREQUAL \"subkey1;subkey3\")")
|
||||||
|
# VIEW TARGET should have same result as VIEW HOST
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" SUBKEYS
|
||||||
|
VIEW TARGET ERROR_VARIABLE status)
|
||||||
|
check("${KEY}[SUBKEYS]" "${result}" "${status}"
|
||||||
|
"(HOST_64BIT AND result STREQUAL \"subkey1;subkey2\")
|
||||||
|
OR (NOT HOST_64BIT AND result STREQUAL \"subkey1;subkey3\")")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" SUBKEYS
|
||||||
|
VIEW 64 ERROR_VARIABLE status)
|
||||||
|
check("${KEY}[SUBKEYS]" "${result}" "${status}"
|
||||||
|
"result STREQUAL \"subkey1;subkey2\"")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" SUBKEYS
|
||||||
|
VIEW 32 ERROR_VARIABLE status)
|
||||||
|
check("${KEY}[SUBKEYS]" "${result}" "${status}"
|
||||||
|
"result STREQUAL \"subkey1;subkey3\"")
|
||||||
|
|
||||||
|
# reg 64bit is read first
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" SUBKEYS
|
||||||
|
VIEW 64_32 ERROR_VARIABLE status)
|
||||||
|
check("${KEY}[SUBLEYS]" "${result}" "${status}" "result STREQUAL \"subkey1;subkey2;subkey3\"")
|
||||||
|
|
||||||
|
# reg 32bit is read first. Result is the same as with view 64_32
|
||||||
|
cmake_host_system_information(RESULT result2 QUERY WINDOWS_REGISTRY "${KEY}" SUBKEYS
|
||||||
|
VIEW 32_64 ERROR_VARIABLE status)
|
||||||
|
check("${KEY}[SUBKEYS]" "${result2}" "${status}" "result2 STREQUAL result")
|
||||||
|
|
||||||
|
|
||||||
|
# Check influence of variable CMAKE_SIZEOF_VOID_P
|
||||||
|
set(CMAKE_SIZEOF_VOID_P 8)
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}"
|
||||||
|
VIEW TARGET ERROR_VARIABLE status)
|
||||||
|
check("${KEY}" "${result}" "${status}" "result STREQUAL \"default 64bit\"")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE BYTE_SIZE
|
||||||
|
VIEW TARGET ERROR_VARIABLE status)
|
||||||
|
check("${KEY}" "${result}" "${status}" "result STREQUAL \"64bit\"")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE_NAMES
|
||||||
|
VIEW TARGET ERROR_VARIABLE status)
|
||||||
|
check("${KEY}" "${result}" "${status}" "result STREQUAL \"(default);BYTE_SIZE;VALUE2_MULTI_SZ;VALUE_DWORD;VALUE_EXPAND_SZ;VALUE_MULTI_SZ;VALUE_QWORD;VALUE_SZ\"")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" SUBKEYS
|
||||||
|
VIEW TARGET ERROR_VARIABLE status)
|
||||||
|
check("${KEY}" "${result}" "${status}" "result STREQUAL \"subkey1;subkey2\"")
|
||||||
|
|
||||||
|
|
||||||
|
set(CMAKE_SIZEOF_VOID_P 4)
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}"
|
||||||
|
VIEW TARGET ERROR_VARIABLE status)
|
||||||
|
check("${KEY}" "${result}" "${status}" "result STREQUAL \"default 32bit\"")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE BYTE_SIZE
|
||||||
|
VIEW TARGET ERROR_VARIABLE status)
|
||||||
|
check("${KEY}" "${result}" "${status}" "result STREQUAL \"32bit\"")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE_NAMES
|
||||||
|
VIEW TARGET ERROR_VARIABLE status)
|
||||||
|
check("${KEY}" "${result}" "${status}" "result STREQUAL \"(default);BYTE_SIZE;VALUE2_SZ\"")
|
||||||
|
|
||||||
|
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" SUBKEYS
|
||||||
|
VIEW TARGET ERROR_VARIABLE status)
|
||||||
|
check("${KEY}" "${result}" "${status}" "result STREQUAL \"subkey1;subkey3\"")
|
@ -21,3 +21,27 @@ if(RunCMake_GENERATOR MATCHES "^Visual Studio " AND NOT RunCMake_GENERATOR STREQ
|
|||||||
else()
|
else()
|
||||||
run_cmake(VsMSBuildMissing)
|
run_cmake(VsMSBuildMissing)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# WINDOWS_REGISTRY tests
|
||||||
|
run_cmake(Registry_NoArgs)
|
||||||
|
run_cmake(Registry_BadQuery1)
|
||||||
|
run_cmake(Registry_BadQuery2)
|
||||||
|
run_cmake(Registry_BadView1)
|
||||||
|
run_cmake(Registry_BadView2)
|
||||||
|
run_cmake(Registry_BadView3)
|
||||||
|
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
|
||||||
|
run_cmake(Registry_BadKey1)
|
||||||
|
run_cmake(Registry_BadKey2)
|
||||||
|
|
||||||
|
# Tests using the Windows registry
|
||||||
|
find_program(REG NAMES "reg.exe" NO_CACHE)
|
||||||
|
if (REG)
|
||||||
|
# crete some entries in the registry
|
||||||
|
cmake_path(CONVERT "${RunCMake_SOURCE_DIR}/registry_data.reg" TO_NATIVE_PATH_LIST registry_data)
|
||||||
|
execute_process(COMMAND "${REG}" import "${registry_data}" OUTPUT_QUIET ERROR_QUIET)
|
||||||
|
run_cmake(Registry_Query)
|
||||||
|
# clean-up registry
|
||||||
|
execute_process(COMMAND "${REG}" delete "HKCU\\SOFTWARE\\Classes\\CLSID\\CMake-Tests" /f OUTPUT_QUIET ERROR_QUIET)
|
||||||
|
execute_process(COMMAND "${REG}" delete "HKCU\\SOFTWARE\\Classes\\WOW6432Node\\CLSID\\CMake-Tests" /f OUTPUT_QUIET ERROR_QUIET)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
BIN
Tests/RunCMake/cmake_host_system_information/registry_data.reg
Normal file
BIN
Tests/RunCMake/cmake_host_system_information/registry_data.reg
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user