/*!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, Xmake Open Source Community. * * @author TitanSnow, ruki * @file registry_query.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "registry_query" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * types */ // the RegGetValueW func type typedef BOOL(WINAPI *xm_RegGetValueW_t)( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpValue, DWORD dwFlags, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData); /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* query registry * * 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) { 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_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 = tb_null; HKEY keynew = tb_null; tb_char_t *value = tb_null; tb_wchar_t *value_w = tb_null; tb_size_t value_n = (tb_size_t)-1; do { // get registry rootkey if (!tb_strcmp(rootkey, "HKEY_CLASSES_ROOT")) { key = HKEY_CLASSES_ROOT; } else if (!tb_strcmp(rootkey, "HKCR")) { key = HKEY_CLASSES_ROOT; } else if (!tb_strcmp(rootkey, "HKEY_CURRENT_CONFIG")) { key = HKEY_CURRENT_CONFIG; } else if (!tb_strcmp(rootkey, "HKCC")) { key = HKEY_CURRENT_CONFIG; } else if (!tb_strcmp(rootkey, "HKEY_CURRENT_USER")) { key = HKEY_CURRENT_USER; } else if (!tb_strcmp(rootkey, "HKCU")) { key = HKEY_CURRENT_USER; } else if (!tb_strcmp(rootkey, "HKEY_LOCAL_MACHINE")) { key = HKEY_LOCAL_MACHINE; } else if (!tb_strcmp(rootkey, "HKLM")) { 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; } // convert rootdir to wide characters tb_wchar_t rootdir_w[TB_PATH_MAXN]; if (tb_atow(rootdir_w, rootdir, TB_PATH_MAXN) == (tb_size_t)-1) { lua_pushnil(lua); lua_pushfstring(lua, "invalid registry rootkey:: %s", rootdir); break; } // convert valuename to wide characters tb_wchar_t valuename_w[TB_PATH_MAXN]; if (tb_atow(valuename_w, valuename, TB_PATH_MAXN) == (tb_size_t)-1) { lua_pushnil(lua); lua_pushfstring(lua, "invalid registry valuename: %s", valuename); break; } // attempt to load RegGetValueW static xm_RegGetValueW_t s_RegGetValueW = tb_null; if (!s_RegGetValueW) { // load the advapi32 module tb_dynamic_ref_t module = (tb_dynamic_ref_t)GetModuleHandleA("advapi32.dll"); if (!module) module = tb_dynamic_init("advapi32.dll"); if (module) s_RegGetValueW = (xm_RegGetValueW_t)tb_dynamic_func(module, "RegGetValueW"); } // get registry value DWORD type = 0; if (s_RegGetValueW) { // get registry value size DWORD valuesize_w = 0; if (s_RegGetValueW(key, rootdir_w, valuename_w, RRF_RT_ANY, 0, tb_null, &valuesize_w) != ERROR_SUCCESS) { lua_pushnil(lua); lua_pushfstring(lua, "get registry value size failed: %s\\%s;%s", rootkey, rootdir, valuename); break; } // make value buffer DWORD valuesize = valuesize_w * 2; value = (tb_char_t *)tb_malloc0(valuesize); tb_assert_and_check_break(value); value_w = (tb_wchar_t *)tb_malloc0(valuesize_w); tb_assert_and_check_break(value_w); // get value result, we attempt to do not expand value if get failed type = 0; if (s_RegGetValueW(key, rootdir_w, valuename_w, RRF_RT_ANY, &type, (PVOID)value_w, &valuesize_w) != ERROR_SUCCESS && s_RegGetValueW( key, rootdir_w, valuename_w, RRF_RT_ANY | RRF_NOEXPAND, &type, (PVOID)value_w, &valuesize_w) != ERROR_SUCCESS) { lua_pushnil(lua); lua_pushfstring(lua, "get registry value failed: %s\\%s;%s", rootkey, rootdir, valuename); break; } value_n = tb_wtoa(value, value_w, valuesize); if (value_n == (tb_size_t)-1) { lua_pushnil(lua); lua_pushfstring(lua, "wtoa registry value failed: %s\\%s;%s", rootkey, rootdir, valuename); break; } } else { // open registry key if (RegOpenKeyExW(key, rootdir_w, 0, KEY_QUERY_VALUE, &keynew) != ERROR_SUCCESS && keynew) { lua_pushnil(lua); lua_pushfstring(lua, "open registry key failed: %s\\%s", rootkey, rootdir); break; } // get registry value size DWORD valuesize_w = 0; if (RegQueryValueExW(keynew, valuename_w, tb_null, tb_null, tb_null, &valuesize_w) != ERROR_SUCCESS) { lua_pushnil(lua); lua_pushfstring(lua, "get registry value size failed: %s\\%s;%s", rootkey, rootdir, valuename); break; } // make value buffer DWORD valuesize = valuesize_w * 2; value = (tb_char_t *)tb_malloc0(valuesize); tb_assert_and_check_break(value); value_w = (tb_wchar_t *)tb_malloc0(valuesize_w); tb_assert_and_check_break(value_w); // get value result type = 0; if (RegQueryValueExW(keynew, valuename_w, tb_null, &type, (LPBYTE)value_w, &valuesize_w) != ERROR_SUCCESS) { lua_pushnil(lua); lua_pushfstring(lua, "get registry value failed: %s\\%s;%s", rootkey, rootdir, valuename); break; } value_n = tb_wtoa(value, value_w, valuesize); if (value_n == (tb_size_t)-1) { lua_pushnil(lua); lua_pushfstring(lua, "wtoa registry value failed: %s\\%s;%s", rootkey, rootdir, valuename); break; } } // save result switch (type) { case REG_SZ: case REG_EXPAND_SZ: lua_pushlstring(lua, value, value_n); ok = tb_true; break; case REG_DWORD: lua_pushfstring(lua, "%d", *((tb_int_t *)value)); ok = tb_true; break; case REG_QWORD: lua_pushfstring(lua, "%lld", *((tb_int64_t *)value)); ok = tb_true; break; default: lua_pushnil(lua); lua_pushfstring(lua, "unsupported registry value type: %d", type); break; } } while (0); // exit registry key if (keynew) { RegCloseKey(keynew); } keynew = tb_null; // exit value if (value) { tb_free(value); } value = tb_null; if (value_w) { tb_free(value_w); } value_w = tb_null; return ok ? 1 : 2; }