﻿══════════════════════════════════════════════════════
  蒸鱼清理 · 使用说明
  一键把电脑恢复到刚开机的清爽状态
══════════════════════════════════════════════════════


【只有一个程序】

  双击  蒸鱼清理.exe  就行。所有功能都收在这一个程序里，
  不会再有一堆小 exe 让你分辨。

  · 双击后会弹一次 UAC（管理员权限），点「是」。
    系统缓存和后台程序需要管理员权限才关得掉。
  · 全程不会出现黑色命令行窗口，桌面上干干净净。
  · 图标是一个蓝色圆角方块，里面一个白色的大写 Z 和一把斜着的小扫帚
    （合起来正好是「蒸鱼」的拼音首字母 ZY），右边还有几颗小星星 ——
    exe、窗口、任务栏、桌面挂件、开始菜单快捷方式用的都是这一张。
  · 窗口顶栏左上角「蒸鱼清理」四个字的右边，还跟着一个同款小图标，
    用的是同一张图，所以换图标的时候它会一起变。
  · 这是一个**单文件**程序：主程序、桌面挂件、图标全都打包在 exe 里面，
    可以单独把它拖到桌面、U 盘或任意文件夹，双击就能用，
    不需要旁边陪着别的文件。


【只有一扇窗，上面四个页签】

  整个程序从头到尾只有一扇窗。蓝色顶栏下面那一排是四个页签：

      后台清理      ← 平时那个主界面（清理项目 / 应用开关 / 日志）
      软件管理      ← 装了哪些软件；缓存、开机自启、卸载都在这儿
      C 盘清理      ← 系统临时文件 + 最占地方的文件
      我的设备      ← 这台电脑的硬件和外设清单（CPU / 显卡 / 主板 / 硬盘…）

  顶栏左上角是程序名「蒸鱼清理」，名字右边跟着一个小图标
  （和 exe、任务栏图标是同一张图）。

  点一下就换页，跟浏览器切标签一样，位置大小都还在原地，
  不会另开一个窗口、也不会两个窗口叠在一起。
  换页只换内容：不管是哪一页，窗口本身都是同一扇。

  顶栏右边三个按钮：— 最小化、□ 放大/还原、✕ 关闭。
  三个都是程序自己画的（不是字体里的那几个符号），大小、间距、线条粗细
  完全一致。鼠标移上去会浮出一块浅色圆角底，关闭那个的底色会变红。
  点「□」放大之后，它自己会变成两个小方块叠在一起的「还原」样子，
  再点一下回到原来的大小。

  窗口可以随便拖大拖小：把鼠标挪到窗口左边 / 右边 / 下边（或右下角）
  的空白边上，指针会变成双箭头，按住拖就行。放大的时候四角会变成直角，
  还原回来又是圆角。屏幕比窗口还小的话（比如 1366x768 的笔记本），
  程序会自动把窗口收一点，不让它顶到屏幕外面去。
  拖动过程很跟手、也不会糊：界面先跟着走，松手那一刻再把细节对齐。

  整个窗口没有任何系统自带的标题栏和边框 —— 看起来就是干干净净一块，
  不会出现那种白色的方框。


【主界面怎么看】

  ① 没有档位了 —— 打开就是全都做
     以前上面那张「运行档位」卡（温柔 / 标准 / 深度）已经去掉了：
     现在只有一种做法，打开程序七项就是全开的，也就是原来那个「深度清理」。
     想轻一点、只想清其中几项 —— 不用找档位了，直接到下面的
     「清理项目」里把不想清的那几项关掉就行，一关一项，不牵连别人。
     关掉的选择在本次运行里一直有效（重新打开程序会回到全开）。

  ② 清理项目
     七项都能单独开关。最后一项「关闭右侧勾选的后台程序」是把右边
     「第三方应用开关」列表里你自己打开的那些关掉 —— 关掉这一项
     就完全不会动任何程序，只清文件。

  ③ 第三方应用开关   ← 这就是"实时监测"那块
     列出这台电脑上此刻正在运行、可以关闭的程序。
     列表从上到下分三段，顺序就是"该不该你现在看一眼"：

       新出现        ← 以前没见过它。开关默认是"不动"，标着蓝色
                       「新出现」标签，整段排在最上面等你看一眼、
                       自己决定要不要清。
       保持不动      ← 见过的、而且你选的是不动它。清理时不碰。
       你选来清理的  ← 你打开过开关的，全集中在这一段，清理时会关掉。

     每一段前面有一条小标题，写着这一组有多少个。
     某一段一个都没有，那一段的标题就不出现。

     ⚠️ 蓝色「新出现」优先于橙色「白名单」、青色「自启动」：
        新装的东西哪怕排在开机自启里，也会先以"新出现"的身份提醒你。

     开关打开 = 清理时关掉它；关闭 = 保留。
     **默认一律是"关闭"（不动它）** —— 只有你自己打开过的才会被清理。
     也就是说，程序不会替你勾任何东西：名单里开着几个，就是你点过几个。
     这是故意的 —— 新出现的程序在你还没看过之前，不该被关掉一次。

     ⚠️ 拨开关的时候，行**不会**立刻跳到另一段去 —— 你停在哪儿就还在哪儿。
        段的归属是"这次启动的时候"按你当时的选择定下来的：
        · 拨完开关，开关本身立刻生效（这次清理就会按新状态来，
          顶部那行「要清 N」也是即时更新的）；
        · 但它换段要等**下次开程序**，那时候它会自己归到
          「你选来清理的」那一段去。
        · 不想重启就想立刻归位，点一下左下角的「刷新」。
        这么设计是为了不让人找不着北：一百来个程序，
        拨一下整行就跳走，你正在看的那一屏就散了。
        列表上方有一行小字写着的就是这条规则 ——
        第一次用的人（尤其是拿到别人分享包的人）看见它，
        就不会以为「开关拨了没用」。

     标着「白名单」的（白名单.txt 里列的那些）默认也是关的，
     但你想关也能自己打开 —— 白名单是软保护，不是硬拦。

     每个开关都会被记住，记在你这台电脑上：这次没在运行的
     程序（列表里根本看不到它）也一样记得，下次不用重新调一遍。

  ④ 便捷工具
     桌面挂件 / 开机自启 / 实时监测 三个开关，加一个「装进开始菜单」。

  ⑤ 运行日志
     欢迎信息、清理结果、报告全在这里滚动显示。
     不会在电脑里生成任何报告文件或日志文件。

  ⑥ 底部两个大按钮
       开始清理       ← 按上面的开关干活
       退出


【软件管理：装了哪些软件，缓存 / 开机自启 / 卸载都在这儿】

  点主界面上方那个「软件管理」页签就进来了。

  这一页整页就一张卡片，一行一个软件，一屏能看六七条。
  卡片右上角有一个搜索框（打几个字就只剩对得上的）和一个排序按钮。

  ── 谁排在最前面 ──

  默认按**缓存体积从大到小**排，谁占地方多谁在最上面，一眼就知道先清谁。
  一个缓存都没找到的排在后面，它们之间按**上次使用时间**从近到远排
  （越近说明越常用、越该被看见）。点右上角那个「按缓存」按钮可以切成
  「按名字」，想找某个具体的软件时按名字排更快。
  卡片上那行小字会写清楚现在按什么排的。

  ── 每一行上有三件事 ──

    · 开机自启
        右边那个蓝色开关。亮着 = 这个软件跟着开机一起起。
        拨一下**立刻生效**：关就是真的把它从开机启动里摘掉，开就是把
        原来那条命令**原样**放回去（连参数一起，程序自己记着）。
        旁边的小字写着状态：
          蓝色的「开机自启」= 现在开着
          灰色的「已关闭」  = 你关过，程序记着原来那条命令
          灰色的「开机自启」= 没在开机自启里，想开可以开
          「无自启项」      = 这个软件根本没往开机自启里放东西（开关是灰的）
        用户级的开机自启直接改；系统级的那几条改的时候会弹一次 UAC。

    · 清缓存
        只清**这一个软件自己**的缓存，别的软件一根头发都不动。
        没找到缓存的软件，这个按钮是灰的。
        清完底下日志会写清了几处、释放了多少。

    · 卸载
        调用**它自己的**卸载程序，绝不硬删目录。
        点之前会先弹一张小卡片，把「要卸哪个软件」和「马上会跑哪条命令」
        原样摆出来给你看一眼 —— 点「继续卸载」才真的走，点「取消」就当
        没这回事。走的是软件厂商自己那套卸载器（多半还会问你几句、可能
        要求重启），和「设置 → 应用」里点卸载是一模一样的。

  ── 点行左边的箭头能展开 ──

  展开之后有三行明细：

      安装时间：2026-04-05　　上次使用：2026-10-14 09:31（今天）　　占用：596 MB
      安装位置：D:\Program Files\douyin
      缓存目录：Roaming\douyin（639.5 MB）　·　Local\douyin（1.2 MB）

    · 安装时间    从注册表里读；注册表没写就看安装目录的创建时间。
    · 上次使用    从 Windows 的 Prefetch 里读 —— 这是**真的跑过**的记录，
                  不是「文件被摸过的时间」（那个会被杀毒和备份搞乱）。
                  读不到就显示 -- ，不编数字糊弄你。
    · 占用        注册表里记的安装体积，读不到也显示 -- 。
    · 缓存目录    就是这一行「清缓存」会清的那几个目录。
                  程序只在 AppData 下面挑**名字对得上** Cache / GPUCache /
                  Code Cache 这一类的目录，所以游戏自己的缓存不算在内 ——
                  那种不归它管，它也不会去猜。
    · 「打开目录」 按钮  直接在资源管理器里打开安装位置。

  · 展开 / 收起不会让列表跳回最上面 —— 你滚到哪儿就停在哪儿。
    （列表长的时候这一点很要紧：一百多个软件，点开一个又弹回顶部，
     等于每次都要重新滚一遍。）

  ── 名字和图标 ──

  名字用的是软件自己在系统里登记的**官方名字**（和「设置 → 应用」里显示的
  一模一样），左边那个图标是从它自己的主程序里抠出来的（透明背景原样保留）。
  下面那行小字是「发行商 · 版本号 · 安装日期」。
  实在取不到图标的，就留一个空框子 —— 不拿别的东西冒充。

  ── 列表最后那组「没归属到软件的缓存」 ──

  这是自动发现扫出来、但**目录名字对不上任何一个已装软件**的那些目录
  （比如 npm-cache、pip\cache、fontconfig\cache 这类工具链留下的）。
  规则和以前一样：只认目录名字，每个目录最多往下看两层，文档 / 下载 /
  桌面 / 图片 / 视频 / OneDrive 这些个人目录整片跳过。

  这一组和上面的软件行是两回事：要**勾上它前面的开关**、再点底下那个
  「清理勾中的缓存」才会清；软件行上的「清缓存」不受它影响。
  它也是按体积从大到小排，体积是 0 的自动收起来、不占地方。

  下面两个按钮「只勾可放心项」「全部取消」只管**这一组**。
  按钮上直接写着这次要清多少（例如「清理勾中的缓存 · 268 MB」），
  上面一行写着「下面那组待清理的缓存已勾选 N 项」。
  这里的东西都是**直接删掉**（不进回收站）—— 清的都是缓存，
  软件下次用的时候会自己重建。

  ── 扫描 ──

  第一次进这一页会自己扫一遍，扫描期间底下的按钮会先变灰、点不动。
  扫描的时候内容区上会盖一张「正在扫描」的卡片（转圈的点点 + 一根进度条 +
  正在看哪个软件 / 哪个目录），告诉你它在忙、不是卡死了。
  想重新扫就点底下的「重新扫描」。

  「软件管理」和「C 盘清理」两页各算各的：在软件管理页上看到的数字、
  点下去清掉的东西，都只有这一页勾上的那些；「C 盘清理」页上勾的系统项
  不会掺进来，反过来也一样。


【C 盘清理：系统临时文件 + 最占地方的文件】

  两个地方都能进去，进的都是同一扇窗、同一个页签：
    · 主界面上方那个「C 盘清理」页签
    · 桌面挂件右键 →「▤  C 盘空间清理」
      （挂件这一条会弹一次 UAC —— 系统级缓存要管理员权限才清得掉，
        进去之后直接停在「C 盘清理」页）

  这一页的控件是**第一次点进来才建的**，所以开主界面的时候不会白扫一遍 C 盘；
  也只有第一次进来才会自动开始扫描。想重新扫就点底下的「重新扫描」。

  页面里从上到下是三块（另外还有底部的运行日志和按钮）：

  ① C 盘容量
     总共多少、已用多少、还空着多少。进度条颜色随占用变：
     75% 以内蓝色，75% 以上橙色，90% 以上红色。

  ② 系统与临时文件 —— 左边一列分类，每项一个开关，开关打开 = 待会儿清它。
     每项都标了风险等级：

       可放心清理（默认已经打开）
         · 用户临时文件       Temp 目录：装软件、解压、安装包留下的垃圾
         · 系统临时文件       C:\Windows\Temp
         · Windows 更新下载缓存  已经装完的更新包，留着也没用
         · 更新分发缓存       Delivery Optimization 的更新碎片
         · 浏览器缓存         Edge / Chrome / Firefox 的网页缓存
         · 显卡着色器缓存      驱动会自己重建，删了不影响使用
         · 缩略图 / 图标缓存    资源管理器生成的预览图（被占用时会跳过）
         · 错误报告与崩溃转储    WER 报告、程序崩溃时留下的转储文件
         · 系统日志           CBS / DISM / WindowsUpdate 的安装日志
         · 清空回收站         清空就找不回来了，自己看着办

       需谨慎（默认是关的，要你自己打开）
         · 系统升级残留       Windows.old 之类，删掉就不能回退旧版本了
         · 系统内存转储       MEMORY.DMP / Minidump，蓝屏排查用的
         · 组件库清理（DISM）  要跑几分钟，清完就不能卸载已装的更新

     下面两个按钮：「只勾可放心项」「全部取消」，嫌一个个点麻烦就用它们。

     （第三方软件的缓存在「软件管理」那一页，一个软件一行，在行上点「清缓存」。）

     点「清理选中项」就开始清。这一列里的东西都是**直接删掉**（不进回收站）——
     清的都是缓存和日志，系统和软件会自己重建。
     无论哪一页，底下那个「清理选中项」按钮上都会直接写着这次要清多少
     （例如「清理选中项 · 643 MB」），不用自己去加。「只勾可放心项」「全部取消」
     和这个数字一样，都是**只算当前这一页**——「软件管理」页上勾的东西不会
     被算进「C 盘清理」页的数，也不会被这一页一并清掉。（「软件管理」页上
     软件行自己的「清缓存」就更不相干了，那是按行算的。）

  ③ 最占地方的文件
     用户目录 + C 盘根目录下所有大于 50 MB 的文件，按大小排队，最多列 100 个。
     这一栏是**只读**的，程序绝不会自己动它：
       · 点一个文件，下面显示它的完整路径
       · 想删就先选中它（按住 Ctrl 可以多选），再点「删除选中文件（回收站）」。
         删掉的东西进回收站，后悔了还能还原。
       · Windows 目录、Program Files、ProgramData、本程序自己的文件夹、
         页面文件（pagefile.sys / hiberfil.sys）一律拒绝删除，会直接跳过
       · 万一这台电脑的回收站用不了，程序会问你一句要不要彻底删除，
         你说不删它就保持原样

  几条硬规矩（写死在代码里的）：
    · 能清的东西全部来自上面那张**固定清单**，程序不会"全盘扫一遍然后乱删"。
    · 每一项都是明确的目录或文件名模式，没有靠猜出来的删除目标。
    · 扫描是边走边更新的：扫大目录时进度条和"正在统计 xxx"都会动，
      窗口不会变成"未响应"；不想看了直接关窗口，它立刻就停
      （切回「后台清理」页不会打断它，扫描会在后台接着跑完）。
    · 所有数字都是当场量出来的。量不到就写 0，不会编一个好看的数字给你。
    · 每次扫描都是**重新读盘**：容量、分类、每一项的体积全部现算，
      程序不会「记住」上一次的结果，也不会把这台电脑的软件清单存成文件 ——
      发给朋友时带过去的只是一套扫描规则，不是一个"我的电脑有什么"的名单。


【我的设备：这台电脑装了什么硬件】

  第四个页签。一次把能读到的硬件和外设全列出来，左边是项目、右边是值，
  一段一类，从上往下是：

      电脑        品牌型号、主机名、内存合计、操作系统、系统版本
      处理器      型号、制造商、核心 / 线程、基准频率、插槽、缓存、架构
      显卡        型号、显存、驱动版本与日期、当前输出分辨率与刷新率
      主板        BIOS 带：厂商、型号、版本、BIOS 版本、BIOS 日期
      内存        条数、总容量、类型，再一条一条列品牌 / 容量 / 频率 / 时序
      硬盘        块数，再一块一块列型号 / 容量 / 类型 / 分区数
      显示器      品牌、型号、当前分辨率（带系统缩放）、生产年份、序列号
      键盘 / 鼠标  各自认得几个，品牌和型号都写出来
      音频设备    声卡 / 音频控制器，一个一条
      网络        有线网卡、无线网卡，带 MAC 和链路速度
      蓝牙        适配器，以及当前连着的蓝牙耳机之类的设备

  · 品牌和型号尽量写全称：比如「AMD Ryzen 7 7800X3D 8-Core Processor」、
    「NVIDIA GeForce RTX 5070 · 12 GB」、「ZHITAI TiPlus5000 1TB · NVMe、SSD」。
  · 值太长放不下会被省略号掐掉，**鼠标停上去能看全**。
  · **读不到的项一律写 --，不猜、不编**。（比如没装独显温度传感器、
    内存条没写时序，就老老实实是 --）
  · 这一页**只读**：从头到尾不改任何设置、不发任何命令。
  · 打开这个页签时才读一次（大约两三秒），不会在后台一直轮询 ——
    想看最新的数字，点左下角「重新读取」。
    （换过硬件、插过新 U 盘之后再点一下就行。）
  · 数据全部来自系统自己的记录：WMI、注册表、显示器 EDID、网卡驱动，
    没有任何一项是联网查的，也不上传。
  · 换页之后窗口大小、位置都不变，跟其它三页完全一样。


【点「开始清理」之后】

  · 不再弹确认框，点一下就开始。
  · 要关掉哪些程序，会先写进下面「运行日志」里，出问题可以回看。
  · 清理完成后只弹一个小窗，写着「蒸鱼真的帅」，
    1 秒后自己消失，也不出声。
  · 详细的清理报告同样在「运行日志」里。


【实时监测：不是记好的一张名单】

  列表里的程序是"现在这一刻"真实扫描出来的，不是预先写死的名单。

  · 程序打开后，主界面会自己出现它，不用手动刷新。
  · 程序关掉后，它会自己从列表里消失。
  · 每 15 秒自动核对一次，检测到变化就即时更新。
  · 更新列表时，你已经调好的开关不会被弄乱。
  · 右侧提示行会写这一行：
       实时监测中 · 27 个（白名单 7 · 已记住 27 · 要清 15 · 新 0）　扫描 23:20:57
    四个数分别是：白名单里有几个、开关表里记得几个、你选了要清几个、
    以及此刻列表里"新出现"几个。末尾是最后一次扫描的时间。
  · 不想让它自动更新，就把「便捷工具」里的「实时监测」关掉，
    之后需要时手动点「刷新」。
  · 只列出真正的应用程序：崩溃上报进程、更新器、后台助手、
    各种 *_sdk / *_server / *_renderer 之类不会出现在列表里。


【"新出现"是怎么认出来的】

  程序额外记了一笔流水：这台电脑上"见过哪些程序、第一次见到是哪天"。
  位置：%APPDATA%\蒸鱼清理\见过的软件.json

  · 记忆里查不到名字的程序 = 头一回见到 → 标蓝色「新出现」、排到列表最上面、
    开关默认是"不动"。
  · 看过一次就记下来了，下次再开程序它就是个"见过的"，标记不再出现。
  · 标记在整个这次运行期间都不会消失 —— 自动监测每 15 秒可能重建一次列表，
    不会把标记冲掉，你能从容看完再决定。
  · 老用户升级上来不会看到满屏「新出现」：凡是「应用开关.json」里已经有
    你明确选择记录的程序，都算"早就见过"，不会再被标一遍。
  · 这份流水和「应用开关.json」是两件事，故意分开存：一个是"要不要清它"，
    一个是"见过没有"。删掉 见过的软件.json 不影响你的任何选择，
    只会让下次开程序时列表里的程序重新被标一遍「新出现」。


【桌面小挂件】

  打开方式：「便捷工具」里的「桌面挂件」开关，打开即出现。

  · 一个小胶囊贴在桌面上，分成两行：
        第一行    当前时间（字号更大、居中）
        第二行    CPU 占用率 · 显卡占用率+温度 · 内存占用
  · 尺寸不是写死的：两行各量一遍最宽的文字，取宽的那个当宽度、两行相加当高度。
    参数行按「CPU 100% · 显卡 100% 100°C · 内存 100%」这个最宽模板算，
    数值变化时宽度不会来回抖
  · 时间每秒对一次表（整分钟翻转不会迟），参数每 5 秒刷新
  · 按住左键拖动，位置会被记住，下次还在原地
    能拖的时候光标是「十字移动」样子；锁定后变回普通箭头，一眼能看出来
  · 双击（胶囊上或托盘图标上） → 立即清理
    效果和主界面按「开始清理」在七项全开时一样：不弹确认框，
    干完只弹一个「蒸鱼真的帅」，1 秒自动消失，没有声音。
    ⚠️ 它不看主界面那七个项目开关 —— 不管你在主界面关掉过哪几项，
    挂件这条路永远是七项全做（这也是它以前叫「深度清理」的原因）。
  · 右键 → 菜单：
        ⟳  立即清理            ← 同上，不弹确认框
        ▣  打开主界面
        ▤  C 盘空间清理        ← 打开主界面并直接停在「C 盘清理」页
                                  （会弹一次 UAC）
        ⚑  开机自动启动挂件
        ◐  透明度      ← 7 档，从「不透明」到「90%」，越往下越淡
        ⊘  固定位置（防误拖）   ← 勾上后挂件不再响应拖动，防手抖拖走；
                                  「重置挂件位置」不受影响，随时能把
                                  它送回默认位置。这个开关会被记住
        ▲  总在最前（玩游戏也看得见） ← 见下面「总在最前」
        ⏻  快速关机            ← 点了直接关机，没有确认框、没有倒计时
        ↻  快速重启            ← 同上，直接重启
        ▾  隐藏挂件
        ⌖  重置挂件位置        ← 无论是否锁定都有效
        ✕  退出挂件
  · 快速关机 / 快速重启是「点一下就执行」的，所以特意用分隔线和
    「隐藏 / 退出」隔开，少一个手滑的机会。它们走 Windows 自带的
    shutdown 命令，并且**不加 /f** —— 不会强杀软件：该提示保存的照样
    提示，只有某个程序彻底卡住时才会拦住关机（Windows 会把它列出来）。
    想改成「不管三七二十一连卡住的程序一起关掉」，把 /f 加上即可。
  · 默认透明度 70%，淡淡的，不挡事
  · 找不到它了   → 看右下角系统托盘的蓝色小图标
  · 挂件不需要管理员权限，只有真正触发清理时才弹 UAC
  · 触发清理不会闪出黑色的「管理员窗口」：挂件调的是 蒸鱼清理.exe
    （无控制台程序），由它自己提权并静默启动，全程零窗口

  读不到的数据会显示 --（不糊弄假数字）：
    CPU 占用率   用系统自带的 GetSystemTimes 直接算，所有 Windows 都有，必定有数
    显卡 占用率+温度   直接读 NVIDIA 驱动里的 nvml.dll，有 N 卡就有数，
                       不是 N 卡就显示 --
    内存 占用    Windows 自带接口，必定有数

  · 为什么没有 CPU 温度：Windows 自己**没有**通用取温接口，要靠主板厂商提供。
    这台机器是虚拟机/云桌面，读不到（就是显示 -- 的那个情况），
    与其留一个永远读不出来的格子，不如换成必定能读的 CPU 占用率。
【总在最前：玩游戏也看得见】

  挂件平时是**贴在桌面上**的（挂在桌面窗口下面），好处是永远不挡事，
  代价是一开窗口就被盖住 —— 想瞄一眼占用率得先把别的程序最小化。

  右键菜单勾上「▲  总在最前（玩游戏也看得见）」之后，挂件会从桌面上摘下来，
  变成一扇普通窗口，并且排在所有窗口最前面：玩游戏、看视频、开浏览器时
  都能看见当前的 CPU / 显卡占用率、显卡温度。再点一下取消勾选，
  它就乖乖贴回桌面。开关状态会被记住，下次启动还是按你上次的选择。

  ⚠️ 一件必须说清楚的事：**独占全屏（真全屏）的游戏，任何普通窗口都盖不上去**，
  挂件也不例外 —— 这是 Windows 的规矩。想让挂件显示在游戏画面上，
  到游戏设置里把显示模式改成「无边框窗口」或「窗口化」就行
  （绝大多数游戏都有，性能损失很小，切窗口也更快）。

  · 勾上以后挂件的行为就是一扇普通小窗口：不再跟着「显示桌面」跑，
    也不在桌面图标下面了，想盖住它就点它自己
  · Alt+Tab 名单、任务栏里依然没有它（这条没变）


【开机自启 / 开始菜单】

  「便捷工具」一栏里就能全部搞定：

  · 开机自启开关    打开 = 每次开机自动出现桌面挂件
  · 装进开始菜单    点一下，把快捷方式放进开始菜单
                    （之后按 Win 键搜「蒸鱼清理」就能找到，
                      想固定到任务栏就在开始菜单里右键「固定」）

  开关状态存在注册表的 Run 项里，卸载时关掉即可，不会残留。

  开机自启的原理：在注册表里登记一句

      "…\蒸鱼清理.exe" widget

  用的是那个 GUI 子系统的小启动器，而且「挂件模式」不提权 ——
  所以每次开机既不闪黑窗，也不会弹 UAC 问你要权限。

  想核对是不是真的生效，两个地方都能看到：
    · 任务管理器 →「启动应用」标签
    · 设置 → 应用 → 启动
  里面应该有一条「蒸鱼清理」，状态是「已启用」。

  如果那里找不到它 —— 或者开关明明显示已开、开机却没反应 ——
  基本就是注册表里那条记录指向的文件已经不在了。最常见的原因：
  把程序文件夹挪了位置，或者从老版本升级上来（老版本有个单独的
  蒸鱼清理-挂件.exe，后来合并成一个 exe，那个文件就没了）。
  · 挂件每次启动会顺手把这种残留改写成当前路径，不用你管；
  · 想手动来一下：把「开机自启」开关关掉、再打开。


【三层硬保护，不会误伤】

  第 1 层  系统层    C:\Windows、ProgramData、WindowsApps 里的进程一律不碰
  第 2 层  微软层    所有微软签名的组件自动跳过（Edge 浏览器除外）
  第 3 层  目录层    白名单.txt 里显式写的「目录路径」，整棵目录一起保护

  另外：你当前正在用的前台窗口、以及本程序自己，永远不会被关掉。


【白名单.txt】

  位置：C:\Users\<你的用户名>\AppData\Roaming\蒸鱼清理\白名单.txt
  打开方式：主界面右下角「编辑白名单」按钮

  默认保护这些（默认不勾选，不是碰不得）：
    · 微信（WeChat / Weixin / WeChatAppEx 小程序容器）
    · Steam 全家桶
    · 输入法（搜狗、QQ拼音、微信输入法）—— 关掉会打不了字
    · 安全软件（火绒、360、腾讯电脑管家）—— 关掉会失去防护
    · 外设工具（罗技 G HUB、NVIDIA、Realtek 音频）

  想调整：
      加保护 → 加一行程序名（如 PotPlayer），或目录路径（如 D:\我的工具）
      以 # 开头的是注释，随便改。

  注意：它们是"默认帮你留着"，不是"永远关不掉"。
        真想连微信 / Steam 一起关掉，把它的开关打开就行。


【开关会被记住】

  你的每一个开关选择（「全选 / 全不选」也算）都会立刻存到
      C:\Users\<你的用户名>\AppData\Roaming\蒸鱼清理\应用开关.json
  下次打开还是按你的来。

  它记的是"你选过的程序"，不是"这次列表里有什么"：
  某个程序这次没在运行、列表里根本没有它，它上次的选择也照样留着，
  下次它再跑起来，开关还是你定好的那个状态。
  想彻底清空重来，把上面这个 json 删掉就行。
  （"谁是新出现的"记在另一份 见过的软件.json 里，跟这份各管各的 ——
    见上面【"新出现"是怎么认出来的】那节。）

  ⚠️ 注意"没记录"和"记着不动"是两件不同的事：
      · 记着"不开" = 你决定过：留着它。→ 归到「保持不动」那一段。
      · 压根没记录 = 还没见过/没决定。→ 归到「新出现」那一段，默认也不动。
     两边的默认结果一样（都不会被清），但列表分居两段，你能一眼看出
     哪些是"自己决定不动的"、哪些是"还没看过的"。
     （这两段怎么分是**每次开程序时**按当时的选择定下来的；
       中途拨开关不会立刻换段，见上面第 ③ 条。）

  为什么放在 AppData 而不是程序文件夹？
  这样整个程序文件夹就是"干净"的，可以直接打包发给朋友，
  里面没有任何属于你个人的东西。


【打开官网 / 自动更新】

  顶栏右边、最小化按钮的左边，有一个小小的「打开官网」按钮。
  它故意做得低调（不抢三个窗口按钮的位置），但一直看得见：
  鼠标移上去会浮出一块浅色底，点一下就用默认浏览器打开官网
      https://zhengyuqingli.app.workbuddy.host/

  版本号就写在主界面「便捷工具」这一栏的右上角（例如 v2.7.3），
  是从 exe 自己的版本信息里读出来的，不是写死在界面上的。

  自动更新：程序每次打开都会顺手问一下官网「有没有新版本」。

  · 有新版 → 它自己下载、自己校验、自己换掉 exe，
    然后重新启动一次（还是同一个程序，位置、开关、白名单都不变）。
  · 没有新版 / 网线没插 → 什么都不做，绝不打扰你，日志里留一行而已。
  · **全程不需要你点任何东西，也不会再弹一次 UAC** ——
    更新是在主程序自己的权限下完成的。

  它凭什么敢自己换掉自己：
  · 下载下来先对大小，再对 SHA-256 指纹，最后还要确认它真的是一个
    Windows 图形程序（PE 头 + 子系统 = 2）。
    三条全过才敢动手 —— 防止「酒店的 WiFi 登录页被当成新版本装上」这种事。
  · 换的时候是「新文件就位 + 旧文件留一份 .bak」一步完成，
    不存在「exe 不见了」的瞬间；万一换不过去，会自动把旧的放回来。
  · 新版真正启动过一次之后，那份 .bak 才会被删掉。
    也就是说：只要新版起不来，旧版就一直躺在旁边当退路。
  · 单个 exe 才有这份能力：如果 exe 旁边就摆着 Zero.ps1（也就是开发目录），
    程序会**故意不自动更新**，免得把正在改的编译产物盖掉。

  更新失败怎么办：直接从官网下载页重新下一个就行
      https://zhengyuqingli.app.workbuddy.host/
  下载的是同一个单文件 exe，覆盖过去即可，个人设置都在 %APPDATA% 里，不受影响。


【分享给朋友】

  只需要发 蒸鱼清理.exe 这一个文件。

  它现在是一个「单文件」程序：主程序、桌面挂件、图标全都打包在 exe 里，
  朋友可以把它单独拖到桌面、放进 U 盘、挪到任意文件夹，双击就能用 ——
  不会再有「找不到 Zero.ps1」这种事，也不需要旁边有别的文件陪着。

  第一次运行时，exe 会自动把自己内部那几份文件释放到
      C:\Users\<用户名>\AppData\Local\蒸鱼清理\bin\
  再从那里启动。整个过程一两秒，用户什么都不用做。
  （放在这个目录而不是别处，是因为每个用户的它都有写权限，也不用麻烦管理员。）

  建议连 使用说明.txt 一起发（就是这份说明）；八张预览图可发可不发，
  它们只是效果图，删掉不影响使用。build 文件夹不用发 —— 那是开发用的
  编译脚本和自检程序，只有想改 exe 本身时才需要。

  最省事的做法：直接用打包好的 zhengyuqingli-windows.zip（官网下载页那个）；
  或者把 exe 选中 → 右键 → 发送到 → 压缩(zipped)文件夹。
  对方解压到**任意文件夹**（别放 C:\Program Files），双击 蒸鱼清理.exe，
  第一次会弹一次 UAC，点「是」。

  · 对方第一次运行时，会在他自己的电脑上重新扫描正在运行的程序，
    自动生成属于他的白名单和开关记录。
  · 程序不会把自己电脑上的软件"记下来"带给别人 —— 列表永远是当场扫的。
  · 「软件管理」和「C 盘清理」两页也一样：系统固定分类、还有对方自己装的
    软件（缓存 / 自启 / 卸载命令）都是到了对方电脑上现扫现查的。程序里没有任何
    "我这台机器上有什么"的清单，对方装了什么软件、缓存放在哪，
    是到他机器上现看现算的。
  · 如果对方想要一份全新的白名单，删掉他电脑上的
      %APPDATA%\蒸鱼清理\白名单.txt
    再开一次程序，就会重新生成默认的那一份。
  · 程序文件夹里**没有任何属于你的个人数据**（白名单、开关记录、挂件位置
    全都存在 %APPDATA%\蒸鱼清理\ 里），所以可以放心发。
  · 不用安装，也不写注册表 —— 只有你主动打开「开机自启」时才会加一条启动项。
    整个文件夹删掉就等于卸载干净（记得先关掉开机自启）。
  · 可能会被拦：这是个没买代码签名的 exe，加上它会关后台进程、删临时文件，
    杀毒软件和浏览器容易误判。让朋友选「仍要运行」，或者先把文件夹加进
    杀软的信任列表。微信 / QQ 直接传 exe 也常被拒，打包成压缩文件再传稳一些。
  · 对方解压后如果发现文件名是乱码，换个解压软件（7-Zip / 新版 WinRAR）
    重新解压即可，那是老版本解压工具不认 UTF-8 文件名的问题，不是文件坏了。


【几点提醒】

  · 清理会顺带关闭后台程序（右边列表里你自己打开的那些），
    没保存的文档或网页可能丢失。
    两条路（主界面「开始清理」和挂件双击）都不再弹确认框，
    但动手前都会先记录「将要关闭哪些程序」：主界面写在下方的运行日志里，
    挂件那条路写在内部运行记录里（不落盘）。
    两种情况干完都只弹一个「蒸鱼真的帅」，1 秒自动消失，没有声音。
  · 关掉浏览器、聊天软件这类程序没问题，重新打开就好。
  · 系统进程、微软组件永远关不掉，即使你想关也关不掉，这是故意的。
  · 清理过程中日志里出现「关不掉」是正常的，说明那个进程受系统保护。


【想改 exe 的样子？】

  这些是给开发者（也就是你自己）看的，分享给朋友时**不需要**带上 build 文件夹：

      build\launcher.cs     exe 的 C# 源码（无控制台启动器，纯 ASCII）
      build\build.ps1       编译（用 Windows 自带的 C# 编译器，不用装任何东西）
      build\rebuild.ps1     重新编译，并把旧 exe 收进 build\_obsolete
      build\mkicon.ps1      用一张图生成图标：自动裁成方形、外圈白底抠成透明、
                            一次生成 16/24/32/48/64/128/256 七种尺寸（小图标才不糊）。
                            源图固定在 build\icon_source.jpg，换图就覆盖它再跑一次。
                            128/256 两张是按 PNG 存的 —— 顶栏那个小图标正是靠
                            「读里面最大的一张 PNG」来保住透明通道的
                            （见 Zero.ps1 里的 ZYUI.Gfx.IconPng）。
      build\go_ui_test.ps1  一键跑全部自检（主界面 / 弹窗 / 静默路）
      build\run_widget_test.ps1  挂件自检（截图、尺寸、读数、固定位置开关）
      build\run_sw_test.ps1     「软件管理」页自检（点页签进去、等它扫完、截图、
                            软件行必须和扫到的软件数一致、图标取到多少张、
                            展开 / 收起的高度和位移、搜索和排序、
                            默认排序必须是「缓存体积降序 + 没缓存的按上次使用时间」、
                            「清缓存」只清这一行的缓存、「卸载」只验它打算跑哪条命令
                            （绝不真的启动卸载器）、开机自启 HKCU 往返、
                            空缓存的行「清缓存」必须是灰的、
                            底下那组「没归属到软件的缓存」的勾选 / 合计 / 清理范围，
                            扫描浮层、缩放到 1200 宽后卡片和按钮有没有跟着重排、
                            **滚下去再展开一行，滚动位置必须一动不动**
                            （面板是原生 AutoScroll，滚动范围默认照可见子控件的
                             边界现算；重排时把行全藏一遍范围会塌成 0，
                             位置就被夹回顶部 —— 这一组就是钉死这个坑））
      build\run_app_test.ps1    第三方应用那块自检（主界面右卡）：三段标题必须
                            按「新出现 → 保持不动 → 你选来清理的」的顺序出现、
                            选中的那批必须全在最下面、开关和程序按下标配对不能错位、
                            头一回见到的默认「不动」且排在最前面、
                            「新出现」标记扛得住重建、重启后不再标、
                            顶部那行说明在最坏情况下也放得下（不被截断）、
                            跑完用户真实的两个 json 逐字节没被动过、
                            **档位那张卡真没了 / 七个项目默认全开 /
                            「清理项目」底下那行解释放得下 / 中间那排直接顶到 152**
                            （v2.7.2 删了温柔 / 标准 / 深度三档，这一组盯着别被加回来）
      build\probe_scroll.ps1 单独验「隐藏子控件会不会把 AutoScroll 的位置夹回顶部」，
                            并对照「显式撑一根 AutoScrollMinSize 之后就不会」。
                            改任何滚动相关的东西之前先跑它
      build\probe_hintw.ps1  量「实时监测中 · …」那一行候选文案的像素宽度，
                            换文案之前先跑它，别靠估
      build\run_space_test.ps1   「C 盘清理」页自检（点页签进去、截图、分类统计、
                            系统文件保护、缩放到 1200x900 后布局有没有跟着重排）
      build\probe_altab.ps1  Alt+Tab 专项自检（无人值守、A/B 对照）：先把「修复前」
                            那份旧载荷当对照组跑起来，再按开始菜单的方式启动真 exe，
                            比对两者的扩展样式。旧载荷应当是 TOOL=False（会出现在
                            Alt+Tab 里），新载荷应当是 TOOL=True（不会），四条断言全过
                            才算修好。判据就是壳子真正看的三件事：可见 / 没有
                            WS_EX_TOOLWINDOW / 没被 DWM 遮盖（见下面「挂件为什么 …」）
      build\probe_update.ps1 自动更新专项自检（无人值守、八段断言）：起一个本地 http
                            服务，把「新版本」喂给更新器，验证 升级 / 已最新 / 指纹不对 /
                            不是 PE / 换完握手清理 / 服务器连不上 / 线上清单 / 线上载荷
      build\demo_update.ps1  同一个套路的「看得见」版本：它会真的把软件窗口打开，
                            你能亲眼看到便捷工具那行小字变成「正在检查更新…」→
                            「已更新到 v9.9.9.9，正在重启…」，然后窗口自己关掉再开一扇。
                            演示用的「新版」＝ 真 exe + 5 个尾字节：PE 加载器和版本资源
                            都不看尾字节，所以它照样能跑，但大小和指纹都变了 ——
                            正好就是更新器要校验的那两样。跑完会留下暂存目录让你翻 .bak。
      build\execheck.ps1    检查 exe 是不是无控制台的 GUI 子系统
      build\vercheck.ps1    读回 exe 的版本信息（任务管理器里显示的名字就靠它）
      build\argroute.ps1    校验 exe 的参数路由（widget / space 有没有走对脚本）
      build\selftest.ps1    单文件模式专项自检：把 exe 单独拷到一个空文件夹，
                            确认它内嵌的资源在、能自己解包出来、解包出的脚本
                            还带着 UTF-8 BOM，并且真的用那份解包出来的脚本起了挂件
      build\bomstate.ps1    列出各文件的 BOM 状态，确认编码没被改坏
      build\tidy.ps1        清掉自检产生的临时文件

  「单文件」是怎么做到的（动了这块一定要跑 build\selftest.ps1）：

  · build.ps1 编译时用 /resource: 把 Zero.ps1、Widget.ps1、蒸鱼清理.ico
    塞进 exe，逻辑名固定为 ZY.Zero.ps1 / ZY.Widget.ps1 / ZY.App.ico
    （launcher.cs 就是按这三个名字去取的，改名字要两边一起改）。
  · launcher.cs 启动时先看 exe 旁边有没有脚本：
      有   → 直接用（文件夹模式，开发时和自检程序都靠这条路）
      没有 → 把内嵌的三份释放到 %LOCALAPPDATA%\蒸鱼清理\bin\ 再跑那份。
    释放前会逐字节比对，内容一样就什么都不写，所以重复启动几乎零开销。
  · 脚本里 $PSScriptRoot 这时候指向释放目录，不是用户双击的那个 exe。
    所以启动器会把自己的真实位置通过环境变量告诉脚本：
      ZY_APP_ROOT / ZY_APP_EXE —— Zero.ps1 和 Widget.ps1 开头就读取它们，
    用来建快捷方式、注册开机自启、以及挂件回头去调主程序。
    没有这两个变量时（直接跑 .ps1）行为跟以前完全一样。

  「自动更新」是怎么办到的（动了这块一定要跑 build\probe_update.ps1）：

  · 更新器不是一个单独的 exe，而是**同一个 exe 的另一个模式**：
      蒸鱼清理.exe update "<状态文件>"
    它在提权分支和 selftest 之前就被拦下来处理，所以是一个无窗口的独立进程 ——
    下载慢也不会冻住界面；它又是提权 GUI 的子进程，天然继承管理员权限，
    所以写得进 exe 所在目录，也不会中途弹第二个 UAC。
  · 官方清单地址写在 launcher.cs 的 DefaultManifestUrl。
    想指向别处（本地 http 服务、测试站点）就设环境变量 ZY_UPDATE_URL ——
    build\probe_update.ps1 正是靠这个把所有分支演练一遍的。
  · 清单是官网的 version.json，更新器只认这三个字段：
      exeFile    ← 相对清单自己所在 URL 的路径（download/zhengyuqingli.exe）
      exeSize    ← 字节数
      exeSha256  ← 大写十六进制
    **发布时必须带上这三个字段**（zhengyuqingli-site\release.ps1 会自动写），
    否则线上老客户端每次检查都只会得到 failed|manifest。
  · 替换不需要「重启后再换」的花招：Main() 起完 powershell.exe 就 return 了，
    界面跑着的时候启动器进程早就退出了，exe 没人占用。
    但以管理员身份启动时它会占住大约一秒，所以换名字那一步要重试 12 次 × 250ms。
  · 「新版真的起来了」是用一个标记文件握手的：
    换完写 <exe>.update，内容是新版本号；下次**这个版本**启动时，
    清理逻辑（HousekeepAfterUpdate）比对版本号成立才删掉标记 + .bak + .new。
    所以这个清理必须排在 selftest / update 这两个提前 return 的分支**前面**，
    否则它们永远走不到（第一版就踩了这个，是 probe_update.ps1 抓出来的）。
  · 用 Environment.SetEnvironmentVariable 传 ZY_UPDATE_URL 之后要记得删掉：
    给它传 $null 在现代 .NET 上**不会删除变量**，而是把它设成空字符串留在环境块里。
  · **自动更新只能「从有这个能力的版本」往后生效**：v2.0 及更早的 exe 里根本没有
    这段代码，它不会去问、不会去下、也不会替换自己 —— 那些版本只能手动换新。
    换句话说 v2.1 是第一个「能自己长大」的版本，而从 v2.2 起才真正能看到
    「打开就自己变新」的效果。发版时别把这条忘了：给朋友的第一个包必须至少是 v2.1。
  · 排查「到底更没更」看两个地方：界面「便捷工具」右上角那行小字（检查中 / 已是最新 /
    已更新到 vX，正在重启…），以及 %TEMP%\zy_upd_<进程号>.txt —— 每个界面实例一个，
    数它就知道一共检查了几次（死循环重启会让它一直变多，而 exe 指纹是看不出来的，
    因为假包每轮字节都一样）。

  ⚠️ 这里有个非常隐蔽的坑，改 launcher.cs 时千万别踩：
  **绝对不要给 ProcessStartInfo.EnvironmentVariables 赋值。**
  它内部是个「大小写不敏感」的字典，如果系统环境里同时存在 http_proxy 和
  HTTP_PROXY 这种重名变量（本机的开发沙箱就是），这个属性会返回一个**空字典**
  而不报错。往里写两个变量再 Process.Start，等于给子进程一个「只有那两个变量、
  连 SystemRoot 和 PATH 都没有」的环境块 —— PowerShell 起不来，挂件悄无声息地
  永远不出现，而且没有任何报错。
  正确做法是 Environment.SetEnvironmentVariable 设在**自己进程**上，
  让子进程自然继承。build\selftest.ps1 的第 6 段就是专门盯这个的回归测试。

  改完记得两套编码规则是不一样的：
  · 含中文的 .ps1（Zero.ps1 / Widget.ps1 / 使用说明.txt）必须存成“UTF-8 带 BOM”，
    否则 PowerShell 5.1 会按 GBK 解码，中文全变乱码。
  · build 里的脚本（.ps1 / launcher.cs）必须“纯 ASCII”，能写英文注释就写英文；
    万一带了中文又不能去掉，就存成“UTF-8 带 BOM”。最怕的是「无 BOM 又带中文」——
    字节错位会静默吃掉一整行代码，报错信息还跟编码毫无关系。
    中文文件名一律用字符码点拼出来（`U '84B8,9C7C,6E05,7406'` = 蒸鱼清理），
    否则可能生成乱码文件名。
  · 拿不准就跑一下 `build\bom.ps1`：它会检查这几个文件，
    并对「无 BOM 又带中文」的 build 脚本自动补上 BOM。
  · PowerShell 的变量名**大小写不敏感** —— 新加变量前先搜一下有没有同名（哪怕大小写不同），
    不然会莫名其妙把别处的值覆盖掉。
  · 界面的位置全部由三个布局函数按客户区尺寸算出来（Layout-Window / Layout-MainPage /
    Layout-SpacePage），建控件时写的那些坐标只是「默认尺寸下的落脚点」。
    要挪东西就改布局函数，别往控件上写死坐标，否则一缩放窗口就对不齐。
  · 无边框窗口（FormBorderStyle=None）没有系统标题栏，所以缩放要自己写在
    MouseMove/MouseDown 里（见 Get-RzEdge），最大化也必须反射设 MaximizedBounds ——
    它是 protected 属性，直接赋值会抛「找不到属性」，而不设的话最大化会盖住任务栏。
  · 缩放不能直接在 MouseMove 里改窗口：PowerShell 里一次 Layout-Window 要 ~16ms
    （几十个 SetBounds，每个都是一次 SetWindowPos），卡在消息循环里 Windows 就没机会
    重绘，只能把旧位图拉大 —— 那既是「卡」也是「糊」的根源。现在的做法：
    MouseMove 只做算术（~90µs），把目标尺寸写进 $Script:RzWant 并起一个 12ms 一次性
    Timer，由 Timer 去真正 SetBounds（同一帧的多次移动自动合并）。拖动开始时置
    $Script:RzFast，跳过 $form.Region / $hdr.Region 的圆角裁剪 —— 带 Region 的窗口
    缩放是靠拉伸旧位图，必然糊；MouseUp 再补一次 Layout-Window + Invalidate($true)。
    另外只有**当前那一页**才重新布局（切页时 Set-Tab 会再调一次）。
  · 标题栏三个按钮是自绘控件 ZYUI.CapBtn —— 不用字体里的 — □ ✕，那几个字符
    在不同系统上粗细和居中都不一样。三个共用一个 12px 字形框、同一支 1.4px 的笔；
    描边坐标要落在**半像素**上（Math.Floor((Width-s)/2f)+0.5f），
    否则抗锯齿会把一条线糊成两行 75% 的灰，看着就比别的粗。
    它继承 Button（为了自检能用 PerformClick 走真实点击路径），
    并关掉 FlatAppearance.BorderSize / UseVisualStyleBackColor，全自绘。
  图标换成自己的：把新图覆盖到 build\icon_source.jpg，跑一次 build\mkicon.ps1
  生成 蒸鱼清理.ico，再 build\rebuild.ps1 重新编译即可。
  **换图标只需要动这一处**：exe 的图标、窗口图标、任务栏、桌面挂件、托盘、
  开始菜单快捷方式、以及顶栏标题旁边那个小图标，全都是读这一个 .ico。
  顶栏小图标走的是 ZYUI.Gfx.IconPng（挑 .ico 里最大的一张 PNG 条目，
  再用 Image.FromStream 读 —— 这样透明通道一定保得住；
  直接用 Icon.ToBitmap() 有可能把四角的白底画成黑块）。

  「挂件为什么不在 Alt+Tab 里」是怎么办到的（动了这块一定要跑 build\probe_altab.ps1）：

  · `ShowInTaskbar = $false` 只管任务栏上那个按钮，**管不着 Alt+Tab** ——
    那是另一份名单。壳子在 Alt+Tab 里只看三件事：
      1. 窗口可见（IsWindowVisible）
      2. 没有 WS_EX_TOOLWINDOW（0x00000080）
      3. 没被 DWM 遮盖（DWMWA_CLOAKED == 0）
    而 WS_EX_APPWINDOW（0x00040000）正相反：它是把窗口**硬塞**进名单。
    微软官方说法（Raymond Chen《Which windows appear in the Alt+Tab list?》）：
    「带 WS_EX_TOOLWINDOW 的窗口会被当成不可见，即使它明明可见。」
    → 所以处方就一句话：加上 TOOLWINDOW、去掉 APPWINDOW。
  · 挂件原来能躲开任务栏、却躲不开 Alt+Tab，是因为它**故意有个 owner**
    （托盘图标那个隐藏窗口）—— 那正是「让可见窗口不出现在任务栏」的官方小抄。
    可这一招对 Alt+Tab 不起作用，所以它就一直赖在切换列表里。
    注意：**owner 与 Alt+Tab 判据无关**，挂件那个 owner 是特意留着的，别顺手删掉
    （删了就轮到任务栏多出一个按钮了）。
  · 改的地方：Widget.ps1 里的 Set-WidgetToolWindow，用 Get/SetWindowLongPtrW 改
    GWL_EXSTYLE(-20)。user32 只在 64 位导出 *Ptr* 那一版，所以 ZZero.Desk 里
    声明了两套、按 [IntPtr]::Size 运行期分派。
  · **透明度会把这一位抹掉**：设 $form.Opacity 会让窗体变成分层窗口，
    WinForms 有可能借 CreateParams 重刷一遍扩展样式。所以补了四处：
    句柄创建时（Add_HandleCreated）、窗口显示末尾（Add_Shown 最后）、
    Apply-Transparency 里、以及托盘「显示挂件」的点击处理里。
    以后凡是「可能重刷窗口样式」的地方，都要顺手补一次，否则挂件会悄悄回到 Alt+Tab。
  · 副作用可以忽略：TOOLWINDOW 会让标题栏变矮、标题字体变小，但挂件本来就是
    FormBorderStyle = 'None'、根本没有标题栏；点击、拖动、右键菜单都不受影响。
  · 本机是虚拟机 / 云桌面，FindWindow('Progman') 返回 0，所以挂件永远走
    「普通窗口 + 托盘」那条退路 —— 但这条修复对两条路都成立，
    因为 Attach-ToDesktop 一个扩展样式都不设。


【不想用了怎么删除】

  1. 主界面「便捷工具」里，把「开机自启」和「桌面挂件」都关掉
     （关掉开机自启会在注册表里删掉那条启动项）
  2. 删掉整个程序文件夹
  3. 删掉开始菜单里的快捷方式（如果装过）
  4. 想让电脑彻底回到“从没装过”的状态，再删掉这个文件夹：
       %APPDATA%\蒸鱼清理
     （里面是白名单、开关记录、见过的软件、挂件位置，
       删了下次运行会重新生成默认的）
  5. 回收站、临时文件这些已经清理的内容不会恢复，但都不影响系统
