diff options
| author | ruki <[email protected]> | 2020-12-26 19:19:31 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2020-12-26 19:19:31 +0800 |
| commit | 3f12aa4188f26396a0883ebd4ba0738a9f1dcefa (patch) | |
| tree | e300f3364cd7f3c1ed95e55bac5c7ed9c7760f58 | |
| parent | 0f8cac544eaf61ecb2fde78cc2fed7f40c04cb92 (diff) | |
| parent | 55e63db24d799dc3f15c7536ee776d2fb5723a74 (diff) | |
Merge pull request #1162 from xmake-io/registry
improve registry
| -rw-r--r-- | CHANGELOG.md | 2 | ||||
| m--------- | core/src/tbox/tbox | 0 | ||||
| -rw-r--r-- | core/src/xmake/engine.c | 4 | ||||
| -rw-r--r-- | core/src/xmake/makefile | 2 | ||||
| -rw-r--r-- | core/src/xmake/winos/registry_keys.c | 231 | ||||
| -rw-r--r-- | core/src/xmake/winos/registry_query.c | 88 | ||||
| -rw-r--r-- | core/src/xmake/winos/registry_values.c | 162 | ||||
| -rw-r--r-- | xmake/core/base/winos.lua | 165 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/interpreter/winos.lua | 8 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/winos.lua | 28 |
10 files changed, 621 insertions, 69 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index d6099107f..b5d4c05f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ * [#1098](https://github.com/xmake-io/xmake/issues/1098): Support stdin for os.execv * [#1079](https://github.com/xmake-io/xmake/issues/1079): Add autoupdate plugin rule for vsxmake, `add_rules("plugin.vsxmake.autoupdate")` * Add `xmake f --vs_runtime=MT` and `set_runtimes("MT")` to set vs runtime for targets and packages +* [#1032](https://github.com/xmake-io/xmake/issues/1032): Support to enum registry keys and values ### Change @@ -895,6 +896,7 @@ * [#1098](https://github.com/xmake-io/xmake/issues/1098): 支持传递 stdin 到 os.execv 进行输入重定向 * [#1079](https://github.com/xmake-io/xmake/issues/1079): 为 vsxmake 插件添加工程自动更新插件,`add_rules("plugin.vsxmake.autoupdate")` * 添加 `xmake f --vs_runtime=MT` 和 `set_runtimes("MT")` 去更方便的对 target 和 package 进行设置 +* [#1032](https://github.com/xmake-io/xmake/issues/1032): 支持枚举注册表 keys 和 values ### 改进 diff --git a/core/src/tbox/tbox b/core/src/tbox/tbox -Subproject 081b2950b1c91e291d8a6ad9f9275fd7d28a7bb +Subproject d80f8d11356e1cdb7465278ecd7ad4e3478c3c4 diff --git a/core/src/xmake/engine.c b/core/src/xmake/engine.c index b4d2b7101..71b202689 100644 --- a/core/src/xmake/engine.c +++ b/core/src/xmake/engine.c @@ -185,6 +185,8 @@ tb_int_t xm_winos_ansi_cp(lua_State* lua); tb_int_t xm_winos_oem_cp(lua_State* lua); tb_int_t xm_winos_logical_drives(lua_State* lua); tb_int_t xm_winos_registry_query(lua_State* lua); +tb_int_t xm_winos_registry_keys(lua_State* lua); +tb_int_t xm_winos_registry_values(lua_State* lua); #endif // the string functions @@ -287,6 +289,8 @@ static luaL_Reg const g_winos_functions[] = , { "ansi_cp", xm_winos_ansi_cp } , { "logical_drives", xm_winos_logical_drives } , { "registry_query", xm_winos_registry_query } +, { "registry_keys", xm_winos_registry_keys } +, { "registry_values", xm_winos_registry_values } , { tb_null, tb_null } }; #endif diff --git a/core/src/xmake/makefile b/core/src/xmake/makefile index 162427ea4..5421a907d 100644 --- a/core/src/xmake/makefile +++ b/core/src/xmake/makefile @@ -135,6 +135,8 @@ ifdef iswin xmake_C_FILES += \ winos/ansi \ winos/logical_drives \ + winos/registry_keys \ + winos/registry_values \ winos/registry_query endif diff --git a/core/src/xmake/winos/registry_keys.c b/core/src/xmake/winos/registry_keys.c new file mode 100644 index 000000000..234cdf035 --- /dev/null +++ b/core/src/xmake/winos/registry_keys.c @@ -0,0 +1,231 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, TBOOX Open Source Group. + * + * @author ruki + * @file registry_keys.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "registry_keys" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * types + */ + +// the enum info type +typedef struct __xm_winos_registry_enum_info_t +{ + lua_State* lua; + HKEY key; + tb_int_t ok; + tb_char_t const* error; + tb_int_t count; + tb_wchar_t key_name[1024]; + tb_char_t key_path_a[TB_PATH_MAXN]; + +}xm_winos_registry_enum_info_t; + +/* ////////////////////////////////////////////////////////////////////////////////////// + * private implementation + */ +static tb_void_t xm_winos_registry_enum_keys(xm_winos_registry_enum_info_t* info, tb_wchar_t const* rootdir, tb_long_t recursion) +{ + // enum keys + HKEY keynew = tb_null; + lua_State* lua = info->lua; + tb_wchar_t* key_path = tb_null; + tb_size_t key_path_maxn = TB_PATH_MAXN; + do + { + // open registry key + if (RegOpenKeyExW(info->key, rootdir, 0, KEY_READ, &keynew) != ERROR_SUCCESS && keynew) + { + info->ok = -1; + info->error = "open registry key failed"; + break; + } + + // query keys + DWORD key_name_num = 0; + DWORD key_name_maxn = 0; + if (RegQueryInfoKeyW(keynew, tb_null, tb_null, tb_null, &key_name_num, &key_name_maxn, tb_null, tb_null, tb_null, tb_null, tb_null, tb_null) != ERROR_SUCCESS) + { + // cannot query this key, we ignore it + break; + } + key_name_maxn++; // add `\0` + + // ensure enough key path buffer + if (key_name_maxn > tb_arrayn(info->key_name)) + { + info->ok = -1; + info->error = "no enough key path buffer"; + break; + } + + // init key path + key_path = (tb_wchar_t*)tb_malloc(key_path_maxn * sizeof(tb_wchar_t)); + if (!key_path) + { + info->ok = -1; + info->error = "no enough key path buffer"; + break; + } + + // get all keys + DWORD i = 0; + for (i = 0; i < key_name_num && info->ok > 0; i++) + { + // get key name + info->key_name[0] = L'\0'; + DWORD key_name_size = tb_arrayn(info->key_name); + if (RegEnumKeyExW(keynew, i, info->key_name, &key_name_size, tb_null, tb_null, tb_null, tb_null) != ERROR_SUCCESS) + { + info->ok = -1; + info->error = "get registry key failed"; + break; + } + + // get key path + tb_swprintf(key_path, key_path_maxn, L"%s\\%s", rootdir, info->key_name); + + // get key path (mbs) + tb_size_t key_path_a_size = tb_wtoa(info->key_path_a, key_path, sizeof(info->key_path_a)); + if (key_path_a_size == -1) + { + info->ok = -1; + info->error = "convert registry key path failed"; + break; + } + + // do callback(key_name) + lua_pushvalue(lua, 4); + lua_pushlstring(lua, info->key_path_a, key_path_a_size); + lua_call(lua, 1, 1); + info->count++; + + // is continue? + tb_bool_t is_continue = lua_toboolean(lua, -1); + lua_pop(lua, 1); + if (!is_continue) + { + info->ok = 0; + break; + } + + // enum all subkeys + if (recursion > 0 || recursion < 0) + xm_winos_registry_enum_keys(info, key_path, recursion > 0? recursion - 1 : recursion); + } + + } while (0); + + // exit registry key + if (keynew) + RegCloseKey(keynew); + keynew = tb_null; + + // free key path + if (key_path) tb_free(key_path); + key_path = tb_null; +} + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +/* get registry keys + * + * local count, errors = winos.registry_keys("HKEY_LOCAL_MACHINE", + * "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", + * function (key_path) + * return true -- continue or break + * end) + */ +tb_int_t xm_winos_registry_keys(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // get the arguments + tb_char_t const* rootkey = luaL_checkstring(lua, 1); + tb_char_t const* rootdir = luaL_checkstring(lua, 2); + tb_long_t recursion = lua_tointeger(lua, 3); + tb_bool_t is_function = lua_isfunction(lua, 4); + tb_check_return_val(rootkey && rootdir && is_function, 0); + + // enum keys + tb_bool_t ok = tb_false; + tb_int_t count = 0; + HKEY key = tb_null; + do + { + // get registry rootkey + if (!tb_strcmp(rootkey, "HKEY_CLASSES_ROOT")) key = HKEY_CLASSES_ROOT; + else if (!tb_strcmp(rootkey, "HKEY_CURRENT_CONFIG")) key = HKEY_CURRENT_CONFIG; + else if (!tb_strcmp(rootkey, "HKEY_CURRENT_USER")) key = HKEY_CURRENT_USER; + else if (!tb_strcmp(rootkey, "HKEY_LOCAL_MACHINE")) key = HKEY_LOCAL_MACHINE; + else if (!tb_strcmp(rootkey, "HKEY_USERS")) key = HKEY_USERS; + else + { + lua_pushnil(lua); + lua_pushfstring(lua, "invalid registry rootkey: %s", rootkey); + break; + } + + // do enum + tb_wchar_t rootdir_w[TB_PATH_MAXN]; + if (tb_atow(rootdir_w, rootdir, TB_PATH_MAXN) == -1) + { + lua_pushnil(lua); + lua_pushfstring(lua, "rootdir is too long: %s", rootdir); + break; + } + xm_winos_registry_enum_info_t info; + info.lua = lua; + info.key = key; + info.count = 0; + info.ok = tb_true; + info.error = tb_null; + xm_winos_registry_enum_keys(&info, rootdir_w, recursion); + count = info.count; + ok = info.ok >= 0; + if (!ok) + { + lua_pushnil(lua); + lua_pushfstring(lua, "%s: %s\\%s", info.error? info.error : "enum registry keys failed", rootkey, rootdir); + } + + } while (0); + + // ok? + if (ok) + { + lua_pushinteger(lua, count); + return 1; + } + else return 2; +} + diff --git a/core/src/xmake/winos/registry_query.c b/core/src/xmake/winos/registry_query.c index a9d968539..f507bbaab 100644 --- a/core/src/xmake/winos/registry_query.c +++ b/core/src/xmake/winos/registry_query.c @@ -42,74 +42,36 @@ typedef BOOL (WINAPI* xm_RegGetValueA_t)(HKEY hkey, LPCSTR lpSubKey, LPCSTR lpVa /* query registry * - * local value, errors = winos.registry_query("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug;Debugger") + * local value, errors = winos.registry_query("HKEY_LOCAL_MACHINE", "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", "Debugger") */ tb_int_t xm_winos_registry_query(lua_State* lua) { // check tb_assert_and_check_return_val(lua, 0); - // get the path - tb_char_t const* path = luaL_checkstring(lua, 1); - tb_check_return_val(path, 0); + // get the arguments + tb_char_t const* rootkey = luaL_checkstring(lua, 1); + tb_char_t const* rootdir = luaL_checkstring(lua, 2); + tb_char_t const* valuename = luaL_checkstring(lua, 3); + tb_check_return_val(rootkey && rootdir && valuename, 0); // query key-value tb_bool_t ok = tb_false; - HKEY key = NULL; - HKEY keynew = NULL; - tb_char_t pathbuf[TB_PATH_MAXN]; + HKEY key = tb_null; + HKEY keynew = tb_null; tb_char_t* value = tb_null; do { - // copy path - tb_size_t size = tb_strlcpy(pathbuf, path, sizeof(pathbuf)); - if (size >= sizeof(pathbuf)) - { - lua_pushnil(lua); - lua_pushfstring(lua, "too long path: %s", path); - break; - } - - // parse path key and subkey - tb_char_t* pathkey = tb_null; - tb_char_t* pathsubkey = tb_null; - tb_char_t* p = pathbuf; - for (; *p && *p != '\\'; p++) ; - if (*p == '\\') - { - *p = '\0'; - pathkey = pathbuf; - pathsubkey = p + 1; - } - if (!pathkey || !pathsubkey) - { - lua_pushnil(lua); - lua_pushfstring(lua, "parse pathkey and pathsubkey failed: %s", path); - break; - } - - // parse value name - tb_char_t* valuename = tb_null; - for (p = pathbuf + size - 1; p >= pathbuf && *p && *p != ';'; p--) ; - if (p >= pathbuf && *p == ';') - { - valuename = p + 1; - *p = '\0'; - } - - // trace - tb_trace_d("key: %s, subkey: %s, name: %s", pathkey, pathsubkey, valuename? valuename : "(default)"); - - // get registry key - if (!tb_strcmp(pathkey, "HKEY_CLASSES_ROOT")) key = HKEY_CLASSES_ROOT; - else if (!tb_strcmp(pathkey, "HKEY_CURRENT_CONFIG")) key = HKEY_CURRENT_CONFIG; - else if (!tb_strcmp(pathkey, "HKEY_CURRENT_USER")) key = HKEY_CURRENT_USER; - else if (!tb_strcmp(pathkey, "HKEY_LOCAL_MACHINE")) key = HKEY_LOCAL_MACHINE; - else if (!tb_strcmp(pathkey, "HKEY_USERS")) key = HKEY_USERS; + // get registry rootkey + if (!tb_strcmp(rootkey, "HKEY_CLASSES_ROOT")) key = HKEY_CLASSES_ROOT; + else if (!tb_strcmp(rootkey, "HKEY_CURRENT_CONFIG")) key = HKEY_CURRENT_CONFIG; + else if (!tb_strcmp(rootkey, "HKEY_CURRENT_USER")) key = HKEY_CURRENT_USER; + else if (!tb_strcmp(rootkey, "HKEY_LOCAL_MACHINE")) key = HKEY_LOCAL_MACHINE; + else if (!tb_strcmp(rootkey, "HKEY_USERS")) key = HKEY_USERS; else { lua_pushnil(lua); - lua_pushfstring(lua, "invalid registry path: %s", path); + lua_pushfstring(lua, "invalid registry rootkey: %s", rootkey); break; } @@ -129,10 +91,10 @@ tb_int_t xm_winos_registry_query(lua_State* lua) { // get registry value size DWORD valuesize = 0; - if (s_RegGetValueA(key, pathsubkey, valuename, RRF_RT_ANY, 0, tb_null, &valuesize) != ERROR_SUCCESS) + if (s_RegGetValueA(key, rootdir, valuename, RRF_RT_ANY, 0, tb_null, &valuesize) != ERROR_SUCCESS) { lua_pushnil(lua); - lua_pushfstring(lua, "get registry value size failed: %s", path); + lua_pushfstring(lua, "get registry value size failed: %s\\%s;%s", rootkey, rootdir, valuename); break; } @@ -142,20 +104,20 @@ tb_int_t xm_winos_registry_query(lua_State* lua) // get value result type = 0; - if (s_RegGetValueA(key, pathsubkey, valuename, RRF_RT_ANY, &type, (PVOID)value, &valuesize) != ERROR_SUCCESS) + if (s_RegGetValueA(key, rootdir, valuename, RRF_RT_ANY, &type, (PVOID)value, &valuesize) != ERROR_SUCCESS) { lua_pushnil(lua); - lua_pushfstring(lua, "get registry value failed: %s", path); + lua_pushfstring(lua, "get registry value failed: %s\\%s;%s", rootkey, rootdir, valuename); break; } } else { // open registry key - if (RegOpenKeyExA(key, pathsubkey, 0, KEY_QUERY_VALUE, &keynew) != ERROR_SUCCESS && keynew) + if (RegOpenKeyExA(key, rootdir, 0, KEY_QUERY_VALUE, &keynew) != ERROR_SUCCESS && keynew) { lua_pushnil(lua); - lua_pushfstring(lua, "open registry key failed: %s", path); + lua_pushfstring(lua, "open registry key failed: %s\\%s", rootkey, rootdir); break; } @@ -164,7 +126,7 @@ tb_int_t xm_winos_registry_query(lua_State* lua) if (RegQueryValueExA(keynew, valuename, tb_null, tb_null, tb_null, &valuesize) != ERROR_SUCCESS) { lua_pushnil(lua); - lua_pushfstring(lua, "get registry value size failed: %s", path); + lua_pushfstring(lua, "get registry value size failed: %s\\%s;%s", rootkey, rootdir, valuename); break; } @@ -177,7 +139,7 @@ tb_int_t xm_winos_registry_query(lua_State* lua) if (RegQueryValueExA(keynew, valuename, tb_null, &type, (LPBYTE)value, &valuesize) != ERROR_SUCCESS) { lua_pushnil(lua); - lua_pushfstring(lua, "get registry value failed: %s", path); + lua_pushfstring(lua, "get registry value failed: %s\\%s;%s", rootkey, rootdir, valuename); break; } } @@ -207,9 +169,9 @@ tb_int_t xm_winos_registry_query(lua_State* lua) } while (0); // exit registry key - if (keynew != NULL) + if (keynew) RegCloseKey(keynew); - keynew = NULL; + keynew = tb_null; // exit value if (value) tb_free(value); diff --git a/core/src/xmake/winos/registry_values.c b/core/src/xmake/winos/registry_values.c new file mode 100644 index 000000000..17aefef6e --- /dev/null +++ b/core/src/xmake/winos/registry_values.c @@ -0,0 +1,162 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, TBOOX Open Source Group. + * + * @author ruki + * @file registry_values.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "registry_values" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +/* get registry values + * + * local count, errors = winos.registry_values("HKEY_LOCAL_MACHINE", + * "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", + * function (value_name) + * return true -- continue or break + * end) + */ +tb_int_t xm_winos_registry_values(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // get the arguments + tb_char_t const* rootkey = luaL_checkstring(lua, 1); + tb_char_t const* rootdir = luaL_checkstring(lua, 2); + tb_bool_t is_function = lua_isfunction(lua, 3); + tb_check_return_val(rootkey && rootdir && is_function, 0); + + // enum values + tb_bool_t ok = tb_false; + tb_int_t count = 0; + HKEY key = tb_null; + HKEY keynew = tb_null; + do + { + // get registry rootkey + if (!tb_strcmp(rootkey, "HKEY_CLASSES_ROOT")) key = HKEY_CLASSES_ROOT; + else if (!tb_strcmp(rootkey, "HKEY_CURRENT_CONFIG")) key = HKEY_CURRENT_CONFIG; + else if (!tb_strcmp(rootkey, "HKEY_CURRENT_USER")) key = HKEY_CURRENT_USER; + else if (!tb_strcmp(rootkey, "HKEY_LOCAL_MACHINE")) key = HKEY_LOCAL_MACHINE; + else if (!tb_strcmp(rootkey, "HKEY_USERS")) key = HKEY_USERS; + else + { + lua_pushnil(lua); + lua_pushfstring(lua, "invalid registry rootkey: %s", rootkey); + break; + } + + // open registry key + if (RegOpenKeyExA(key, rootdir, 0, KEY_QUERY_VALUE, &keynew) != ERROR_SUCCESS && keynew) + { + lua_pushnil(lua); + lua_pushfstring(lua, "open registry key failed: %s\\%s", rootkey, rootdir); + break; + } + + // query values + DWORD value_name_num = 0; + DWORD value_name_maxn = 0; + if (RegQueryInfoKeyW(keynew, tb_null, tb_null, tb_null, tb_null, tb_null, tb_null, &value_name_num, &value_name_maxn, tb_null, tb_null, tb_null) != ERROR_SUCCESS) + { + lua_pushnil(lua); + lua_pushfstring(lua, "query registry info failed: %s\\%s", rootkey, rootdir); + break; + } + value_name_maxn++; // add `\0` + + // ensure enough value name buffer + tb_wchar_t value_name[1024]; + if (value_name_maxn > tb_arrayn(value_name)) + { + lua_pushnil(lua); + lua_pushfstring(lua, "no enough value name buffer: %s\\%s", rootkey, rootdir); + break; + } + + // get all values + DWORD i = 0; + tb_char_t value_name_a[1024]; + for (i = 0; i < value_name_num; i++) + { + // get value name + value_name[0] = L'\0'; + DWORD value_name_size = tb_arrayn(value_name); + if (RegEnumValueW(keynew, i, value_name, &value_name_size, tb_null, tb_null, tb_null, tb_null) != ERROR_SUCCESS) + { + lua_pushnil(lua); + lua_pushfstring(lua, "get registry value name(%d) failed: %s\\%s", i, rootkey, rootdir); + break; + } + + // get value name (mbs) + tb_size_t value_name_a_size = tb_wtoa(value_name_a, value_name, sizeof(value_name_a)); + if (value_name_a_size == -1) + { + lua_pushnil(lua); + lua_pushfstring(lua, "convert registry value name(%d) failed: %s\\%s", i, rootkey, rootdir); + break; + } + + // do callback(value_name) + lua_pushvalue(lua, 3); + lua_pushlstring(lua, value_name_a, value_name_a_size); + lua_call(lua, 1, 1); + count++; + + // is continue? + tb_bool_t is_continue = lua_toboolean(lua, -1); + lua_pop(lua, 1); + if (!is_continue) + { + ok = tb_true; + break; + } + } + + // ok + if (i == value_name_num) + ok = tb_true; + + } while (0); + + // exit registry key + if (keynew) + RegCloseKey(keynew); + keynew = tb_null; + + // ok? + if (ok) + { + lua_pushinteger(lua, count); + return 1; + } + else return 2; +} diff --git a/xmake/core/base/winos.lua b/xmake/core/base/winos.lua index e50b79a92..d7cc081a9 100644 --- a/xmake/core/base/winos.lua +++ b/xmake/core/base/winos.lua @@ -23,10 +23,14 @@ local winos = winos or {} -- load modules local os = require("base/os") +local path = require("base/path") local semver = require("base/semver") -winos._ansi_cp = winos._ansi_cp or winos.ansi_cp -winos._oem_cp = winos._oem_cp or winos.oem_cp +winos._ansi_cp = winos._ansi_cp or winos.ansi_cp +winos._oem_cp = winos._oem_cp or winos.oem_cp +winos._registry_query = winos._registry_query or winos.registry_query +winos._registry_keys = winos._registry_keys or winos.registry_keys +winos._registry_values = winos._registry_values or winos.registry_values function winos.ansi_cp() if not winos._ANSI_CP then @@ -178,5 +182,162 @@ function winos.cmdargv(argv, key) return argv end +-- query registry value +-- +-- @param keypath the key path +-- @return the value and errors +-- +-- @code +-- local value, errors = winos.registry_query("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug") +-- local value, errors = winos.registry_query("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug;Debugger") +-- @endcode +-- +function winos.registry_query(keypath) + + -- get value name + local splitinfo = keypath:split(';', {plain = true}) + local valuename = splitinfo[2] or "(Default)" + keypath = splitinfo[1] + + -- get rootkey, e.g. HKEY_LOCAL_MACHINE + local rootkey + local p = keypath:find("\\", 1, true) + if p then + rootkey = keypath:sub(1, p - 1) + end + if not rootkey then + return nil, "root key not found!" + end + + -- get the root directory + local rootdir = keypath:sub(p + 1) + + -- query value + return winos._registry_query(rootkey, rootdir, valuename) +end + +-- get registry key paths +-- +-- @param keypath the key path (support key pattern, e.g. \\a\\b;xx*yy) +-- uses "*" to match any part of a key path, +-- uses "**" to recurse into subkey paths. +-- @return the result array and errors +-- +-- @code +-- local keys, errors = winos.registry_keys("HKEY_LOCAL_MACHINE\\SOFTWARE\\*\\Windows NT\\*\\CurrentVersion\\AeDebug") +-- local keys, errors = winos.registry_keys("HKEY_LOCAL_MACHINE\\SOFTWARE\\**") +-- @endcode +-- +function winos.registry_keys(keypath) + + -- get rootkey, e.g. HKEY_LOCAL_MACHINE + local rootkey + local p = keypath:find("\\", 1, true) + if p then + rootkey = keypath:sub(1, p - 1) + end + if not rootkey then + return + end + keypath = keypath:sub(p + 1) + + -- get the root directory + local pattern + local rootdir = keypath + p = rootdir:find("*", 1, true) + if p then + pattern = path.pattern(rootdir) + rootdir = path.directory(rootdir:sub(1, p - 1)) + end + + -- compute the recursion level + -- + -- infinite recursion: aaa\\** + -- limit recursion level: aaa\\*\\* + local recursion = 0 + if keypath:find("**", 1, true) then + recursion = -1 + else + -- "aaa\\*\\*" -> "*\\" -> recursion level: 1 + -- "aaa\\*\\xxx" -> "*\\" -> recursion level: 1 + -- "aaa\\*\\subkey\\xxx" -> "*\\\\" -> recursion level: 2 + if p then + local _, seps = keypath:sub(p):gsub("\\", "") + if seps > 0 then + recursion = seps + end + end + end + + -- get keys + local keys = {} + local count, errors = winos._registry_keys(rootkey, rootdir, recursion, function (key) + if not pattern or key:match("^" .. pattern .. "$") then + table.insert(keys, rootkey .. '\\' .. key) + if #keys > 4096 then + return false + end + end + return true + end) + if #keys > 4096 then + return nil, "too much registry keys: " .. keypath + end + if count ~= nil then + return keys + else + return nil, errors + end +end + +-- get registry values from the given key path +-- +-- @param keypath the key path (support value pattern, e.g. \\a\\b;xx*yy) +-- uses "*" to match value name, +-- @return the values array and errors +-- +-- @code +-- local values, errors = winos.registry_values("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug") +-- local values, errors = winos.registry_values("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug;Debug*") +-- @endcode +-- +function winos.registry_values(keypath) + + -- get value pattern + local splitinfo = keypath:split(';', {plain = true}) + local pattern = splitinfo[2] + if pattern then + pattern = path.pattern(pattern) + end + keypath = splitinfo[1] + + -- get rootkey, e.g. HKEY_LOCAL_MACHINE + local rootkey + local p = keypath:find("\\", 1, true) + if p then + rootkey = keypath:sub(1, p - 1) + end + if not rootkey then + return nil, "root key not found!" + end + + -- get the root directory + local rootdir = keypath:sub(p + 1) + + -- get value names + local value_names = {} + local count, errors = winos._registry_values(rootkey, rootdir, function (value_name) + if not pattern or value_name:match("^" .. pattern .. "$") then + table.insert(value_names, value_name) + end + return true + end) + if count ~= nil then + return value_names + else + return nil, errors + end +end + -- return module: winos return winos diff --git a/xmake/core/sandbox/modules/interpreter/winos.lua b/xmake/core/sandbox/modules/interpreter/winos.lua index 6787d9a3f..2a470c7fd 100644 --- a/xmake/core/sandbox/modules/interpreter/winos.lua +++ b/xmake/core/sandbox/modules/interpreter/winos.lua @@ -25,9 +25,11 @@ local winos = require("base/winos") local sandbox_winos = sandbox_winos or {} -- export some readonly interfaces -sandbox_winos.registry_query = winos.registry_query -sandbox_winos.logical_drives = winos.logical_drives -sandbox_winos.version = winos.version +sandbox_winos.registry_query = winos.registry_query +sandbox_winos.registry_keys = winos.registry_keys +sandbox_winos.registry_values = winos.registry_values +sandbox_winos.logical_drives = winos.logical_drives +sandbox_winos.version = winos.version -- return module return sandbox_winos diff --git a/xmake/core/sandbox/modules/winos.lua b/xmake/core/sandbox/modules/winos.lua index 1726897f8..0a0192470 100644 --- a/xmake/core/sandbox/modules/winos.lua +++ b/xmake/core/sandbox/modules/winos.lua @@ -31,7 +31,6 @@ sandbox_winos.ansi_cp = winos.ansi_cp sandbox_winos.cp_info = winos.cp_info sandbox_winos.console_cp = winos.console_cp sandbox_winos.console_output_cp = winos.console_output_cp -sandbox_winos.registry_query = winos.registry_query sandbox_winos.logical_drives = winos.logical_drives sandbox_winos.cmdargv = winos.cmdargv @@ -44,6 +43,33 @@ function sandbox_winos.version() return winver end +-- query registry value +function sandbox_winos.registry_query(keypath) + local value, errors = winos.registry_query(keypath) + if not value then + raise(errors) + end + return value +end + +-- get registry keys +function sandbox_winos.registry_keys(keypath) + local keys, errors = winos.registry_keys(keypath) + if not keys then + raise(errors) + end + return keys +end + +-- get registry values +function sandbox_winos.registry_values(keypath) + local values, errors = winos.registry_values(keypath) + if not values then + raise(errors) + end + return values +end + -- return module return sandbox_winos |
