
像 TranslucentTB 这类工具,体积小、功能单,看起来是个"玩具项目"。但它身上集中了一类常驻小工具特有的工程问题:它的工作对象不是自己,而是系统里的另一个进程。
这篇用任务栏美化程序作为例子,把这类工具的工程要点梳理一遍。写过桌面常驻程序的人应该都有共鸣。
任务栏属于系统的桌面进程,而这类工具做的事情,是给那个进程里的窗口设置外观属性。
这就决定了它的生命周期模型和普通桌面程序完全不同:它不是一个独立完成工作的程序,而是一个依附于别人生命周期的调节器。
最直接的后果:那个进程重启,你设置的属性就没了。 桌面进程因为异常、更新、或者被用户手动重启时会重新创建任务栏,设置随之丢失——除非你的工具还在运行并重新设置一遍。
第二行是最影响观感的细节:如果工具启动得太晚,用户会先看到默认样式的任务栏,然后它才变成想要的样子。这个"闪一下"在体验上很扎眼,而解决办法不是"更快启动",而是在应用前先读状态、只做必要的设置,减少可见的变化过程。
两个实例会争抢同一个属性,结果就是"谁最后设置谁生效"——表现出来是效果时好时坏、随机变化。
用户往往把这种现象理解为"软件不稳定",而根因是两个进程在互相覆盖。
实现上很简单:用一个全局唯一的命名互斥对象,第二个实例启动时发现已存在就退出。
但要注意一点:不要静默退出。给一个可见的反馈("程序已在运行"),比让用户反复双击、怀疑程序坏了要好得多。这是常驻工具常见的礼貌问题。
这是这类工具最值得认真设计的一处。
轮询:按固定周期检查状态。实现简单,但带来固定频率的唤醒——耗电主要来自唤醒次数,而不是 CPU 占用百分比。
事件驱动:订阅状态变化,平时几乎不耗资源。代价是要处理漏事件与订阅失效这两种情况。
实践中的折中方案:以事件为主,加一个低频的兜底校验。这样既能保持低功耗,又不会因为漏掉一个事件而导致"长时间无效果"。
这一点在笔记本上尤其重要:一个看起来"CPU 占用 0%"的常驻程序,如果每秒唤醒一次,续航照样会掉。
TranslucentTB 这类工具想要的视觉效果,常常依赖系统内部或未公开的合成属性,而不是给第三方准备的公开接口。
直接的后果就是:系统更新之后可能失效。 这不是偶发 bug,而是这类实现方式的固有风险。
能做的应对有三步,顺序不能改:
常驻程序最难处理的支持场景就是"它没反应"。
所以要在启动过程里记录关键结果:依附进程有没有找到、属性设置有没有成功、是否发生了降级、当前用的哪条分支。
再提供一个"导出诊断信息"的入口,用户一条就能发给你。这一条决定了你能不能远程解决问题——否则只能靠用户描述"就是不行",而那种描述无法定位任何东西。
因为要在状态变化后反复应用,这个动作必须是幂等的:重复应用同一个状态不产生副作用。
否则会出现"应用两次导致效果叠加或异常"这类难查的问题。示意:
// idempotent: applying the same state twice is harmless
void ApplyState(BarState s) {
if (s == current) return;
current = s;
SetBarAppearance(s);
}先比较、再设置,是最简单的幂等实现方式。
关于这类"依附于别的进程"的常驻工具,记住四条:
这些点与"任务栏美化"本身无关,任何依附于系统进程、需要长期驻留并反复应用设置的工具,都会遇到同样的问题——把它当成一份常驻程序的工程清单来用即可。
https://www.ijinshan.com/software/TranslucentTB.html?channel=4075
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。