From 64e231d5cb0320e7fd9f3863fbd31f21c19620a1 Mon Sep 17 00:00:00 2001 From: fofolee Date: Tue, 14 Jan 2025 16:24:12 +0800 Subject: [PATCH] =?UTF-8?q?win=E8=87=AA=E5=8A=A8=E5=8C=96=E5=88=86?= =?UTF-8?q?=E7=B1=BB=E6=B7=BB=E5=8A=A0=E8=BF=9B=E7=A8=8B=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E3=80=81=E6=B3=A8=E5=86=8C=E8=A1=A8=E7=AE=A1=E7=90=86=E3=80=81?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=AE=A1=E7=90=86=E3=80=81=E8=BD=AF=E4=BB=B6?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=92=8C=E7=B3=BB=E7=BB=9F=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/lib/csharp/process.cs | 281 +++++++++ plugin/lib/csharp/registry.cs | 357 ++++++++++++ plugin/lib/csharp/service.cs | 233 ++++++++ plugin/lib/csharp/software.cs | 352 +++++++++++ plugin/lib/csharp/utils.cs | 407 +++++++++++++ plugin/lib/quickcomposer/windows/index.js | 10 + plugin/lib/quickcomposer/windows/process.js | 57 ++ plugin/lib/quickcomposer/windows/registry.js | 96 +++ plugin/lib/quickcomposer/windows/service.js | 39 ++ plugin/lib/quickcomposer/windows/software.js | 38 ++ plugin/lib/quickcomposer/windows/utils.js | 146 +++++ src/js/composer/commands/windowsCommands.js | 577 +++++++++++++++++++ 12 files changed, 2593 insertions(+) create mode 100644 plugin/lib/csharp/process.cs create mode 100644 plugin/lib/csharp/registry.cs create mode 100644 plugin/lib/csharp/service.cs create mode 100644 plugin/lib/csharp/software.cs create mode 100644 plugin/lib/csharp/utils.cs create mode 100644 plugin/lib/quickcomposer/windows/process.js create mode 100644 plugin/lib/quickcomposer/windows/registry.js create mode 100644 plugin/lib/quickcomposer/windows/service.js create mode 100644 plugin/lib/quickcomposer/windows/software.js create mode 100644 plugin/lib/quickcomposer/windows/utils.js diff --git a/plugin/lib/csharp/process.cs b/plugin/lib/csharp/process.cs new file mode 100644 index 0000000..32bad45 --- /dev/null +++ b/plugin/lib/csharp/process.cs @@ -0,0 +1,281 @@ +using System; +using System.Diagnostics; +using System.Text; +using System.Runtime.InteropServices; +using System.Collections.Generic; +using System.IO; + +public class ProcessManager +{ + [DllImport("kernel32.dll")] + private static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId); + + [DllImport("kernel32.dll")] + private static extern bool CloseHandle(IntPtr hObject); + + [DllImport("kernel32.dll")] + private static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode); + + private const uint PROCESS_TERMINATE = 0x0001; + private const uint PROCESS_QUERY_INFORMATION = 0x0400; + + public static void Main(string[] args) + { + if (args.Length == 0 || args[0] == "-h" || args[0] == "--help") + { + ShowHelp(); + return; + } + + string type = GetArgumentValue(args, "-type"); + if (string.IsNullOrEmpty(type)) + { + Console.Error.WriteLine("Error: 必须指定操作类型 (-type)"); + return; + } + + try + { + switch (type.ToLower()) + { + case "list": + ListProcesses(); + break; + case "kill": + string target = GetArgumentValue(args, "-target"); + if (string.IsNullOrEmpty(target)) + { + Console.Error.WriteLine("Error: 必须指定目标进程 (-target)"); + return; + } + KillProcess(target); + break; + case "start": + string path = GetArgumentValue(args, "-path"); + string arguments = GetArgumentValue(args, "-args"); + if (arguments == null) + { + arguments = ""; + } + StartProcess(path, arguments); + break; + default: + Console.Error.WriteLine("Error: 不支持的操作类型"); + break; + } + } + catch (Exception ex) + { + Console.Error.WriteLine(string.Format("Error: {0}", ex.Message)); + } + } + + private static void ListProcesses() + { + Console.Write("["); + Process[] processes = Process.GetProcesses(); + bool first = true; + foreach (Process proc in processes) + { + try + { + string processPath = ""; + DateTime startTime = DateTime.MinValue; + TimeSpan cpuTime = TimeSpan.Zero; + long memorySize = 0; + int threadCount = 0; + ProcessPriorityClass priority = ProcessPriorityClass.Normal; + string description = ""; + string company = ""; + string version = ""; + + try + { + if (proc.MainModule != null) + { + processPath = proc.MainModule.FileName; + } + else + { + processPath = ""; + } + startTime = proc.StartTime; + cpuTime = proc.TotalProcessorTime; + memorySize = proc.WorkingSet64; + threadCount = proc.Threads.Count; + priority = proc.PriorityClass; + + // 获取文件版本信息 + if (!string.IsNullOrEmpty(processPath) && File.Exists(processPath)) + { + var versionInfo = FileVersionInfo.GetVersionInfo(processPath); + description = versionInfo.FileDescription; + if (description == null) description = ""; + company = versionInfo.CompanyName; + if (company == null) company = ""; + version = versionInfo.FileVersion; + if (version == null) version = ""; + } + } + catch { } + + if (!first) + { + Console.Write(","); + } + first = false; + + Console.Write(string.Format( + "{{" + + "\"id\": {0}," + + "\"name\": \"{1}\"," + + "\"title\": \"{2}\"," + + "\"path\": \"{3}\"," + + "\"startTime\": \"{4}\"," + + "\"cpuTime\": \"{5}\"," + + "\"memory\": {6}," + + "\"threads\": {7}," + + "\"priority\": \"{8}\"," + + "\"description\": \"{9}\"," + + "\"company\": \"{10}\"," + + "\"version\": \"{11}\"" + + "}}", + proc.Id, + proc.ProcessName, + proc.MainWindowTitle.Replace("\"", "\\\""), + processPath.Replace("\\", "\\\\").Replace("\"", "\\\""), + startTime.ToString("yyyy-MM-dd HH:mm:ss"), + cpuTime.ToString(), + memorySize, + threadCount, + priority.ToString(), + description.Replace("\"", "\\\""), + company.Replace("\"", "\\\""), + version.Replace("\"", "\\\"") + )); + } + catch { } + } + Console.Write("]"); + } + + private static void KillProcess(string target) + { + int pid; + if (int.TryParse(target, out pid)) + { + KillProcessById(pid); + } + else + { + KillProcessByName(target); + } + } + + private static void KillProcessById(int pid) + { + Process proc = Process.GetProcessById(pid); + try + { + proc.Kill(); + Console.WriteLine(string.Format("成功终止进程: {0} (PID: {1})", proc.ProcessName, pid)); + } + catch (Exception ex) + { + throw new Exception(string.Format("无法终止进程: {0}", ex.Message)); + } + } + + private static void KillProcessByName(string name) + { + Process[] processes = Process.GetProcessesByName(name); + if (processes.Length == 0) + { + throw new Exception("找不到指定的进程"); + } + + foreach (Process proc in processes) + { + try + { + proc.Kill(); + Console.WriteLine(string.Format("成功终止进程: {0} (PID: {1})", name, proc.Id)); + } + catch (Exception ex) + { + Console.Error.WriteLine(string.Format("无法终止进程: {0} (PID: {1}) - {2}", + name, proc.Id, ex.Message)); + } + } + } + + private static void StartProcess(string path, string args) + { + ProcessStartInfo startInfo = new ProcessStartInfo + { + FileName = path, + Arguments = args, + UseShellExecute = true + }; + + Process proc = Process.Start(startInfo); + Console.WriteLine(string.Format("已启动进程: {0} (PID: {1})", path, proc.Id)); + } + + private static void ShowHelp() + { + string help = @" +进程管理工具使用说明 +================ + +基本语法: +process.exe -type <操作类型> [参数...] + +操作类型: +-------- +1. list - 列出所有进程 + 示例: process.exe -type list + +2. kill - 终止进程 + 参数: + -target 要终止的进程ID或名称 + 示例: + process.exe -type kill -target notepad + process.exe -type kill -target 1234 + +3. start - 启动进程 + 参数: + -path <程序路径> 要启动的程序路径 + -args <参数> 启动参数(可选) + 示例: + process.exe -type start -path ""c:\windows\notepad.exe"" + process.exe -type start -path ""c:\program.exe"" -args ""-param value"" + +返回值: +------ +list操作返回JSON格式的进程信息: +{""id"": 进程ID, ""name"": ""进程名"", ""title"": ""窗口标题"", ""path"": ""进程路径"", +""startTime"": ""启动时间"", ""cpuTime"": ""CPU时间"", ""memory"": 内存使用量, +""threads"": 线程数, ""priority"": ""优先级"", ""description"": ""描述"", +""company"": ""公司"", ""version"": ""版本""} + +注意事项: +-------- +1. 终止进程可能需要管理员权限 +2. 进程名称不需要包含.exe后缀 +"; + Console.WriteLine(help); + } + + private static string GetArgumentValue(string[] args, string key) + { + for (int i = 0; i < args.Length - 1; i++) + { + if (args[i].Equals(key, StringComparison.OrdinalIgnoreCase)) + { + return args[i + 1]; + } + } + return null; + } +} diff --git a/plugin/lib/csharp/registry.cs b/plugin/lib/csharp/registry.cs new file mode 100644 index 0000000..53c2327 --- /dev/null +++ b/plugin/lib/csharp/registry.cs @@ -0,0 +1,357 @@ +using System; +using System.Text; +using Microsoft.Win32; +using System.Collections.Generic; +using System.Web.Script.Serialization; + +public class RegistryManager +{ + public static void Main(string[] args) + { + if (args.Length == 0 || args[0] == "-h" || args[0] == "--help") + { + ShowHelp(); + return; + } + + string type = GetArgumentValue(args, "-type"); + if (string.IsNullOrEmpty(type)) + { + Console.Error.WriteLine("Error: 必须指定操作类型 (-type)"); + return; + } + + try + { + string path = GetArgumentValue(args, "-path"); + string name = GetArgumentValue(args, "-name"); + string value = GetArgumentValue(args, "-value"); + string valueType = GetArgumentValue(args, "-valuetype"); + if (valueType == null) + { + valueType = "string"; + } + else + { + valueType = valueType.ToLower(); + } + + switch (type.ToLower()) + { + case "get": + if (string.IsNullOrEmpty(path)) + { + Console.Error.WriteLine("Error: 必须指定注册表路径 (-path)"); + return; + } + GetValue(path, name); + break; + + case "set": + if (string.IsNullOrEmpty(path) || string.IsNullOrEmpty(name)) + { + Console.Error.WriteLine("Error: 必须指定注册表路径 (-path) 和键名 (-name)"); + return; + } + SetValue(path, name, value, valueType); + break; + + case "delete": + if (string.IsNullOrEmpty(path)) + { + Console.Error.WriteLine("Error: 必须指定注册表路径 (-path)"); + return; + } + DeleteValue(path, name); + break; + + case "list": + if (string.IsNullOrEmpty(path)) + { + Console.Error.WriteLine("Error: 必须指定注册表路径 (-path)"); + return; + } + ListKeys(path); + break; + + default: + Console.Error.WriteLine("Error: 不支持的操作类型"); + break; + } + } + catch (Exception ex) + { + Console.Error.WriteLine(string.Format("Error: {0}", ex.Message)); + } + } + + private static void GetValue(string path, string name) + { + using (RegistryKey key = OpenRegistryKey(path)) + { + if (key != null) + { + object value = key.GetValue(name); + if (value != null) + { + var info = new Dictionary(); + info["path"] = path.Replace("\\", "\\\\"); + info["name"] = name; + info["value"] = value.ToString(); + info["type"] = key.GetValueKind(name).ToString(); + + var serializer = new JavaScriptSerializer(); + Console.Write(serializer.Serialize(info)); + return; + } + } + } + Console.Error.WriteLine("Error: 找不到指定的注册表值"); + } + + private static void SetValue(string path, string name, string value, string valueType) + { + using (RegistryKey key = OpenRegistryKey(path, true)) + { + if (key == null) + { + throw new Exception("找不到指定的注册表项"); + } + + object typedValue = ConvertValue(value, valueType); + RegistryValueKind kind = GetValueKind(valueType); + key.SetValue(name, typedValue, kind); + Console.WriteLine("成功设置注册表值"); + } + } + + private static void DeleteValue(string path, string name) + { + using (RegistryKey key = OpenRegistryKey(path, true)) + { + if (key == null) + { + throw new Exception("找不到指定的注册表项"); + } + + if (string.IsNullOrEmpty(name)) + { + // 删除整个键 + Registry.LocalMachine.DeleteSubKeyTree(GetRelativePath(path), false); + Console.WriteLine("成功删除注册表项"); + } + else + { + // 删除指定值 + key.DeleteValue(name, false); + Console.WriteLine("成功删除注册表值"); + } + } + } + + private static void ListKeys(string path) + { + var result = new List>(); + using (RegistryKey key = OpenRegistryKey(path)) + { + if (key != null) + { + foreach (string subKeyName in key.GetSubKeyNames()) + { + var info = new Dictionary(); + info["path"] = (path + "\\" + subKeyName).Replace("\\", "\\\\"); + info["name"] = subKeyName; + result.Add(info); + } + } + } + + var serializer = new JavaScriptSerializer(); + Console.Write(serializer.Serialize(result)); + } + + private static RegistryKey OpenRegistryKey(string path, bool writable = false) + { + string[] parts = path.Split('\\'); + if (parts.Length < 2) + { + throw new Exception("无效的注册表路径"); + } + + RegistryKey root = GetRootKey(parts[0]); + string subPath = string.Join("\\", parts, 1, parts.Length - 1); + return root.OpenSubKey(subPath, writable); + } + + private static RegistryKey GetRootKey(string name) + { + switch (name.ToUpper()) + { + case "HKLM": + case "HKEY_LOCAL_MACHINE": + return Registry.LocalMachine; + case "HKCU": + case "HKEY_CURRENT_USER": + return Registry.CurrentUser; + case "HKCR": + case "HKEY_CLASSES_ROOT": + return Registry.ClassesRoot; + case "HKU": + case "HKEY_USERS": + return Registry.Users; + case "HKCC": + case "HKEY_CURRENT_CONFIG": + return Registry.CurrentConfig; + default: + throw new Exception("无效的注册表根键"); + } + } + + private static string GetRelativePath(string path) + { + string[] parts = path.Split('\\'); + if (parts.Length < 2) + { + throw new Exception("无效的注册表路径"); + } + return string.Join("\\", parts, 1, parts.Length - 1); + } + + private static void OutputValue(string name, object value, RegistryValueKind kind) + { + string valueStr = FormatValue(value, kind); + Console.WriteLine(string.Format("{{\"type\": \"value\", \"name\": \"{0}\", \"value\": {1}, \"valueType\": \"{2}\"}}", + name.Replace("\"", "\\\""), + valueStr, + kind.ToString())); + } + + private static string FormatValue(object value, RegistryValueKind kind) + { + switch (kind) + { + case RegistryValueKind.String: + case RegistryValueKind.ExpandString: + return string.Format("\"{0}\"", value.ToString().Replace("\"", "\\\"")); + case RegistryValueKind.MultiString: + return string.Format("[{0}]", string.Join(",", Array.ConvertAll( + (string[])value, + s => string.Format("\"{0}\"", s.Replace("\"", "\\\""))))); + case RegistryValueKind.Binary: + return string.Format("[{0}]", string.Join(",", (byte[])value)); + default: + return value.ToString(); + } + } + + private static object ConvertValue(string value, string valueType) + { + switch (valueType) + { + case "string": + return value; + case "dword": + return int.Parse(value); + case "qword": + return long.Parse(value); + case "binary": + return Array.ConvertAll(value.Split(','), byte.Parse); + case "multistring": + return value.Split(','); + case "expandstring": + return value; + default: + throw new Exception("不支持的值类型"); + } + } + + private static RegistryValueKind GetValueKind(string valueType) + { + switch (valueType) + { + case "string": + return RegistryValueKind.String; + case "dword": + return RegistryValueKind.DWord; + case "qword": + return RegistryValueKind.QWord; + case "binary": + return RegistryValueKind.Binary; + case "multistring": + return RegistryValueKind.MultiString; + case "expandstring": + return RegistryValueKind.ExpandString; + default: + throw new Exception("不支持的值类型"); + } + } + + private static void ShowHelp() + { + string help = @" +Windows 注册表管理工具使用说明 +====================== + +基本语法: +registry.exe -type <操作类型> [参数...] + +操作类型: +-------- +1. get - 获取注册表值 + 参数: + -path <注册表路径> 完整的注册表路径 + -name <值名称> 要获取的值名称(可选,不指定则列出所有值) + 示例: + registry.exe -type get -path ""HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion"" -name ""ProgramFilesDir"" + +2. set - 设置注册表值 + 参数: + -path <注册表路径> 完整的注册表路径 + -name <值名称> 要设置的值名称 + -value <值> 要设置的值 + -valuetype <类型> 值类型(可选,默认为string) + 支持的类型:string, dword, qword, binary, multistring, expandstring + 示例: + registry.exe -type set -path ""HKCU\Software\MyApp"" -name ""Setting"" -value ""123"" -valuetype dword + +3. delete - 删除注册表项或值 + 参数: + -path <注册表路径> 完整的注册表路径 + -name <值名称> 要删除的值名称(可选,不指定则删除整个键) + 示例: + registry.exe -type delete -path ""HKCU\Software\MyApp"" -name ""Setting"" + +4. list - 列出注册表项下的所有子项和值 + 参数: + -path <注册表路径> 完整的注册表路径 + 示例: + registry.exe -type list -path ""HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion"" + +返回值: +------ +JSON格式的注册表信息: +键:{""type"": ""key"", ""name"": ""键名""} +值:{""type"": ""value"", ""name"": ""值名"", ""value"": 值, ""valueType"": ""值类型""} + +注意事项: +-------- +1. 需要管理员权限才能修改系统关键注册表项 +2. 注册表路径必须以根键开头(HKLM、HKCU、HKCR、HKU、HKCC) +3. 修改注册表可能会影响系统稳定性,请谨慎操作 +4. 建议在修改前备份重要的注册表项 +"; + Console.WriteLine(help); + } + + private static string GetArgumentValue(string[] args, string key) + { + for (int i = 0; i < args.Length - 1; i++) + { + if (args[i].Equals(key, StringComparison.OrdinalIgnoreCase)) + { + return args[i + 1]; + } + } + return null; + } +} diff --git a/plugin/lib/csharp/service.cs b/plugin/lib/csharp/service.cs new file mode 100644 index 0000000..07cffe8 --- /dev/null +++ b/plugin/lib/csharp/service.cs @@ -0,0 +1,233 @@ +using System; +using System.ServiceProcess; +using System.Runtime.InteropServices; +using System.Text; + +public class ServiceManager +{ + [DllImport("advapi32.dll", SetLastError = true)] + private static extern IntPtr OpenSCManager(string lpMachineName, string lpDatabaseName, uint dwDesiredAccess); + + [DllImport("advapi32.dll", SetLastError = true)] + private static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess); + + [DllImport("advapi32.dll", SetLastError = true)] + private static extern bool StartService(IntPtr hService, uint dwNumServiceArgs, string[] lpServiceArgVectors); + + [DllImport("advapi32.dll", SetLastError = true)] + private static extern bool ControlService(IntPtr hService, uint dwControl, ref SERVICE_STATUS lpServiceStatus); + + [DllImport("advapi32.dll", SetLastError = true)] + private static extern bool CloseServiceHandle(IntPtr hSCObject); + + private const uint SC_MANAGER_ALL_ACCESS = 0xF003F; + private const uint SERVICE_ALL_ACCESS = 0xF01FF; + private const uint SERVICE_CONTROL_STOP = 0x00000001; + private const uint SERVICE_CONTROL_PAUSE = 0x00000002; + private const uint SERVICE_CONTROL_CONTINUE = 0x00000003; + + [StructLayout(LayoutKind.Sequential)] + private struct SERVICE_STATUS + { + public uint dwServiceType; + public uint dwCurrentState; + public uint dwControlsAccepted; + public uint dwWin32ExitCode; + public uint dwServiceSpecificExitCode; + public uint dwCheckPoint; + public uint dwWaitHint; + } + + public static void Main(string[] args) + { + if (args.Length == 0 || args[0] == "-h" || args[0] == "--help") + { + ShowHelp(); + return; + } + + string type = GetArgumentValue(args, "-type"); + if (string.IsNullOrEmpty(type)) + { + Console.Error.WriteLine("Error: 必须指定操作类型 (-type)"); + return; + } + + try + { + switch (type.ToLower()) + { + case "list": + ListServices(); + break; + case "start": + case "stop": + case "pause": + case "continue": + string name = GetArgumentValue(args, "-name"); + if (string.IsNullOrEmpty(name)) + { + Console.Error.WriteLine("Error: 必须指定服务名称 (-name)"); + return; + } + ControlServiceByName(name, type); + break; + default: + Console.Error.WriteLine("Error: 不支持的操作类型"); + break; + } + } + catch (Exception ex) + { + Console.Error.WriteLine(string.Format("Error: {0}", ex.Message)); + } + } + + private static void ListServices() + { + Console.Write("["); + bool first = true; + ServiceController[] services = ServiceController.GetServices(); + foreach (ServiceController service in services) + { + if (!first) + { + Console.Write(","); + } + first = false; + Console.Write(string.Format("{{\"name\": \"{0}\", \"displayName\": \"{1}\", \"status\": \"{2}\"}}", + service.ServiceName, + service.DisplayName.Replace("\"", "\\\""), + service.Status)); + } + Console.Write("]"); + } + + private static void ControlServiceByName(string serviceName, string operation) + { + IntPtr scm = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS); + if (scm == IntPtr.Zero) + { + throw new Exception("无法打开服务控制管理器"); + } + + try + { + IntPtr service = OpenService(scm, serviceName, SERVICE_ALL_ACCESS); + if (service == IntPtr.Zero) + { + throw new Exception("无法打开服务"); + } + + try + { + SERVICE_STATUS status = new SERVICE_STATUS(); + bool success = false; + + switch (operation.ToLower()) + { + case "start": + success = StartService(service, 0, null); + break; + case "stop": + success = ControlService(service, SERVICE_CONTROL_STOP, ref status); + break; + case "pause": + success = ControlService(service, SERVICE_CONTROL_PAUSE, ref status); + break; + case "continue": + success = ControlService(service, SERVICE_CONTROL_CONTINUE, ref status); + break; + } + + if (success) + { + Console.WriteLine(string.Format("成功{0}服务: {1}", GetOperationName(operation), serviceName)); + } + else + { + throw new Exception(string.Format("无法{0}服务", GetOperationName(operation))); + } + } + finally + { + CloseServiceHandle(service); + } + } + finally + { + CloseServiceHandle(scm); + } + } + + private static string GetOperationName(string operation) + { + switch (operation.ToLower()) + { + case "start": return "启动"; + case "stop": return "停止"; + case "pause": return "暂停"; + case "continue": return "继续"; + default: return operation; + } + } + + private static void ShowHelp() + { + string help = @" +Windows 服务管理工具使用说明 +====================== + +基本语法: +service.exe -type <操作类型> [参数...] + +操作类型: +-------- +1. list - 列出所有服务 + 示例: service.exe -type list + +2. start - 启动服务 + 参数: + -name <服务名> 服务名称 + 示例: service.exe -type start -name Spooler + +3. stop - 停止服务 + 参数: + -name <服务名> 服务名称 + 示例: service.exe -type stop -name Spooler + +4. pause - 暂停服务 + 参数: + -name <服务名> 服务名称 + 示例: service.exe -type pause -name Spooler + +5. continue - 继续服务 + 参数: + -name <服务名> 服务名称 + 示例: service.exe -type continue -name Spooler + +返回值: +------ +list操作返回JSON格式的服务信息: +{""name"": ""服务名"", ""displayName"": ""显示名称"", ""status"": ""状态""} + +注意事项: +-------- +1. 需要管理员权限 +2. 并非所有服务都支持暂停/继续操作 +"; + Console.WriteLine(help); + } + + private static string GetArgumentValue(string[] args, string key) + { + for (int i = 0; i < args.Length - 1; i++) + { + if (args[i].Equals(key, StringComparison.OrdinalIgnoreCase)) + { + return args[i + 1]; + } + } + return null; + } +} diff --git a/plugin/lib/csharp/software.cs b/plugin/lib/csharp/software.cs new file mode 100644 index 0000000..0b964db --- /dev/null +++ b/plugin/lib/csharp/software.cs @@ -0,0 +1,352 @@ +using System; +using System.Text; +using System.Runtime.InteropServices; +using Microsoft.Win32; +using System.Collections.Generic; +using System.Diagnostics; +using System.Web.Script.Serialization; +using System.Linq; + +public class SoftwareManager +{ + [DllImport("msi.dll", CharSet = CharSet.Unicode)] + private static extern uint MsiEnumProducts(uint iProductIndex, StringBuilder lpProductBuf); + + [DllImport("msi.dll", CharSet = CharSet.Unicode)] + private static extern uint MsiGetProductInfo(string szProduct, string szProperty, StringBuilder lpValueBuf, ref uint pcchValueBuf); + + [DllImport("msi.dll", CharSet = CharSet.Unicode)] + private static extern uint MsiConfigureProduct(string szProduct, int iInstallLevel, int eInstallState); + + private const int INSTALLSTATE_DEFAULT = -1; + private const int INSTALLSTATE_ABSENT = 2; + private const int INSTALLLEVEL_DEFAULT = 0; + + public static void Main(string[] args) + { + if (args.Length == 0 || args[0] == "-h" || args[0] == "--help") + { + ShowHelp(); + return; + } + + string type = GetArgumentValue(args, "-type"); + if (string.IsNullOrEmpty(type)) + { + Console.Error.WriteLine("Error: 必须指定操作类型 (-type)"); + return; + } + + try + { + switch (type.ToLower()) + { + case "list": + ListSoftware(); + break; + case "uninstall": + string target = GetArgumentValue(args, "-target"); + if (string.IsNullOrEmpty(target)) + { + Console.Error.WriteLine("Error: 必须指定目标软件 (-target)"); + return; + } + UninstallSoftware(target); + break; + case "repair": + string product = GetArgumentValue(args, "-target"); + if (string.IsNullOrEmpty(product)) + { + Console.Error.WriteLine("Error: 必须指定目标软件 (-target)"); + return; + } + RepairSoftware(product); + break; + default: + Console.Error.WriteLine("Error: 不支持的操作类型"); + break; + } + } + catch (Exception ex) + { + Console.Error.WriteLine(string.Format("Error: {0}", ex.Message)); + } + } + + private static void ListSoftware() + { + Console.Write("["); + bool first = true; + + // 列出MSI安装的软件 + uint index = 0; + StringBuilder productCode = new StringBuilder(39); + while (MsiEnumProducts(index++, productCode) == 0) + { + uint charCount = 128; + StringBuilder displayName = new StringBuilder((int)charCount); + StringBuilder publisher = new StringBuilder((int)charCount); + StringBuilder version = new StringBuilder((int)charCount); + + MsiGetProductInfo(productCode.ToString(), "ProductName", displayName, ref charCount); + charCount = 128; + MsiGetProductInfo(productCode.ToString(), "Publisher", publisher, ref charCount); + charCount = 128; + MsiGetProductInfo(productCode.ToString(), "VersionString", version, ref charCount); + + if (!first) + { + Console.Write(","); + } + first = false; + Console.Write(string.Format("{{\"name\": \"{0}\", \"publisher\": \"{1}\", \"version\": \"{2}\", \"source\": \"{3}\", \"id\": \"{4}\"}}", + displayName.ToString().Replace("\"", "\\\""), + publisher.ToString().Replace("\"", "\\\""), + version.ToString().Replace("\"", "\\\""), + "MSI", + productCode.ToString().Replace("\\", "\\\\").Replace("\"", "\\\""))); + } + + // 列出注册表中的软件 + string[] registryPaths = { + @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", + @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall" + }; + + foreach (string registryPath in registryPaths) + { + using (RegistryKey key = Registry.LocalMachine.OpenSubKey(registryPath)) + { + if (key != null) + { + foreach (string subKeyName in key.GetSubKeyNames()) + { + using (RegistryKey subKey = key.OpenSubKey(subKeyName)) + { + if (subKey != null) + { + string displayName = subKey.GetValue("DisplayName") as string; + if (!string.IsNullOrEmpty(displayName)) + { + string publisher = subKey.GetValue("Publisher") as string; + if (publisher == null) publisher = ""; + string version = subKey.GetValue("DisplayVersion") as string; + if (version == null) version = ""; + string uninstallString = subKey.GetValue("UninstallString") as string; + if (uninstallString == null) uninstallString = ""; + + if (!first) + { + Console.Write(","); + } + first = false; + Console.Write(string.Format("{{\"name\": \"{0}\", \"publisher\": \"{1}\", \"version\": \"{2}\", \"source\": \"{3}\", \"id\": \"{4}\"}}", + displayName.Replace("\"", "\\\""), + publisher.Replace("\"", "\\\""), + version.Replace("\"", "\\\""), + "Registry", + uninstallString.Replace("\\", "\\\\").Replace("\"", "\\\""))); + } + } + } + } + } + } + } + Console.Write("]"); + } + + private static void OutputSoftwareInfo(string name, string publisher, string version, string source, string id) + { + Console.WriteLine(string.Format("{{\"name\": \"{0}\", \"publisher\": \"{1}\", \"version\": \"{2}\", \"source\": \"{3}\", \"id\": \"{4}\"}}", + name.Replace("\"", "\\\""), + publisher.Replace("\"", "\\\""), + version.Replace("\"", "\\\""), + source, + id.Replace("\"", "\\\""))); + } + + private static void UninstallSoftware(string target) + { + // 尝试通过MSI卸载 + if (target.Length == 38 && target.StartsWith("{") && target.EndsWith("}")) + { + uint result = MsiConfigureProduct(target, INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT); + if (result == 0) + { + Console.WriteLine("成功启动卸载程序"); + return; + } + } + + // 尝试通过注册表卸载字符串卸载 + string[] registryPaths = { + @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", + @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall" + }; + + foreach (string registryPath in registryPaths) + { + using (RegistryKey key = Registry.LocalMachine.OpenSubKey(registryPath)) + { + if (key != null) + { + foreach (string subKeyName in key.GetSubKeyNames()) + { + using (RegistryKey subKey = key.OpenSubKey(subKeyName)) + { + if (subKey != null) + { + string displayName = subKey.GetValue("DisplayName") as string; + if (displayName != null && displayName.Contains(target)) + { + string uninstallString = subKey.GetValue("UninstallString") as string; + if (!string.IsNullOrEmpty(uninstallString)) + { + // 启动卸载程序 + ProcessStartInfo startInfo = new ProcessStartInfo + { + FileName = "cmd.exe", + Arguments = "/c " + uninstallString, + UseShellExecute = true + }; + Process.Start(startInfo); + Console.WriteLine("成功启动卸载程序"); + return; + } + } + } + } + } + } + } + } + + throw new Exception("找不到指定的软件或无法卸载"); + } + + private static void RepairSoftware(string productCode) + { + if (productCode.Length != 38 || !productCode.StartsWith("{") || !productCode.EndsWith("}")) + { + throw new Exception("无效的产品代码"); + } + + uint result = MsiConfigureProduct(productCode, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT); + if (result == 0) + { + Console.WriteLine("成功启动修复程序"); + } + else + { + throw new Exception("无法修复软件"); + } + } + + private static void ShowHelp() + { + string help = @" +Windows 软件管理工具使用说明 +====================== + +基本语法: +software.exe -type <操作类型> [参数...] + +操作类型: +-------- +1. list - 列出已安装的软件 + 示例: software.exe -type list + +2. uninstall - 卸载软件 + 参数: + -target <软件名称或ID> 要卸载的软件名称或产品代码 + 示例: + software.exe -type uninstall -target ""Microsoft Office"" + software.exe -type uninstall -target ""{12345678-1234-1234-1234-123456789012}"" + +3. repair - 修复MSI安装的软件 + 参数: + -target <产品代码> 要修复的软件的产品代码 + 示例: software.exe -type repair -target ""{12345678-1234-1234-1234-123456789012}"" + +返回值: +------ +list操作返回JSON格式的软件信息: +{""name"": ""软件名称"", ""publisher"": ""发布者"", ""version"": ""版本"", ""source"": ""来源"", ""id"": ""标识符""} + +注意事项: +-------- +1. 需要管理员权限 +2. 卸载和修复操作可能需要用户确认 +3. 并非所有软件都支持修复功能 +4. 卸载操作会启动软件自带的卸载程序 +"; + Console.WriteLine(help); + } + + private static string GetArgumentValue(string[] args, string key) + { + for (int i = 0; i < args.Length - 1; i++) + { + if (args[i].Equals(key, StringComparison.OrdinalIgnoreCase)) + { + return args[i + 1]; + } + } + return null; + } + + private static string GetSoftwareInfo() + { + var result = new List>(); + string uninstallKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"; + string uninstallKey32 = @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"; + + // 获取64位和32位软件信息 + GetSoftwareFromRegistry(Registry.LocalMachine, uninstallKey, result); + GetSoftwareFromRegistry(Registry.LocalMachine, uninstallKey32, result); + + var serializer = new JavaScriptSerializer(); + return serializer.Serialize(result.Select(info => new { + id = info["id"], + name = info["name"], + version = info["version"], + publisher = info["publisher"], + installLocation = info.ContainsKey("installLocation") && info["installLocation"] != null ? + info["installLocation"].Replace("\\", "\\\\") : null, + uninstallString = info.ContainsKey("uninstallString") && info["uninstallString"] != null ? + info["uninstallString"].Replace("\\", "\\\\") : null + })); + } + + private static void GetSoftwareFromRegistry(RegistryKey root, string keyPath, List> result) + { + using (RegistryKey key = root.OpenSubKey(keyPath)) + { + if (key != null) + { + foreach (string subKeyName in key.GetSubKeyNames()) + { + using (RegistryKey subKey = key.OpenSubKey(subKeyName)) + { + if (subKey != null) + { + string displayName = subKey.GetValue("DisplayName") as string; + if (!string.IsNullOrEmpty(displayName)) + { + var info = new Dictionary(); + info["id"] = subKeyName; + info["name"] = displayName; + info["version"] = subKey.GetValue("DisplayVersion") as string ?? ""; + info["publisher"] = subKey.GetValue("Publisher") as string ?? ""; + info["installLocation"] = subKey.GetValue("InstallLocation") as string; + info["uninstallString"] = subKey.GetValue("UninstallString") as string; + result.Add(info); + } + } + } + } + } + } + } +} diff --git a/plugin/lib/csharp/utils.cs b/plugin/lib/csharp/utils.cs new file mode 100644 index 0000000..9a87308 --- /dev/null +++ b/plugin/lib/csharp/utils.cs @@ -0,0 +1,407 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; +using System.Net.NetworkInformation; +using System.Diagnostics; +using System.IO; +using Microsoft.Win32; + +public class SystemUtils +{ + #region Win32 API + [DllImport("user32.dll", CharSet = CharSet.Auto)] + private static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni); + + [DllImport("user32.dll")] + private static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam); + + [DllImport("user32.dll")] + private static extern IntPtr GetForegroundWindow(); + + [DllImport("PowrProf.dll", CharSet = CharSet.Auto, ExactSpelling = true)] + private static extern bool SetSuspendState(bool hibernate, bool forceCritical, bool disableWakeEvent); + + [DllImport("kernel32.dll")] + private static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags); + + private const int SPI_SETDESKWALLPAPER = 20; + private const int SPIF_UPDATEINIFILE = 0x01; + private const int SPIF_SENDCHANGE = 0x02; + private const int WM_SYSCOMMAND = 0x0112; + private const int SC_MONITORPOWER = 0xF170; + + [Flags] + private enum EXECUTION_STATE : uint + { + ES_AWAYMODE_REQUIRED = 0x00000040, + ES_CONTINUOUS = 0x80000000, + ES_DISPLAY_REQUIRED = 0x00000002, + ES_SYSTEM_REQUIRED = 0x00000001 + } + #endregion + + public static void Main(string[] args) + { + if (args.Length == 0 || args[0] == "-h" || args[0] == "--help") + { + ShowHelp(); + return; + } + + string type = GetArgumentValue(args, "-type"); + if (string.IsNullOrEmpty(type)) + { + Console.Error.WriteLine("Error: 必须指定操作类型 (-type)"); + return; + } + + try + { + switch (type.ToLower()) + { + case "wallpaper": + string wallpaperPath = GetArgumentValue(args, "-path"); + if (string.IsNullOrEmpty(wallpaperPath)) + { + Console.Error.WriteLine("Error: 必须指定壁纸路径 (-path)"); + return; + } + SetWallpaper(wallpaperPath); + break; + + case "monitor": + string action = GetArgumentValue(args, "-action"); + if (string.IsNullOrEmpty(action)) + { + Console.Error.WriteLine("Error: 必须指定动作 (-action)"); + return; + } + ControlMonitor(action); + break; + + case "power": + string mode = GetArgumentValue(args, "-mode"); + if (string.IsNullOrEmpty(mode)) + { + Console.Error.WriteLine("Error: 必须指定电源模式 (-mode)"); + return; + } + PowerControl(mode); + break; + + case "network": + string interfaceName = GetArgumentValue(args, "-interface"); + string ip = GetArgumentValue(args, "-ip"); + string mask = GetArgumentValue(args, "-mask"); + string gateway = GetArgumentValue(args, "-gateway"); + string dns = GetArgumentValue(args, "-dns"); + ConfigureNetwork(interfaceName, ip, mask, gateway, dns); + break; + + case "startup": + string appPath = GetArgumentValue(args, "-path"); + string appName = GetArgumentValue(args, "-name"); + bool remove = HasArgument(args, "-remove"); + ManageStartup(appPath, appName, remove); + break; + + case "shortcut": + string targetPath = GetArgumentValue(args, "-target"); + string shortcutPath = GetArgumentValue(args, "-path"); + string shortcutArgs = GetArgumentValue(args, "-args"); + CreateShortcut(targetPath, shortcutPath, shortcutArgs); + break; + + case "brightness": + string brightness = GetArgumentValue(args, "-level"); + if (string.IsNullOrEmpty(brightness)) + { + Console.Error.WriteLine("Error: 必须指定亮度级别 (-level)"); + return; + } + SetBrightness(int.Parse(brightness)); + break; + + default: + Console.Error.WriteLine("Error: 不支持的操作类型"); + break; + } + } + catch (Exception ex) + { + Console.Error.WriteLine(string.Format("Error: {0}", ex.Message)); + } + } + + private static void SetWallpaper(string path) + { + if (!File.Exists(path)) + { + throw new Exception("壁纸文件不存在"); + } + + SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, path, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE); + Console.WriteLine("成功设置壁纸"); + } + + private static void ControlMonitor(string action) + { + IntPtr hWnd = GetForegroundWindow(); + switch (action.ToLower()) + { + case "off": + SendMessage(hWnd, WM_SYSCOMMAND, SC_MONITORPOWER, 2); + break; + case "on": + SendMessage(hWnd, WM_SYSCOMMAND, SC_MONITORPOWER, -1); + break; + default: + throw new Exception("不支持的显示器操作"); + } + Console.WriteLine("成功控制显示器"); + } + + private static void PowerControl(string mode) + { + switch (mode.ToLower()) + { + case "sleep": + SetSuspendState(false, false, false); + break; + case "hibernate": + SetSuspendState(true, false, false); + break; + case "awake": + SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS | EXECUTION_STATE.ES_DISPLAY_REQUIRED | EXECUTION_STATE.ES_SYSTEM_REQUIRED); + break; + case "normal": + SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS); + break; + default: + throw new Exception("不支持的电源模式"); + } + Console.WriteLine("成功设置电源模式"); + } + + private static void ConfigureNetwork(string interfaceName, string ip, string mask, string gateway, string dns) + { + // 使用netsh命令配置网络 + StringBuilder command = new StringBuilder(); + command.AppendFormat("interface ip set address \"{0}\" static {1} {2}", interfaceName, ip, mask); + if (!string.IsNullOrEmpty(gateway)) + { + command.AppendFormat(" {0}", gateway); + } + + ProcessStartInfo startInfo = new ProcessStartInfo + { + FileName = "netsh", + Arguments = command.ToString(), + UseShellExecute = false, + RedirectStandardOutput = true, + CreateNoWindow = true + }; + + using (Process process = Process.Start(startInfo)) + { + process.WaitForExit(); + if (process.ExitCode != 0) + { + throw new Exception("设置IP地址失败"); + } + } + + if (!string.IsNullOrEmpty(dns)) + { + command.Clear(); + command.AppendFormat("interface ip set dns \"{0}\" static {1}", interfaceName, dns); + startInfo.Arguments = command.ToString(); + + using (Process process = Process.Start(startInfo)) + { + process.WaitForExit(); + if (process.ExitCode != 0) + { + throw new Exception("设置DNS失败"); + } + } + } + + Console.WriteLine("成功配置网络"); + } + + private static void ManageStartup(string appPath, string appName, bool remove) + { + string keyPath = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; + using (RegistryKey key = Registry.CurrentUser.OpenSubKey(keyPath, true)) + { + if (key == null) + { + throw new Exception("无法访问启动项注册表"); + } + + if (remove) + { + key.DeleteValue(appName, false); + Console.WriteLine("成功移除开机启动项"); + } + else + { + key.SetValue(appName, appPath); + Console.WriteLine("成功添加开机启动项"); + } + } + } + + private static void CreateShortcut(string targetPath, string shortcutPath, string args) + { + // 使用PowerShell创建快捷方式 + StringBuilder command = new StringBuilder(); + command.AppendFormat(@" + $WshShell = New-Object -comObject WScript.Shell + $Shortcut = $WshShell.CreateShortcut('{0}') + $Shortcut.TargetPath = '{1}'", + shortcutPath.Replace("'", "''"), + targetPath.Replace("'", "''")); + + if (!string.IsNullOrEmpty(args)) + { + command.AppendFormat(@" + $Shortcut.Arguments = '{0}'", + args.Replace("'", "''")); + } + + command.Append(@" + $Shortcut.Save()"); + + ProcessStartInfo startInfo = new ProcessStartInfo + { + FileName = "powershell", + Arguments = command.ToString(), + UseShellExecute = false, + RedirectStandardOutput = true, + CreateNoWindow = true + }; + + using (Process process = Process.Start(startInfo)) + { + process.WaitForExit(); + if (process.ExitCode != 0) + { + throw new Exception("创建快捷方式失败"); + } + } + + Console.WriteLine("成功创建快捷方式"); + } + + private static void SetBrightness(int level) + { + if (level < 0 || level > 100) + { + throw new Exception("亮度级别必须在0-100之间"); + } + + // 使用PowerShell命令设置亮度 + ProcessStartInfo startInfo = new ProcessStartInfo + { + FileName = "powershell", + Arguments = string.Format("(Get-WmiObject -Namespace root/WMI -Class WmiMonitorBrightnessMethods).WmiSetBrightness(1,{0})", level), + UseShellExecute = false, + RedirectStandardOutput = true, + CreateNoWindow = true + }; + + using (Process process = Process.Start(startInfo)) + { + process.WaitForExit(); + if (process.ExitCode != 0) + { + throw new Exception("设置亮度失败"); + } + } + + Console.WriteLine("成功设置亮度"); + } + + private static void ShowHelp() + { + string help = @" +Windows 系统工具使用说明 +=================== + +基本语法: +utils.exe -type <操作类型> [参数...] + +操作类型: +-------- +1. wallpaper - 设置壁纸 + 参数: + -path <文件路径> 壁纸图片路径 + 示例: utils.exe -type wallpaper -path ""C:\wallpaper.jpg"" + +2. monitor - 控制显示器 + 参数: + -action <动作> on/off + 示例: utils.exe -type monitor -action off + +3. power - 电源控制 + 参数: + -mode <模式> sleep/hibernate/awake/normal + 示例: utils.exe -type power -mode sleep + +4. network - 配置网络 + 参数: + -interface <网卡名称> 网络接口名称 + -ip 要设置的IP地址 + -mask <子网掩码> 子网掩码 + -gateway <网关> 默认网关(可选) + -dns DNS服务器(可选) + 示例: utils.exe -type network -interface ""以太网"" -ip 192.168.1.100 -mask 255.255.255.0 + +5. startup - 管理开机启动项 + 参数: + -path <应用程序路径> 应用程序路径 + -name <启动项名称> 启动项名称 + -remove 移除开机启动项(可选) + 示例: utils.exe -type startup -path ""C:\Program Files\MyApp\MyApp.exe"" -name MyApp + +6. shortcut - 创建快捷方式 + 参数: + -target <目标路径> 目标路径 + -path <快捷方式路径> 快捷方式路径 + -args <参数> 参数(可选) + 示例: utils.exe -type shortcut -target ""C:\Program Files\MyApp\MyApp.exe"" -path ""C:\Users\MyUser\Desktop\MyApp.lnk"" + +7. brightness - 控制亮度 + 参数: + -level <亮度> 亮度级别(0-100) + 示例: utils.exe -type brightness -level 75 + +注意事项: +-------- +1. 某些操作可能需要管理员权限 +2. 网络配置更改可能会暂时断开网络连接 +3. 电源控制可能会影响正在运行的程序 +4. 建议在更改系统设置前先备份当前配置 +"; + Console.WriteLine(help); + } + + private static string GetArgumentValue(string[] args, string key) + { + for (int i = 0; i < args.Length - 1; i++) + { + if (args[i].Equals(key, StringComparison.OrdinalIgnoreCase)) + { + return args[i + 1]; + } + } + return null; + } + + private static bool HasArgument(string[] args, string key) + { + return Array.Exists(args, arg => arg.Equals(key, StringComparison.OrdinalIgnoreCase)); + } +} diff --git a/plugin/lib/quickcomposer/windows/index.js b/plugin/lib/quickcomposer/windows/index.js index 37f8aef..99ab884 100644 --- a/plugin/lib/quickcomposer/windows/index.js +++ b/plugin/lib/quickcomposer/windows/index.js @@ -1,9 +1,19 @@ const window = require("./window"); const sendmessage = require("./sendmessage"); const monitor = require("./monitor"); +const process = require("./process"); +const registry = require("./registry"); +const service = require("./service"); +const software = require("./software"); +const utils = require("./utils"); module.exports = { window, sendmessage, monitor, + process, + registry, + service, + software, + utils, }; diff --git a/plugin/lib/quickcomposer/windows/process.js b/plugin/lib/quickcomposer/windows/process.js new file mode 100644 index 0000000..71cdf5e --- /dev/null +++ b/plugin/lib/quickcomposer/windows/process.js @@ -0,0 +1,57 @@ +const { runCsharpFeature } = require("../../csharp"); + +/** + * 列出进程 + * @returns {Array} 进程列表 + */ +const listProcesses = async function () { + const args = ["-type", "list"]; + const result = await runCsharpFeature("process", args); + if (result && result.startsWith("Error:")) { + throw new Error(result.substring(7)); + } + try { + return JSON.parse(result); + } catch (error) { + console.error("解析进程列表失败:", error); + return null; + } +}; + +/** + * 终止进程 + * @param {string} target 进程ID或名称 + * @returns {boolean} 是否成功 + */ +const killProcess = async function (target) { + const args = ["-type", "kill", "-target", target]; + const result = await runCsharpFeature("process", args); + if (result && result.startsWith("Error:")) { + throw new Error(result.substring(7)); + } + return true; +}; + +/** + * 启动进程 + * @param {string} path 程序路径 + * @param {string} arguments 启动参数 + * @returns {boolean} 是否成功 + */ +const startProcess = async function (path, arguments = "") { + const args = ["-type", "start", "-path", path]; + if (arguments) { + args.push("-args", arguments); + } + const result = await runCsharpFeature("process", args); + if (result && result.startsWith("Error:")) { + throw new Error(result.substring(7)); + } + return true; +}; + +module.exports = { + listProcesses, + killProcess, + startProcess, +}; diff --git a/plugin/lib/quickcomposer/windows/registry.js b/plugin/lib/quickcomposer/windows/registry.js new file mode 100644 index 0000000..1bfc471 --- /dev/null +++ b/plugin/lib/quickcomposer/windows/registry.js @@ -0,0 +1,96 @@ +const { runCsharpFeature } = require("../../csharp"); + +/** + * 获取注册表值 + * @param {string} path 注册表路径 + * @param {string} name 值名称 + * @returns {object} 注册表值 + */ +const getValue = async function (path, name = "") { + const args = ["-type", "get", "-path", path]; + if (name) { + args.push("-name", name); + } + const result = await runCsharpFeature("registry", args); + if (result && result.startsWith("Error:")) { + throw new Error(result.substring(7)); + } + try { + return JSON.parse(result); + } catch (error) { + console.error("解析注册表值失败:", error); + return null; + } +}; + +/** + * 设置注册表值 + * @param {string} path 注册表路径 + * @param {string} name 值名称 + * @param {string} value 值 + * @param {string} valueType 值类型 + * @returns {boolean} 是否成功 + */ +const setValue = async function (path, name, value, valueType = "string") { + const args = [ + "-type", + "set", + "-path", + path, + "-name", + name, + "-value", + value, + "-valuetype", + valueType, + ]; + const result = await runCsharpFeature("registry", args); + if (result && result.startsWith("Error:")) { + throw new Error(result.substring(7)); + } + return true; +}; + +/** + * 删除注册表值 + * @param {string} path 注册表路径 + * @param {string} name 值名称 + * @returns {boolean} 是否成功 + */ +const deleteValue = async function (path, name = "") { + const args = ["-type", "delete", "-path", path]; + if (name) { + args.push("-name", name); + } + const result = await runCsharpFeature("registry", args); + if (result && result.startsWith("Error:")) { + throw new Error(result.substring(7)); + } + return true; +}; + +/** + * 列出注册表项 + * @param {string} path 注册表路径 + * @returns {Array} 注册表项列表 + */ +const listKeys = async function (path) { + const args = ["-type", "list", "-path", path]; + const result = await runCsharpFeature("registry", args); + if (result && result.startsWith("Error:")) { + throw new Error(result.substring(7)); + } + try { + return JSON.parse(result); + } catch (error) { + console.error("解析注册表项列表失败:", error); + return null; + } +}; + +module.exports = { + getValue, + setValue, + deleteValue, + listKeys, +}; diff --git a/plugin/lib/quickcomposer/windows/service.js b/plugin/lib/quickcomposer/windows/service.js new file mode 100644 index 0000000..9d87e6f --- /dev/null +++ b/plugin/lib/quickcomposer/windows/service.js @@ -0,0 +1,39 @@ +const { runCsharpFeature } = require("../../csharp"); + +/** + * 列出服务 + * @returns {Array} 服务列表 + */ +const listServices = async function () { + const args = ["-type", "list"]; + const result = await runCsharpFeature("service", args); + if (result && result.startsWith("Error:")) { + throw new Error(result.substring(7)); + } + try { + return JSON.parse(result); + } catch (error) { + console.error("解析服务列表失败:", error); + return null; + } +}; + +/** + * 控制服务 + * @param {string} name 服务名称 + * @param {string} operation 操作类型:start/stop/pause/continue + * @returns {boolean} 是否成功 + */ +const controlService = async function (name, operation) { + const args = ["-type", operation, "-name", name]; + const result = await runCsharpFeature("service", args); + if (result && result.startsWith("Error:")) { + throw new Error(result.substring(7)); + } + return true; +}; + +module.exports = { + listServices, + controlService, +}; diff --git a/plugin/lib/quickcomposer/windows/software.js b/plugin/lib/quickcomposer/windows/software.js new file mode 100644 index 0000000..8f4cb4f --- /dev/null +++ b/plugin/lib/quickcomposer/windows/software.js @@ -0,0 +1,38 @@ +const { runCsharpFeature } = require("../../csharp"); + +/** + * 列出已安装软件 + * @returns {Array} 软件列表 + */ +const listSoftware = async function () { + const args = ["-type", "list"]; + const result = await runCsharpFeature("software", args); + if (result && result.startsWith("Error:")) { + throw new Error(result.substring(7)); + } + try { + return JSON.parse(result); + } catch (error) { + console.error("解析软件列表失败:", error); + return null; + } +}; + +/** + * 卸载软件 + * @param {string} target 软件ID + * @returns {boolean} 是否成功 + */ +const uninstallSoftware = async function (target) { + const args = ["-type", "uninstall", "-target", target]; + const result = await runCsharpFeature("software", args); + if (result && result.startsWith("Error:")) { + throw new Error(result.substring(7)); + } + return true; +}; + +module.exports = { + listSoftware, + uninstallSoftware, +}; diff --git a/plugin/lib/quickcomposer/windows/utils.js b/plugin/lib/quickcomposer/windows/utils.js new file mode 100644 index 0000000..d6285fb --- /dev/null +++ b/plugin/lib/quickcomposer/windows/utils.js @@ -0,0 +1,146 @@ +const { runCsharpFeature } = require("../../csharp"); + +/** + * 设置壁纸 + * @param {string} path 壁纸路径 + * @returns {boolean} 是否成功 + */ +const setWallpaper = async function (path) { + const args = ["-type", "wallpaper", "-path", path]; + const result = await runCsharpFeature("utils", args); + if (result && result.startsWith("Error:")) { + throw new Error(result.substring(7)); + } + return true; +}; + +/** + * 控制显示器 + * @param {string} action 动作:on/off + * @returns {boolean} 是否成功 + */ +const controlMonitor = async function (action) { + const args = ["-type", "monitor", "-action", action]; + const result = await runCsharpFeature("utils", args); + if (result && result.startsWith("Error:")) { + throw new Error(result.substring(7)); + } + return true; +}; + +/** + * 电源控制 + * @param {string} mode 模式:sleep/hibernate/awake/normal + * @returns {boolean} 是否成功 + */ +const powerControl = async function (mode) { + const args = ["-type", "power", "-mode", mode]; + const result = await runCsharpFeature("utils", args); + if (result && result.startsWith("Error:")) { + throw new Error(result.substring(7)); + } + return true; +}; + +/** + * 配置网络 + * @param {string} interfaceName 网卡名称 + * @param {string} ip IP地址 + * @param {string} mask 子网掩码 + * @param {string} gateway 网关 + * @param {string} dns DNS服务器 + * @returns {boolean} 是否成功 + */ +const configureNetwork = async function ( + interfaceName, + ip, + mask, + gateway = "", + dns = "" +) { + const args = [ + "-type", + "network", + "-interface", + interfaceName, + "-ip", + ip, + "-mask", + mask, + ]; + if (gateway) args.push("-gateway", gateway); + if (dns) args.push("-dns", dns); + + const result = await runCsharpFeature("utils", args); + if (result && result.startsWith("Error:")) { + throw new Error(result.substring(7)); + } + return true; +}; + +/** + * 管理开机启动项 + * @param {string} path 程序路径 + * @param {string} name 启动项名称 + * @param {boolean} remove 是否移除 + * @returns {boolean} 是否成功 + */ +const manageStartup = async function (path, name, remove = false) { + const args = ["-type", "startup", "-path", path, "-name", name]; + if (remove) args.push("-remove"); + + const result = await runCsharpFeature("utils", args); + if (result && result.startsWith("Error:")) { + throw new Error(result.substring(7)); + } + return true; +}; + +/** + * 创建快捷方式 + * @param {string} targetPath 目标路径 + * @param {string} shortcutPath 快捷方式路径 + * @param {string} args 启动参数 + * @returns {boolean} 是否成功 + */ +const createShortcut = async function (targetPath, shortcutPath, args = "") { + const cmdArgs = [ + "-type", + "shortcut", + "-target", + targetPath, + "-path", + shortcutPath, + ]; + if (args) cmdArgs.push("-args", args); + + const result = await runCsharpFeature("utils", args); + if (result && result.startsWith("Error:")) { + throw new Error(result.substring(7)); + } + return true; +}; + +/** + * 设置亮度 + * @param {number} level 亮度级别(0-100) + * @returns {boolean} 是否成功 + */ +const setBrightness = async function (level) { + const args = ["-type", "brightness", "-level", level.toString()]; + const result = await runCsharpFeature("utils", args); + if (result && result.startsWith("Error:")) { + throw new Error(result.substring(7)); + } + return true; +}; + +module.exports = { + setWallpaper, + controlMonitor, + powerControl, + configureNetwork, + manageStartup, + createShortcut, + setBrightness, +}; diff --git a/src/js/composer/commands/windowsCommands.js b/src/js/composer/commands/windowsCommands.js index 1d288ce..be218f0 100644 --- a/src/js/composer/commands/windowsCommands.js +++ b/src/js/composer/commands/windowsCommands.js @@ -45,6 +45,65 @@ const controlClass = [ { value: "GroupBox", label: "分组框 (GroupBox)" }, ]; +const registryPaths = [ + // 系统设置 + { + value: "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion", + label: "Windows设置", + }, + { value: "HKLM\\SYSTEM\\CurrentControlSet\\Control", label: "系统控制" }, + { + value: "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", + label: "Windows NT设置", + }, + + // 启动项 + { + value: "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", + label: "系统启动项", + }, + { + value: "HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", + label: "用户启动项", + }, + + // 软件设置 + { + value: "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall", + label: "已安装软件(64位)", + }, + { + value: + "HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall", + label: "已安装软件(32位)", + }, + + // 文件关联 + { value: "HKLM\\SOFTWARE\\Classes", label: "系统文件关联" }, + { value: "HKCU\\SOFTWARE\\Classes", label: "用户文件关联" }, + + // 服务 + { value: "HKLM\\SYSTEM\\CurrentControlSet\\Services", label: "系统服务" }, + + // 环境变量 + { + value: + "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", + label: "系统环境变量", + }, + { value: "HKCU\\Environment", label: "用户环境变量" }, + + // 网络设置 + { + value: "HKLM\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", + label: "TCP/IP设置", + }, + { + value: "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList", + label: "网络配置", + }, +]; + export const windowsCommands = { label: "Win自动化", icon: "window", @@ -520,5 +579,523 @@ export const windowsCommands = { }, ], }, + { + value: "quickcomposer.windows.process.listProcesses", + label: "进程管理", + desc: "Windows进程操作", + icon: "memory", + isAsync: true, + subCommands: [ + { + value: "quickcomposer.windows.process.listProcesses", + label: "进程列表", + icon: "list", + outputVariable: "processList", + saveOutput: true, + }, + { + value: "quickcomposer.windows.process.killProcess", + label: "终止进程", + icon: "stop_circle", + config: [ + { + key: "target", + label: "进程ID/名称", + component: "VariableInput", + icon: "tag", + width: 12, + placeholder: "输入进程ID或名称", + required: true, + }, + ], + }, + { + value: "quickcomposer.windows.process.startProcess", + label: "启动进程", + icon: "play_circle", + config: [ + { + key: "path", + label: "程序路径", + component: "VariableInput", + icon: "folder", + width: 12, + options: { + dialog: { + type: "open", + options: { + title: "选择程序", + filters: [ + { name: "可执行文件", extensions: ["exe"] }, + { name: "所有文件", extensions: ["*"] }, + ], + }, + }, + }, + required: true, + }, + { + key: "arguments", + label: "启动参数", + component: "VariableInput", + icon: "code", + width: 12, + placeholder: "可选的启动参数", + }, + ], + }, + ], + }, + { + value: "quickcomposer.windows.registry.listKeys", + label: "注册表管理", + desc: "Windows注册表操作", + icon: "settings", + isAsync: true, + config: [ + { + key: "path", + label: "注册表路径", + component: "VariableInput", + icon: "folder", + width: 12, + placeholder: "如: HKLM\\SOFTWARE\\Microsoft\\Windows", + options: { + items: registryPaths, + }, + required: true, + }, + ], + subCommands: [ + { + value: "quickcomposer.windows.registry.listKeys", + label: "列出项", + icon: "list", + outputVariable: "registryKeys", + saveOutput: true, + }, + { + value: "quickcomposer.windows.registry.getValue", + label: "获取值", + icon: "search", + config: [ + { + key: "path", + label: "注册表路径", + component: "VariableInput", + icon: "folder", + width: 12, + placeholder: "如: HKLM\\SOFTWARE\\Microsoft\\Windows", + options: { + items: registryPaths, + }, + required: true, + }, + { + key: "name", + label: "值名称", + component: "VariableInput", + icon: "label", + width: 12, + placeholder: "要获取的值名称", + }, + ], + outputVariable: "registryValue", + saveOutput: true, + }, + { + value: "quickcomposer.windows.registry.setValue", + label: "设置值", + icon: "edit", + config: [ + { + key: "path", + label: "注册表路径", + component: "VariableInput", + icon: "folder", + width: 12, + placeholder: "如: HKLM\\SOFTWARE\\Microsoft\\Windows", + options: { + items: registryPaths, + }, + required: true, + }, + { + key: "name", + label: "值名称", + component: "VariableInput", + icon: "label", + width: 12, + placeholder: "要设置的值名称", + required: true, + }, + { + key: "value", + label: "值内容", + component: "VariableInput", + icon: "text_fields", + width: 8, + required: true, + }, + { + key: "valueType", + label: "值类型", + component: "q-select", + icon: "category", + width: 4, + options: [ + { label: "字符串", value: "string" }, + { label: "可扩展字符串", value: "expandstring" }, + { label: "二进制", value: "binary" }, + { label: "DWORD", value: "dword" }, + { label: "QWORD", value: "qword" }, + { label: "多字符串", value: "multistring" }, + ], + defaultValue: "string", + }, + ], + }, + { + value: "quickcomposer.windows.registry.deleteValue", + label: "删除值", + icon: "delete", + config: [ + { + key: "path", + label: "注册表路径", + component: "VariableInput", + icon: "folder", + width: 12, + placeholder: "如: HKLM\\SOFTWARE\\Microsoft\\Windows", + options: { + items: registryPaths, + }, + required: true, + }, + { + key: "name", + label: "值名称", + component: "VariableInput", + icon: "label", + width: 12, + placeholder: "要删除的值名称(留空删除整个项)", + }, + ], + }, + ], + }, + { + value: "quickcomposer.windows.service.listServices", + label: "服务管理", + desc: "Windows服务操作", + icon: "miscellaneous_services", + isAsync: true, + subCommands: [ + { + value: "quickcomposer.windows.service.listServices", + label: "服务列表", + icon: "list", + outputVariable: "serviceList", + saveOutput: true, + }, + { + value: "quickcomposer.windows.service.controlService", + label: "控制服务", + icon: "settings", + config: [ + { + key: "name", + label: "服务名称", + component: "VariableInput", + icon: "label", + width: 12, + placeholder: "输入服务名称", + required: true, + }, + { + key: "operation", + label: "操作", + component: "ButtonGroup", + icon: "play_circle", + width: 12, + options: [ + { label: "启动", value: "start" }, + { label: "停止", value: "stop" }, + { label: "暂停", value: "pause" }, + { label: "继续", value: "continue" }, + ], + defaultValue: "start", + }, + ], + }, + ], + }, + { + value: "quickcomposer.windows.software.listSoftware", + label: "软件管理", + desc: "Windows软件操作", + icon: "apps", + isAsync: true, + subCommands: [ + { + value: "quickcomposer.windows.software.listSoftware", + label: "软件列表", + icon: "list", + outputVariable: "softwareList", + saveOutput: true, + }, + { + value: "quickcomposer.windows.software.uninstallSoftware", + label: "卸载软件", + icon: "delete", + config: [ + { + key: "target", + label: "软件ID", + component: "VariableInput", + icon: "tag", + width: 12, + placeholder: "输入软件ID(从软件列表获取)", + required: true, + }, + ], + }, + ], + }, + { + value: "quickcomposer.windows.utils.setWallpaper", + label: "系统工具", + desc: "Windows系统工具", + icon: "build", + isAsync: true, + subCommands: [ + { + value: "quickcomposer.windows.utils.setWallpaper", + label: "设置壁纸", + icon: "wallpaper", + config: [ + { + key: "path", + label: "壁纸路径", + component: "VariableInput", + icon: "image", + width: 12, + options: { + dialog: { + type: "open", + options: { + title: "选择壁纸", + filters: [ + { + name: "图片文件", + extensions: ["jpg", "jpeg", "png", "bmp"], + }, + ], + }, + }, + }, + required: true, + }, + ], + }, + { + value: "quickcomposer.windows.utils.controlMonitor", + label: "控制显示器", + icon: "desktop_windows", + config: [ + { + key: "action", + component: "ButtonGroup", + icon: "power_settings_new", + width: 12, + options: [ + { label: "开启", value: "on" }, + { label: "关闭", value: "off" }, + ], + defaultValue: "off", + }, + ], + }, + { + value: "quickcomposer.windows.utils.powerControl", + label: "电源控制", + icon: "power", + config: [ + { + key: "mode", + component: "ButtonGroup", + icon: "power_settings_new", + width: 12, + options: [ + { label: "睡眠", value: "sleep" }, + { label: "休眠", value: "hibernate" }, + { label: "保持唤醒", value: "awake" }, + { label: "正常", value: "normal" }, + ], + defaultValue: "sleep", + }, + ], + }, + { + value: "quickcomposer.windows.utils.configureNetwork", + label: "配置网络", + icon: "network_check", + config: [ + { + key: "interfaceName", + label: "网卡名称", + component: "VariableInput", + icon: "settings_ethernet", + width: 12, + placeholder: "输入网卡名称", + required: true, + }, + { + key: "ip", + label: "IP地址", + component: "VariableInput", + icon: "router", + width: 6, + placeholder: "如: 192.168.1.100", + required: true, + }, + { + key: "mask", + label: "子网掩码", + component: "VariableInput", + icon: "filter_alt", + width: 6, + placeholder: "如: 255.255.255.0", + required: true, + }, + { + key: "gateway", + label: "默认网关", + component: "VariableInput", + icon: "dns", + width: 6, + placeholder: "可选", + }, + { + key: "dns", + label: "DNS服务器", + component: "VariableInput", + icon: "dns", + width: 6, + placeholder: "可选", + }, + ], + }, + { + value: "quickcomposer.windows.utils.manageStartup", + label: "开机启动项", + icon: "power", + config: [ + { + key: "path", + label: "程序路径", + component: "VariableInput", + icon: "folder", + width: 12, + options: { + dialog: { + type: "open", + options: { + title: "选择程序", + filters: [ + { name: "可执行文件", extensions: ["exe"] }, + { name: "所有文件", extensions: ["*"] }, + ], + }, + }, + }, + required: true, + }, + { + key: "name", + label: "启动项名称", + component: "VariableInput", + icon: "label", + width: 8, + required: true, + }, + { + key: "remove", + label: "移除", + component: "CheckButton", + icon: "delete", + width: 4, + }, + ], + }, + { + value: "quickcomposer.windows.utils.createShortcut", + label: "创建快捷方式", + icon: "link", + config: [ + { + key: "targetPath", + label: "目标路径", + component: "VariableInput", + icon: "folder", + width: 12, + options: { + dialog: { + type: "open", + options: { + title: "选择目标", + filters: [{ name: "所有文件", extensions: ["*"] }], + }, + }, + }, + required: true, + }, + { + key: "shortcutPath", + label: "快捷方式路径", + component: "VariableInput", + icon: "save", + width: 12, + options: { + dialog: { + type: "save", + options: { + title: "保存快捷方式", + filters: [{ name: "快捷方式", extensions: ["lnk"] }], + }, + }, + }, + required: true, + }, + { + key: "args", + label: "启动参数", + component: "VariableInput", + icon: "code", + width: 12, + placeholder: "可选的启动参数", + }, + ], + }, + { + value: "quickcomposer.windows.utils.setBrightness", + label: "设置亮度", + icon: "brightness_medium", + config: [ + { + key: "level", + label: "亮度级别", + component: "NumberInput", + icon: "brightness_medium", + width: 12, + min: 0, + max: 100, + defaultValue: 50, + required: true, + }, + ], + }, + ], + }, ], };