GTweak 的 CommandExecutor:6 个入口如何静默驱动数十项 Windows 优化按钮
【免费下载链接】GTweakPortable Tool for an Ideal Windows Setup项目地址: https://gitcode.com/GitHub_Trending/gt/GTweak
在 GTweak 里勾选"清理临时文件"后,后台其实有一长串 cmd 命令正以系统最高权限身份悄悄执行,全程没有黑框弹窗打扰你——这就是命令执行器 CommandExecutor 的功劳。它把启动进程、捕获输出、权限提升这些脏活收进一个仅 185 行的文件,为项目里每个功能按钮提供统一通道。
⚠️ 点击 GTweak 按钮后,底层发生了什么
在维护页点一下"清理",程序先通过原生接口清空各进程的内存工作集,再把一长串rd/del命令交给执行器,由它在 TrustedInstaller 身份下拉起隐藏子进程完成删除。假如每个功能都自己手写这套流程,问题会很快堆积:
| 自己实现时会遇到的坑 | 统一收口后的变化 |
|---|---|
| 近 20 个源文件各写一遍"启动进程、读输出"样板,行为难以一致 | 全部走同一组 6 个入口,新功能只管挑方法 |
| 黑框弹窗时隐时现,有的功能要提权、有的不要 | 隐藏窗口与 UAC 策略由执行器统一决定 |
| 单条命令失败就抛异常,卡死 UI | 异常统一吞掉并交给 ErrorLogger,一次失败不扩散 |
一句话定位:所有命令的调度台
它像一个餐厅的调度台。服务员(各个功能模块)只需报一句话:哪道菜、要热还是冷、要不要专用灶台——也就是哪条命令、隐藏还是可见、要不要提权。至于用哪个解释器(cmd或 PowerShell)、要不要显示窗口、要不要请求 UAC,都由 CommandExecutor.cs 自行裁决,功能代码从头到尾碰不到System.Diagnostics.Process类。
入口怎么选:6 个方法一张表讲清
6 个执行入口按"执行方式"划分,选型时只看两个维度:要不要看输出、要不要提权或可见。
| 使用场景 | 入口方法 | 关键特征 |
|---|---|---|
| 需要拿到命令的文本输出 | GetCommandOutput | 隐藏窗口并等待退出,退出码非 0 时返回空字符串 |
| 发出去就不用管 | RunCommand | Verb设为runas,权限不足时请求 UAC,不取结果 |
| 删除受保护的深层文件 | RunCommandAsTrustedInstaller | 借权限最高的 TrustedInstaller 服务身份执行 |
| 用户需要看到过程 | InvokeRunVisibleProcess | 可见窗口,必要时切换到 TrustedInstaller 通道 |
| 下一步依赖这一步的结果 | InvokeRunCommand | 隐藏窗口加await等退出,适合串联流程 |
| 命令里特殊字符太多 | RunEncodedPowerShell | 先转 Base64 再交给-EncodedCommand,绕开引号地狱 |
除 6 个入口外,还有异步等待扩展方法WaitForExitAsync和清洗工具CleanCommand,后文再说。
主线走查:一条命令如何以 TrustedInstaller 身份跑起来
以 MemoryCleaner.cs 清理临时文件为例,完整过程分四步。
- 把命令交给通道。
MemoryCleaner把一长串rd/del命令交给RunCommandAsTrustedInstaller,调用方立刻返回,真正的执行发生在后台。 - 确认"执行身份"存活。执行器把缓存的服务进程号(静态字段
PID,初始为 0)传给TrustedInstaller.CreateProcessAsTrustedInstaller;发现服务没起,就先调StartTrustedInstallerService:内部通过RunCommand执行sc config/sc start,再用系统 P/Invoke 接口轮询服务状态,最长等 30 秒,Running 后把进程号写回PID。 - 临时借用 SYSTEM 身份。
ImpersonateSystem开启SeDebugPrivilege与SeImpersonatePrivilege两个特权,仿冒当前会话 winlogon 进程的令牌,短暂获得以 SYSTEM 身份拉进程的权利。 - 以正确的名义拉子进程。通过
PROC_THREAD_ATTRIBUTE_PARENT_PROCESS属性把子进程的父进程指定为 TrustedInstaller 服务进程,命令就"名正言顺"地以 TrustedInstaller 名义运行;结束后RevertToSelf()恢复原身份,全程失败最多重试 3 次。完整实现在 TrustedInstaller.cs。
PID字段的作用容易看漏:它是一根接力棒,写入之后任何通道都能复用已启动的服务,不必再走一遍 30 秒轮询。
两个不显眼的细节 💡
- 非阻塞等待
WaitForExitAsync。.NET Framework 时代的Process没有原生异步等待,这里用TaskCompletionSource(任务完成包装器)加Exited事件实现,完成后自动解绑事件,GetCommandOutput/InvokeRunCommand才能await而不卡死 WPF 界面线程。 - 多行参数压平
CleanCommand。用户写的脚本参数常带换行和多余空格,CleanCommand按行拆分、压缩连续空白,再自动选&&或&作分隔符合并,多行命令就不会拼接变形。
换个场景验证:GTweak 自定义脚本如何跑通
把.ps1、.bat、.cmd、.reg放进指定目录,点击运行,AddonsViewModel.cs 的链路是:
- 按扩展名映射解释器:
.reg→reg.exe import;.ps1→ PowerShell 加-ExecutionPolicy Bypass;其余 → cmd 的/k模式(窗口保留,输出可见)。 - 参数先经
CleanCommand压平,再交给InvokeRunVisibleProcess。 - 若脚本标记"需要管理员",
InvokeRunVisibleProcess内部改走 TrustedInstaller 通道,完整复用上面四步提权链。
这个类是货真价实的项目级公共设施:激活模块 WinLicenseHandler.cs 的组合更花——Win10 下先借RunCommandAsTrustedInstaller修复.vbs关联,awaitInvokeRunCommand跑slmgr.vbs装密钥,RunCommand发出去就删旧票据,最后GetCommandOutput读回激活结果;MemoryCleaner、ServicesTweaks、ErrorLogger等近 20 个源文件引用的都是同一组方法。
能带走的三条工程习惯 ✅
- 先定义"执行契约"再写功能。把 隐藏/可见、同步/异步、普通/提权 组合成有限入口,功能只挑方法,谁也不在业务代码里 new 进程对象。
- 旧 API 异步化有固定套路。
TaskCompletionSource加事件回调,记得在续用里解绑事件,这一招对任何回调式 API 都适用。 - 给所有异常留落脚点。每个方法用 try/catch 包住并交给 ErrorLogger 记录,单条命令失败只留日志,不拖垮界面。
下次再点 GTweak 的"清理"按钮,别只把它当按钮:服务存活检查、借身份、静默执行、失败留痕,全都由这个调度台办妥。你以后做"按钮多、命令多"的工具时,不妨先造这么一条统一通道。
【免费下载链接】GTweakPortable Tool for an Ideal Windows Setup项目地址: https://gitcode.com/GitHub_Trending/gt/GTweak
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考