PowerToys Run Value Generator 插件解析:一行命令完成哈希、Base64、GUID 与 URL 编解码
2026/9/7 4:13:49 网站建设 项目流程

PowerToys Run Value Generator 插件解析:一行命令完成哈希、Base64、GUID 与 URL 编解码

【免费下载链接】PowerToysMicrosoft PowerToys is a collection of utilities that supercharge productivity and customization on Windows项目地址: https://gitcode.com/GitHub_Trending/po/PowerToys

本文以 PowerToys 官方开发文档 Value Generator 插件说明 为主体,完整梳理 Value Generator 插件支持的 18 个查询命令、IComputeRequest计算请求契约、查询解析规则与错误处理约定,并深入 InputParser.cs、GUIDGenerator.cs、HashRequest.cs 等源码,还原每个命令背后的实际 API 调用链,最终给出扩展新生成器的完整步骤。读完后你可以直接使用全部命令,也能按仓库约定为插件新增自己的生成器。

插件定位与基本用法

Value Generator 是 PowerToys Run(launcher)内置的社区插件,用于对字符串做哈希、计算 Base64 编解码、对 URL/URI 进行转义与反转义、生成版本 1/3/4/5/7 的 GUID。插件源码位于 Community.PowerToys.Run.Plugin.ValueGenerator 目录,其 plugin.json 声明了:

  • ActionKeyword#,即在 PowerToys Run 查询框中输入#加空格即可触发该插件的命令补全;
  • ExecuteFileNameCommunity.PowerToys.Run.Plugin.ValueGenerator.dll,插件以独立 DLL 形式由 launcher 加载;
  • isGlobalfalse,仅通过#关键字激活。

插件入口 Main.cs 实现IPlugin, IPluginI18n, IDisposable,其Query()方法把用户输入交给InputParser.ParseInput()得到计算请求对象,再调用Compute()生成Result。每条结果以固定Score = 300展示,点击后在 STA 线程中调用Clipboard.SetText(request.ResultToString())将结果复制到剪贴板;仅当命令正确而参数有误(ArgumentException)时才展示带警告图标的错误条目,标题取自资源文件中的Value Generator Error(见 Resources.resx)。

支持的命令一览

QueryHelper.cs 中的GeneratorDataList完整枚举了插件暴露的全部关键字、说明与示例,这是插件在#空查询时展示的建议列表来源。逐条对应如下(示例直接取自源码):

关键字功能示例(源码原文)
uuid/guid生成随机 UUID(默认版本 4)uuidguid
uuidv1生成版本 1:基于时间的 UUIDuuidv1uuid1
uuidv3版本 3(MD5):基于命名空间和名称的 UUIDuuidv3 ns:<DNS, URL, OID, 或 X500> <your input>
uuidv4版本 4:随机生成的 UUIDuuidv4uuid4
uuidv5版本 5(SHA1):基于命名空间和名称的 UUIDuuidv5 ns:<DNS, URL, OID, 或 X500> <your input>
uuidv7版本 7:按时间排序的随机 UUIDuuidv7uuid7
md5MD5 哈希md5 <your input>
sha1SHA1 哈希sha1 <your input>
sha256SHA256 哈希sha256 <your input>
sha384SHA384 哈希sha384 <your input>
sha512SHA512 哈希sha512 <your input>
base64Base64 编码字符串base64 <your input>
base64dBase64 解码字符串base64d <your input>
urlURL 编码url https://bing.com/?q=My Test query
urldURL 解码urld https://bing.com/?q=My+Test+query
esc:data数据串转义(Uri.EscapeDataStringesc:data C:\Program Files\PowerToys\PowerToys.exe
uesc:data数据串反转义uesc:data C%3A%5CProgram%20Files%5CPowerToys%5CPowerToys.exe
esc:hex单个字符的十六进制转义esc:hex z
uesc:hex单个十六进制转义字符还原uesc:hex %7A

几个使用细节值得注意:

  • 所有命令前必须带#前缀(如# md5 hello),否则不会路由到本插件;
  • 哈希、Base64 等命令的参数是取关键字之后的原始查询串RawUserQuery.Substring(commandIndex + command.Length)),因此参数中的空格会被完整保留并参与计算;
  • guiduuid的别名,输入guidguidv1guidv3等均按相同逻辑解析(截图示例即为# guidv3 ns:DNS www.microsoft.com)。

核心契约:IComputeRequest 接口

插件的抽象核心是 IComputeRequest.cs,每个具体生成器都必须实现该接口:

  • bool Compute():执行计算,必须填充IsSuccessful以及ResultErrorMessage中的一个;
  • string ResultToString():返回结果的可读文本,直接用作结果条目的标题(Title);
  • string Description:用作结果条目的副标题(Subtitle),例如哈希请求的SHA256(原始字符串)
  • byte[] Result:计算结果的原始字节。

Main.GetResult()(Main.cs)把request.Result存入ContextDataResultToString()作为标题、Description作为副标题,并在点击动作里复制ResultToString()的输出。这个“解析 → 请求对象 → Compute → Result”的三段式结构,是理解各生成器实现的关键。

InputParser:查询解析规则与错误约定

InputParser.cs 唯一职责是解析用户查询,ParseInput()要么返回一个IComputeRequest实例,要么抛出FormatExceptionArgumentException。原文档对此的错误语义约定非常重要,源码中也能逐条印证:

  • ArgumentException表示用户可修正的输入错误(如不支持的哈希函数、无效 GUID 版本、无效命名空间),其消息会直接展示给用户,且不写日志。例如 Main.cs 捕获ArgumentException后调用GetErrorResult(e.Message),生成带警告图标的错误条目;
  • FormatException表示“查询可能变有效”或“彻底无效”(如还没输入内容、哈希命令后还没有要跟字符串),此时不向用户显示错误,只写一条 Debug 日志。从 Main.cs 可以看到,捕获FormatException后仅Log.Debug(...),若当前是通过#动作关键字进入,还会退化为模糊匹配关键字的建议列表(GetSuggestionFuzzyResults),所以输入# md时不会弹错误,而是继续给出md5等候选项。

具体解析分支(对照 InputParser.cs 源码):

  • md5:精确匹配,参数为空时抛FormatException("Empty hash request")
  • sha*:前缀匹配后按command.Substring(3)分支为1/256/384/512,其余抛出FormatException,提示支持变体为 SHA1、SHA256、SHA384、SHA512;
  • guid*/uuid*:版本默认 4;取command第 5 个字符起的内容(guid/uuid之后),若以v开头则去掉,再int.TryParse得到版本号,解析失败抛FormatException,提示支持的版本为 1、3、4、5、7。版本 3/5 时要求恰好两个参数(命名空间 + 名称),参数个数不对时抛ArgumentException并给出示例uuidv{version} ns:<DNS, URL, OID, or X500> <your input>
  • esc:/uesc:前缀分别进入转义与反转义分支,仅接受esc:dataesc:hexuesc:datauesc:hex四种精确关键字,其余形式抛FormatException。其中esc:hex要求输入恰好 1 个字符(超过 1 个字符抛ArgumentException,为空抛FormatException);
  • 其余未识别输入统一抛FormatException($"Invalid Query: {query.RawUserQuery}")

哈希生成器:HashRequest

HashRequest.cs 实现IComputeRequest,支持System.Security.Cryptography中的 MD5、SHA1、SHA256、SHA384、SHA512。其内部_algorithms字典(HashRequest.cs)静态缓存了各算法的HashAlgorithm实例,Compute()直接调用_algorithms[AlgorithmName].ComputeHash(DataToHash)。文档中给出的扩展提示与源码一致:若未来System.Security.Cryptography增加新的算法,只需向_algorithms字典注册,并让InputParser.ParseInput()能对该关键字返回HashRequest

两个实现细节:

  • ResultToString()将结果字节逐字节格式化为大写十六进制(b.ToString("X2"))拼接,因此结果是大写Hex 字符串;
  • Description动态生成算法名(原始输入),例如SHA256(hello),作为结果副标题展示;
  • 构造函数对dataToHash做空引用检查;Compute()中若DataToHash为 null 会记录异常日志并置IsSuccessful = false,错误信息为Null data passed to hash request

哈希输入统一按 UTF-8 编码为字节(Encoding.UTF8.GetBytes(content),见 InputParser.cs),即命令参数以什么字节序列进入算法是明确且可预期的。

Base64 编解码

Base64Request.cs 与 Base64DecodeRequest.cs 分别处理base64base64d

  • Base64Request的构造函数接收字节数组(由InputParserEncoding.UTF8.GetBytes(content)传入),Compute()调用System.Convert.ToBase64String得到编码串;
  • Base64DecodeRequest的构造函数接收字符串Compute()调用System.Convert.FromBase64String得到解码后的字节数组,ResultToString()再按 UTF-8 还原为文本。

两者的共同模式是:Compute()内 try/catch 包裹,异常时通过Log.Exception记录、填充ErrorMessage并置IsSuccessful = false;解码失败(如非法 Base64 串)时结果标题会展示 .NET 的原始异常消息。

GUID 生成器:五个版本与命名空间

GUIDRequest.cs 实现IComputeRequest,通过 GUIDGenerator.cs 这个工具类实际生成或计算 GUID。各版本的底层来源与源码逐一对应:

  • 版本 1(时间基准)V1()调用 Win32 APIUuidCreateSequential(经NativeMethods.UuidCreateSequentialP/Invoke),返回码为RPC_S_OKRPC_S_UUID_LOCAL_ONLY均视为成功,否则抛InvalidOperationException("Failed to create GUID version 1")
  • 版本 4(随机)V4()直接调用System.Guid.NewGuid()
  • 版本 7(时间有序)V7()调用 .NET 8 引入的System.Guid.CreateVersion7()
  • 版本 3/5(命名空间 + 名称)V3AndV5()(GUIDGenerator.cs)按 RFC 4122 手工实现——先把命名空间 GUID 的time_lowtime_midtime_hi_and_version三个字段转为网络字节序,拼接名称的 ASCII 字节后,版本 3 用MD5.HashData、版本 5 用SHA1.HashData取前 16 字节,再将版本号按time_hi_and_version &= 0x0FFF; | (version << 12)写入,并将第 9 字节高两位置为10(变体位)后构造Guid。源码中对 MD5/SHA1 的使用以#pragma warning disable CA5351/CA5350显式压制了“弱算法”告警——这是规范要求的,而非性能取舍。

命名空间参数规则(与文档一致):命名空间必须是一个合法 GUID,或是 GUIDGenerator.cs 中PredefinedNamespaces字典提供的 RFC 4122 附录 C 预定义命名空间别名:

别名预定义 GUID
ns:dns6ba7b810-9dad-11d1-80b4-00c04fd430c8
ns:url6ba7b811-9dad-11d1-80b4-00c04fd430c8
ns:oid6ba7b812-9dad-11d1-80b4-00c04fd430c8
ns:x5006ba7b814-9dad-11d1-80b4-00c04fd430c8

GUIDRequest.cs 的构造函数做了三重校验:

  1. 版本必须是 1、3、4、5、7 之一(2 和 6 明确不支持,Version is < 1 or > 7 or 2 or 6时抛ArgumentException);
  2. 版本 3/5 时命名空间不能为 null,且先按小写字符串查PredefinedNamespaces,查不到再尝试Guid.TryParse,两者都失败时抛ArgumentNullException,消息列出所有可用别名;
  3. 版本 3/5 时名称(name)不能为 null。

Description属性按版本返回不同副标题,如Version 3 (SHA1 算法名): Namespace and name based GUID.Version 7: Time-ordered randomly generated GUID等,这些正是结果列表第二行显示的内容(截图中的Version 3 (MDS): Namespace and name based GUID.即此输出)。

URI 转义与反转义

Generators/Uri目录下六个请求类分别对应六个命令,底层 API 与 InputParser.cs 的分发一一对应:

类文件命令底层 API说明
UrlEncodeRequest.csurlHttpUtility.UrlEncode()整个 URL 编码,空格变+
UrlDecodeRequest.csurldHttpUtility.UrlDecode()整个 URL 解码
DataEscapeRequest.csesc:dataSystem.Uri.EscapeDataString()数据串转义,空格变%20
DataUnescapeRequest.csuesc:dataSystem.Uri.UnescapeDataString()数据串反转义
HexEscapeRequest.csesc:hexSystem.Uri.HexEscape()仅支持单字符输入,构造函数对长度不为 1 的输入抛ArgumentOutOfRangeException
HexUnescapeRequest.csuesc:hexSystem.Uri.HexUnescape()只还原字符串开头第一个十六进制转义序列(先Uri.IsHexEncoding探测,再HexUnescape),用户输入其余部分被忽略

urlesc:data的差别在于HttpUtility.UrlEncode面向完整 URL(空格 →+),而Uri.EscapeDataString面向单个数据分量(空格 →%20);esc:hex/uesc:hex则是最细粒度的单字符%XX转义对。四个类的错误处理模式与 Base64 一致:异常时记日志、填ErrorMessageResult保持 null,此时ResultToString()返回空串,结果条目因标题为空不会被加入(见 Main.cs 中对Title为空时直接返回空列表的处理)。

建议列表与模糊匹配:Main 层的两个辅助路径

除了主计算路径,Main.cs 还有两条展示路径,理解它们能解释插件的实际交互行为:

  1. 空查询建议:当Search为空但ActionKeyword存在(即刚输入#)时,GetSuggestionResults()遍历 QueryHelper.GeneratorDataList 生成全部 18 条关键字建议,点击后通过_context.API.ChangeQuery($"{query.ActionKeyword} {generatorData.Keyword} ", true)直接把关键字写入查询框;
  2. 模糊建议:解析出FormatException且带ActionKeyword时,GetSuggestionFuzzyResults()StringMatcher.FuzzySearch对输入做模糊打分,把得分大于 0 的关键字作为候选返回。

这正是“FormatException不直接报错”约定的产品意义:输入过程中的中间态(如# md)永远展示候选而非错误,只有ArgumentException这类确定的用户错误才呈现警告条目。

如何为插件新增一个生成器

原文档给出的三步扩展流程,与源码结构完全对应,可按此操作(在自己的 fork/本地环境中进行,本仓库只读):

  1. 在 Generators/ 目录下新建文件夹(与HashingBase64GUIDUri并列),在其中实现IComputeRequest接口的请求类,Compute()负责填充IsSuccessfulResultErrorMessage
  2. 新生成器私有的工具类放在同一文件夹内,与其他生成器隔离——可参照GUID文件夹中GUIDGeneratorGUIDRequest的分工:工具类负责纯计算,*Request类负责对接接口契约;
  3. 修改 InputParser.ParseInput(),为新关键字增加分支并返回第 1 步创建的实例。同时注意遵守前文错误约定:用户可修正的错误抛ArgumentException(会展示给用户),中间态/无效查询抛FormatException(只记日志)。若希望新命令出现在#建议列表与模糊匹配中,还应向 QueryHelper.GeneratorDataList 追加一条GeneratorData(关键字、描述、示例),并在 Resources.resx 中提供可本地化的描述资源。

小结

Value Generator 插件用一套极简的IComputeRequest契约 + 一个InputParser分发器,把哈希、Base64、GUID、URL 四类共 18 个命令收敛在数百行代码内:解析层严格区分“可修正错误”与“中间态”两种异常语义,计算层各请求类只关心填充Result/ErrorMessage,展示层统一由 Main.cs 负责标题、副标题与剪贴板复制。所有行为均可在源码中逐条验证,扩展新生成器也只需要遵循“新建 Generator 文件夹 → 实现接口 → 注册解析分支”三步约定。

【免费下载链接】PowerToysMicrosoft PowerToys is a collection of utilities that supercharge productivity and customization on Windows项目地址: https://gitcode.com/GitHub_Trending/po/PowerToys

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询