From c3fe31a3bf32c59a6f72fef3fc31e745b70539af Mon Sep 17 00:00:00 2001 From: taynpg Date: Thu, 26 Feb 2026 09:45:25 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B3=A8=E5=86=8CWindwosTerm?= =?UTF-8?q?inal=E5=8F=B3=E9=94=AE=E8=8F=9C=E5=8D=95=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .clang-format | 20 +++ .clangd | 12 ++ .gitignore | 39 +---- .vscode/settings.json | 147 +++++++++++++++++ CMakeLists.txt | 12 ++ README.md | 6 +- wt_reg/CMakeLists.txt | 5 + wt_reg/main.cpp | 370 ++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 576 insertions(+), 35 deletions(-) create mode 100644 .clang-format create mode 100644 .clangd create mode 100644 .vscode/settings.json create mode 100644 CMakeLists.txt create mode 100644 wt_reg/CMakeLists.txt create mode 100644 wt_reg/main.cpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..8d63d3f --- /dev/null +++ b/.clang-format @@ -0,0 +1,20 @@ +BasedOnStyle: LLVM +IndentWidth: 4 +PointerAlignment: Left +AccessModifierOffset: -4 +ReflowComments: true +SpacesBeforeTrailingComments: 3 +AllowShortFunctionsOnASingleLine: None +AllowShortEnumsOnASingleLine: false +BreakBeforeBraces: Custom +BraceWrapping: + AfterFunction: true + AfterClass: true +TabWidth: 4 +ColumnLimit: 130 +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^<.*>' + Priority: 1 + - Regex: '^".*"' + Priority: 2 diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..40557fb --- /dev/null +++ b/.clangd @@ -0,0 +1,12 @@ +Hover: + ShowAKA: Yes +Diagnostics: + UnusedIncludes: None # 禁用未使用头文件提示 + Suppress: [ + anon_type_definition, # 禁用匿名的typedef提示 + unused-variable, # 禁用未使用变量提示 + unused-function, # 禁用未使用函数提示 + unused-includes, + ] + ClangTidy: + Remove: misc-unused-alias-decls diff --git a/.gitignore b/.gitignore index e257658..fe107f6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,34 +1,5 @@ -# ---> C++ -# Prerequisites -*.d - -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app - +build/ +.cache/ +.qtcreator/ +.vs +out/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d5551fa --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,147 @@ +{ + "files.autoSave": "onFocusChange", + "editor.fontSize": 14, + "editor.fontFamily": "'Maple Mono NL NF CN Light', 'Maple Mono NL NF CN Light', 'Maple Mono NL NF CN Light'", + "editor.wordWrap": "on", + "terminal.integrated.fontFamily": "'Maple Mono NL NF CN Light'", + "cmake.configureOnOpen": true, + //"C_Cpp.intelliSenseEngine": "disabled", + "cmake.debugConfig": { + "console": "externalTerminal", + "setupCommands": [ + { + "description": "-gdb-set charset utf-8", + "text": "-gdb-set charset UTF-8" + }, + { + "description": "Enable gdb pretty-printing", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + //"visualizerFile": "${workspaceRoot}/.vscode/qt6.natvis", + "args": [ + "uninstall" + ] + }, + "cmake.configureArgs": [ + "-Wno-dev" + ], + // "cmake.configureSettings": { + // "CMAKE_TOOLCHAIN_FILE": "${env:VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" + // }, + "cmake.options.statusBarVisibility": "visible", + "cmake.generator": "Ninja", + "C_Cpp.default.compileCommands": "${workspaceRoot}/build/compile_commands.json", + "C_Cpp.default.cppStandard": "c++17", + "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", + "editor.inlayHints.enabled": "off", + "editor.unicodeHighlight.allowedLocales": { + "ja": true, + "zh-hant": true, + "zh-hans": true + }, + "files.associations": { + "*.cfg": "json", + "xstring": "cpp", + "algorithm": "cpp", + "array": "cpp", + "atomic": "cpp", + "cctype": "cpp", + "charconv": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "condition_variable": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "exception": "cpp", + "filesystem": "cpp", + "forward_list": "cpp", + "fstream": "cpp", + "functional": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "iterator": "cpp", + "limits": "cpp", + "list": "cpp", + "locale": "cpp", + "map": "cpp", + "memory": "cpp", + "mutex": "cpp", + "new": "cpp", + "optional": "cpp", + "ostream": "cpp", + "ratio": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "thread": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeinfo": "cpp", + "unordered_map": "cpp", + "utility": "cpp", + "vector": "cpp", + "xfacet": "cpp", + "xhash": "cpp", + "xiosbase": "cpp", + "xlocale": "cpp", + "xlocbuf": "cpp", + "xlocinfo": "cpp", + "xlocmes": "cpp", + "xlocmon": "cpp", + "xlocnum": "cpp", + "xloctime": "cpp", + "xmemory": "cpp", + "xmemory0": "cpp", + "xstddef": "cpp", + "xtr1common": "cpp", + "xtree": "cpp", + "xutility": "cpp", + "bit": "cpp", + "compare": "cpp", + "concepts": "cpp", + "coroutine": "cpp", + "format": "cpp", + "stop_token": "cpp", + "bitset": "cpp", + "complex": "cpp", + "cstdarg": "cpp", + "set": "cpp", + "variant": "cpp", + "expected": "cpp", + "source_location": "cpp", + "regex": "cpp", + "*.in": "cpp", + "deque": "cpp", + "future": "cpp", + "queue": "cpp", + "resumable": "cpp", + "any": "cpp", + "codecvt": "cpp", + "csignal": "cpp", + "cwctype": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "random": "cpp", + "shared_mutex": "cpp", + "cinttypes": "cpp", + "cfenv": "cpp", + "unordered_set": "cpp", + "ranges": "cpp", + "typeindex": "cpp" + } +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..7ab627a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.16) + +project(sim_tool LANGUAGES CXX) +set(CMAKE_CXX_STANDARD 17) + +set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib/${CMAKE_BUILD_TYPE}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin/${CMAKE_BUILD_TYPE}) + +if (MSVC) + add_compile_options(/utf-8) + add_subdirectory(wt_reg) +endif() diff --git a/README.md b/README.md index 18d86b9..e0e47e3 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ # sim_tool -简易工具。 \ No newline at end of file +简易工具。 + +## wt_reg + +注册Windows Terminal右键菜单的工具。 \ No newline at end of file diff --git a/wt_reg/CMakeLists.txt b/wt_reg/CMakeLists.txt new file mode 100644 index 0000000..c45a797 --- /dev/null +++ b/wt_reg/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.16) + +project(wt_reg LANGUAGES CXX) + +add_executable(wt_reg main.cpp) \ No newline at end of file diff --git a/wt_reg/main.cpp b/wt_reg/main.cpp new file mode 100644 index 0000000..e2d4341 --- /dev/null +++ b/wt_reg/main.cpp @@ -0,0 +1,370 @@ +/* + 在包含任何 Windows 头文件之前定义宏 WIN32_LEAN_AND_MEAN +*/ +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include +#include + +#ifndef WHAT_FUCK +#include // 需要在 windows.h 之后包含 +#endif + +namespace fs = std::filesystem; + +class RegistryManager +{ +private: + std::string wtPath; + + bool checkWtExists() + { + if (fs::exists(wtPath) && fs::path(wtPath).filename() == "wt.exe") { + std::cout << "找到 wt.exe: " << wtPath << std::endl; + return true; + } else { + std::cout << "错误: wt.exe 不存在或路径无效: " << wtPath << std::endl; + return false; + } + } + + bool isAdmin() + { + BOOL isAdmin = FALSE; + PSID adminGroup = NULL; + SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY; + + if (AllocateAndInitializeSid(&ntAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, + &adminGroup)) { + if (!CheckTokenMembership(NULL, adminGroup, &isAdmin)) { + isAdmin = FALSE; + } + FreeSid(adminGroup); + } + + return isAdmin != FALSE; + } + + // 创建注册表键并设置值 + bool createRegistryKeyWithValue(const std::string& keyPath, const std::string& valueName, const std::string& valueData) + { + HKEY hKey; + + std::cout << "创建注册表键: " << keyPath << std::endl; + if (!valueName.empty()) { + std::cout << "设置值: " << valueName << " = " << valueData << std::endl; + } else { + std::cout << "设置默认值: " << valueData << std::endl; + } + + LONG result = + RegCreateKeyEx(HKEY_CLASSES_ROOT, keyPath.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL); + + if (result != ERROR_SUCCESS) { + std::cout << "创建注册表键失败: " << keyPath << " 错误码: " << result << std::endl; + return false; + } + + if (!valueName.empty() || valueData.length() > 0) { + result = RegSetValueEx(hKey, valueName.c_str(), 0, REG_SZ, (const BYTE*)valueData.c_str(), + static_cast(valueData.length() + 1)); + + if (result != ERROR_SUCCESS) { + std::cout << "设置注册表值失败: " << valueName << " 错误码: " << result << std::endl; + RegCloseKey(hKey); + return false; + } + } + + RegCloseKey(hKey); + return true; + } + + // 创建注册表键(不设置值) + bool createRegistryKey(const std::string& keyPath) + { + HKEY hKey; + + std::cout << "创建注册表键: " << keyPath << std::endl; + + LONG result = + RegCreateKeyEx(HKEY_CLASSES_ROOT, keyPath.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL); + + if (result != ERROR_SUCCESS) { + std::cout << "创建注册表键失败: " << keyPath << " 错误码: " << result << std::endl; + return false; + } + + RegCloseKey(hKey); + return true; + } + + // 递归删除注册表键及其所有子键 + bool deleteRegistryKeyRecursive(HKEY hRoot, const std::string& subKey) + { + HKEY hKey; + + // 尝试打开键 + LONG result = RegOpenKeyEx(hRoot, subKey.c_str(), 0, KEY_READ | KEY_WRITE, &hKey); + + if (result != ERROR_SUCCESS) { + if (result == ERROR_FILE_NOT_FOUND) { + // 键不存在,视为成功删除 + return true; + } + std::cout << "打开注册表键失败: " << subKey << " 错误码: " << result << std::endl; + return false; + } + + // 递归删除所有子键 + DWORD subKeyCount = 0; + DWORD maxSubKeyLen = 0; + + result = RegQueryInfoKey(hKey, NULL, NULL, NULL, &subKeyCount, &maxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL); + + if (result == ERROR_SUCCESS && subKeyCount > 0) { + std::vector subKeyName(maxSubKeyLen + 2, 0); // +2 保证有足够空间 + + for (DWORD i = 0; i < subKeyCount; i++) { + DWORD nameLen = maxSubKeyLen + 1; + result = RegEnumKeyEx(hKey, + 0, // 总是删除第一个子键 + &subKeyName[0], &nameLen, NULL, NULL, NULL, NULL); + + if (result == ERROR_SUCCESS) { + std::string childPath = subKey + "\\" + std::string(&subKeyName[0]); + if (!deleteRegistryKeyRecursive(hRoot, childPath)) { + RegCloseKey(hKey); + return false; + } + } else { + RegCloseKey(hKey); + std::cout << "枚举子键失败: " << subKey << " 错误码: " << result << std::endl; + return false; + } + } + } + + RegCloseKey(hKey); + + // 删除当前键 + result = RegDeleteKey(hRoot, subKey.c_str()); + if (result != ERROR_SUCCESS) { + std::cout << "删除注册表键失败: " << subKey << " 错误码: " << result << std::endl; + return false; + } + + return true; + } + + bool deleteRegistryKey(const std::string& keyPath) + { + return deleteRegistryKeyRecursive(HKEY_CLASSES_ROOT, keyPath); + } + + bool installContextMenu() + { + std::cout << "安装 Windows Terminal 右键菜单..." << std::endl; + + bool success = true; + + // 1. 创建背景右键菜单项 + std::cout << "\n=== 安装背景右键菜单 ===" << std::endl; + + // 1.1 创建 wt 键 + if (!createRegistryKey("Directory\\Background\\shell\\wt")) { + std::cout << "创建背景菜单键失败" << std::endl; + success = false; + } + + // 1.2 设置默认值 + if (!createRegistryKeyWithValue("Directory\\Background\\shell\\wt", "", "Terminal")) { + std::cout << "设置背景菜单名称失败" << std::endl; + success = false; + } + + // 1.3 设置图标 + if (!createRegistryKeyWithValue("Directory\\Background\\shell\\wt", "Icon", "\"" + wtPath + "\"")) { + std::cout << "设置背景菜单图标失败" << std::endl; + success = false; + } + + // 1.4 创建 command 子键 + if (!createRegistryKey("Directory\\Background\\shell\\wt\\command")) { + std::cout << "创建背景命令键失败" << std::endl; + success = false; + } + + // 1.5 设置命令 + if (!createRegistryKeyWithValue("Directory\\Background\\shell\\wt\\command", "", "\"" + wtPath + "\"")) { + std::cout << "设置背景命令失败" << std::endl; + success = false; + } + + // 2. 创建目录右键菜单项 + std::cout << "\n=== 安装目录右键菜单 ===" << std::endl; + + // 2.1 创建 wt 键 + if (!createRegistryKey("Directory\\shell\\wt")) { + std::cout << "创建目录菜单键失败" << std::endl; + success = false; + } + + // 2.2 设置默认值 + if (!createRegistryKeyWithValue("Directory\\shell\\wt", "", "Terminal")) { + std::cout << "设置目录菜单名称失败" << std::endl; + success = false; + } + + // 2.3 设置图标 + if (!createRegistryKeyWithValue("Directory\\shell\\wt", "Icon", "\"" + wtPath + "\"")) { + std::cout << "设置目录菜单图标失败" << std::endl; + success = false; + } + + // 2.4 创建 command 子键 + if (!createRegistryKey("Directory\\shell\\wt\\command")) { + std::cout << "创建目录命令键失败" << std::endl; + success = false; + } + + // 2.5 设置命令 - 注意:这里需要转义双引号 + std::string command = "\"" + wtPath + "\" -d \"%V\""; + if (!createRegistryKeyWithValue("Directory\\shell\\wt\\command", "", command)) { + std::cout << "设置目录命令失败" << std::endl; + success = false; + } + + return success; + } + + bool uninstallContextMenu() + { + std::cout << "卸载 Windows Terminal 右键菜单..." << std::endl; + + bool success = true; + + // 删除背景右键菜单项 + if (!deleteRegistryKey("Directory\\Background\\shell\\wt")) { + std::cout << "警告: Directory\\Background\\shell\\wt 删除失败,可能不存在或已删除" << std::endl; + } + + // 删除目录右键菜单项 + if (!deleteRegistryKey("Directory\\shell\\wt")) { + std::cout << "警告: Directory\\shell\\wt 删除失败,可能不存在或已删除" << std::endl; + } + + return success; + } + + void refreshExplorer() + { + // 发送消息刷新资源管理器 + SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, + (LPARAM) "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", SMTO_ABORTIFHUNG, 1000, + NULL); + + // 通知资源管理器更新 + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); + } + +public: + RegistryManager(const std::string& path) : wtPath(path) + { + // 规范化路径(统一使用反斜杠) + std::replace(wtPath.begin(), wtPath.end(), '/', '\\'); + } + + bool install() + { + if (!checkWtExists()) { + return false; + } + + if (!isAdmin()) { + std::cout << "需要管理员权限来修改注册表" << std::endl; + std::cout << "请以管理员身份重新运行此程序" << std::endl; + return false; + } + + bool success = installContextMenu(); + if (success) { + refreshExplorer(); + std::cout << "\n安装成功!" << std::endl; + } else { + std::cout << "\n安装失败!" << std::endl; + } + + return success; + } + + bool uninstall() + { + if (!isAdmin()) { + std::cout << "需要管理员权限来修改注册表" << std::endl; + std::cout << "请以管理员身份重新运行此程序" << std::endl; + return false; + } + + bool success = uninstallContextMenu(); + if (success) { + refreshExplorer(); + std::cout << "卸载成功!" << std::endl; + } else { + std::cout << "卸载失败!" << std::endl; + } + + return success; + } +}; + +void printUsage(const char* programName) +{ + std::cout << "Windows Terminal 右键菜单管理工具" << std::endl; + std::cout << "用法:" << std::endl; + std::cout << " " << programName << " install " << std::endl; + std::cout << " " << programName << " uninstall" << std::endl; + std::cout << std::endl; + std::cout << "示例:" << std::endl; + std::cout << " " << programName << " install \"D:\\Program\\terminal\\wt.exe\"" << std::endl; + std::cout << " " << programName << " uninstall" << std::endl; +} + +int main(int argc, char* argv[]) +{ + // 设置控制台输出为UTF-8 + SetConsoleOutputCP(CP_UTF8); + + if (argc < 2) { + printUsage(argv[0]); + return 1; + } + + std::string action = argv[1]; + + if (action == "install") { + if (argc < 3) { + std::cout << "错误: 需要指定 wt.exe 的路径" << std::endl; + printUsage(argv[0]); + return 1; + } + + std::string wtPath = argv[2]; + RegistryManager manager(wtPath); + + return manager.install() ? 0 : 1; + } else if (action == "uninstall") { + std::string dummyPath = "C:\\Windows\\System32\\cmd.exe"; + RegistryManager manager(dummyPath); + + return manager.uninstall() ? 0 : 1; + } else { + std::cout << "错误: 未知的操作: " << action << std::endl; + printUsage(argv[0]); + return 1; + } +} \ No newline at end of file