RunAsDate 替代品,补上了缺失的部分
多年来,RunAsDate 一直是“在 Windows 上让这个程序以另一个日期运行”的答案,而且是个好答案。本页讲的是两者的不同之处,以及 RunAsDate 在哪些情况下仍是更好的选择。
并排对比
| RunAsDate | Chrono Mock | |
|---|---|---|
| 让一个应用以虚拟日期运行 | 是 | 是 |
| 不动系统时钟 | 是 | 是 |
| 被拦截的时间函数 | 5 | 44(30 个被偏移,14 个仅计数) |
| 比真实时间更快的时钟 | 不提供 | 任意整数倍率 |
| 冻结时钟 | 是,默认如此 | 是 |
| 应用运行期间跳转 | 只能在设定的秒数后回到真实日期 | 向前和向后,跳到任意时刻 |
| 仅对该进程生效的时区 | 文档中未提及 | 是,固定偏移量 |
| 子进程继承会话 | 文档中未提及 | 是 |
| 附加到已在运行的应用程序 | 是,自 1.40 版起 | 否 - 它自己启动应用程序 |
| 同时以不同日期运行多个应用程序 | 是 | 否 - 一次只有一个会话 |
| 告诉你是否生效 | 否 | 判定,逐个通道,附调用次数 |
| Electron 和 Chromium 应用 | 文档中未提及 | 独立的机制 |
| 可用于 CI 的命令行 | 是 | 是,带退出码和 JSON |
| 源代码 | 免费软件,闭源 | GPL-3.0 |
| 体积 | 下载 47 KB,64 位版 57 KB | 命令行版约 2.4 MB,带窗口版约 70 MB |
| 旧版 Windows | 最早到 Windows 2000 | Windows 10 和 11 |
“文档中未提及”的意思是 RunAsDate 的页面没有提到这项功能,并不是声称该工具没有这项功能。 除非打开 RunAsDate 的选项 Move the time forward according to the real time,否则它的时钟静止不动。
最重要的差别
不在于通道的数量。而在于 RunAsDate 在它自己的文档里老实地告诉你,它“对从其他来源获取当前日期/时间的应用不起作用”——然后让你自己去弄清楚你的应用是不是其中之一。
Chrono Mock 把同一句话当作需要测量的东西。每次会话都以一个判定、应用实际读取过的通道及各自的次数、被遗漏的通道,以及在应用还没询问时钟之前就被发现打开了网络连接时的警告结束。
一个看起来时间被改了、其实没有的应用,比一个根本没有启动的应用更糟——它会产出一个毫无意义的通过的测试。 审计是如何工作的 →
五个函数,还是 44 个通道
RunAsDate 拦截 GetSystemTime、GetLocalTime、GetSystemTimeAsFileTime、NtQuerySystemTime 和 GetSystemTimePreciseAsFileTime。对非常多的应用来说,这确实足够了,因为挂钟时间就是在这些地方被读取的。
其余的部分,则是与日期相关的代码容易藏身之处:
- 时区 - 报告时区的两个函数,加上在时区之间换算的六个函数,报表落到错误日期正是因为它们
- 经过时间轴——滴答计数和无偏的中断时间,试用期倒计时通常测量的正是它们
- 休眠,让延迟成为会话时钟上的延迟,而不是真实时钟上的延迟,还有对象等待,它们被计数并保持真实时长
- 定时器——可等待定时器、窗口定时器、线程池定时器和多媒体定时器
- 进程创建,让安装程序的子进程在同一个会话中运行,而不是跑在当下的日期
- 网络连接,作为时间可能来自服务器的迹象被计数
在 44 个通道中,30 个被换到会话时钟上。其余 14 个只计数并保持真实,所以报告会列出它们,而不会声称它们被偏移了。墙上时钟和时区在每个会话中都会被偏移。经过时间轴和等待在你用 --scale-duration 要求时被监视,高分辨率计数器则用 --scale-qpc。
什么时候 RunAsDate 是更好的选择
说真的,而且并不少见:
- 你只需要一个日期、正常速度、马上就要。RunAsDate 的下载不到 60 KB,没有需要学习的窗口,多年来一直在做的正是这件事。
- 你在用较旧的 Windows。RunAsDate 最早支持到 Windows 2000。这个工具面向 Windows 10 和 11,在更旧的系统上没有测试过。
- 体积很重要。47 KB 的下载对比命令行版约 2.4 MB 或带窗口版约 70 MB,根本不在一个量级。
- 你不想要判定。测量覆盖情况意味着要去读结果。如果这个测试是用完即弃的,那就是你没有要求的额外负担。
- 应用程序已经在运行。RunAsDate 自 1.40 版起可以附加到正在运行的进程。Chrono Mock 自己启动应用程序,所以无法重新启动的应用程序超出了它的能力范围。
- 你想同时以不同日期运行多个应用程序。RunAsDate 会给每个应用程序各自的日期。Chrono Mock 一次只运行一个会话。
两者也可以并存。这里没有任何东西会阻止你为快速的场景继续保留 RunAsDate。
两者都不是为此而生的
两个工具都会出现在关于延长试用期的搜索里。这个工具不是为此而做的,这里也不会有任何示例、预设或页面演示这一点。Chrono Mock 是用来测试你自己负责的软件的——你自己的许可证到期、你自己的续费逻辑、你自己的月末报表。
这也是最不可能奏效的情形。许可证保护通常通过刻意选择的、难以拦截的途径读取时间——共享的用户模式数据页、直接系统调用、服务器——而时钟向后走正是这类代码被编写来检测的情况。审计会告诉你它没有生效,这是诚实的答案,而不是有用的答案。