summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2020-12-26 19:19:31 +0800
committerGitHub <[email protected]>2020-12-26 19:19:31 +0800
commit3f12aa4188f26396a0883ebd4ba0738a9f1dcefa (patch)
treee300f3364cd7f3c1ed95e55bac5c7ed9c7760f58
parent0f8cac544eaf61ecb2fde78cc2fed7f40c04cb92 (diff)
parent55e63db24d799dc3f15c7536ee776d2fb5723a74 (diff)
Merge pull request #1162 from xmake-io/registry
improve registry
-rw-r--r--CHANGELOG.md2
m---------core/src/tbox/tbox0
-rw-r--r--core/src/xmake/engine.c4
-rw-r--r--core/src/xmake/makefile2
-rw-r--r--core/src/xmake/winos/registry_keys.c231
-rw-r--r--core/src/xmake/winos/registry_query.c88
-rw-r--r--core/src/xmake/winos/registry_values.c162
-rw-r--r--xmake/core/base/winos.lua165
-rw-r--r--xmake/core/sandbox/modules/interpreter/winos.lua8
-rw-r--r--xmake/core/sandbox/modules/winos.lua28
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