开源项目: Resolution Switcher

版权声明:所有博客文章除特殊声明外均为原创,允许转载,但要求注明出处。

在最近的项目中,我们计划支持两种不同屏幕的机器:1920 * 1080 横屏(很常见),以及 1600 * 1200 竖屏(比较罕见)。遗憾的是,我手头并没有一台真正的测试机,尽管笔记本可以同时支持两种分辨率,但调试时要去系统设置里反复切换分辨率还是很烦人的。因此,我决定自己写个工具来帮助自己。现在已经有了一个可用的版本,开源到 Github: Resolution Switcher

在开始动手之前,我也简单搜索了一下其他人是否写过类似的程序。在 Github 上发现了一个: Quick Change Resolution ,有趣的一点:它的开发平台是 Delphi

关于技术选型

这里稍稍跑一点题,说说有关技术选型的问题。在写下这篇文章的时间点(2021年底),开发 Windows 桌面平台的技术应该说正处于一个低潮期(与Web和移动平台相比),但也出现了不少新的选择。如果以 C++ 为编程语言的话,MFC/WTL 之类已经有些太老了,不太值得继续投资。Qt 是一个流行且不错的选择,但对于小工具来说体积有点过于庞大。另一个 wxWidgets 对于小工具来说其实比较合适,最大的问题在于能找到的参考资料太少了。其他私有且不开源的技术这里不做讨论。

既然是在 Windows 平台,微软的技术栈当然是应该考虑的。WinFormWPF 已经开源且迁移到了 .Net Core,但它们可以说是已经被微软放弃的技术,将来也只会慢慢衰落下去。UWP 基本上也已经被判了死刑。主要由社区维护的 Avalonia/Uno Platform 我了解有限,从别人的分析看还很不成熟,问题很多。微软自己则最近又开了 WinUIMAUI 两个大坑,但鉴于微软一向喜欢每隔几年就重新发明轮子的不良爱好,何况这两个东西本身也存在一定冲突,我目前不打算投入资源去学习它们。

客户端开发的另外一个分支是与 Web 融合的路线。这方面的主要代表包括 Electon、微软基于 Edge 浏览器的技术、CEF 及各种衍生体等。对于是大型跨平台应用来说的确值得考虑,但小工具嵌入一个 Web 引擎还是比较过分的。所以以该项目而言就暂时不考虑这个方向了。

现在说回到 Delphi。说实话,在几年前看到它被 Embarcadero 收购之后,还是走收费路线,且价格还比较昂贵,我本来觉得这个产品恐怕会很快死掉。没想到重新了解之后发现它不但没有死,似乎还活得不错,产品线竟然还在扩充,而且总算有了免费的社区版(尽管申请注册码还是有点麻烦)。我注意到国外的书商最近也出版了几本关于 Delphi 的新书,Github 上也有一些用它和开源的 Lazarus 开发的项目在持续更新,说明这个社区尽管已经比较小众,但还是有不少死忠在继续支持它的。

从技术上讲,我认为 Delphi 有些类似于 Qt————它并不仅仅是一个 GUI 框架,而应该说是一个 Application Framework,核心类库比较全面,编译速度快,生成文件也不算大,对不太复杂的桌面应用来说其实是比较理想的选择。从语言特性上讲,与 C++ 相比,Object Pascal 的语言和工具链都要更加简单和一致,此外它也反向吸收了 C# 的部分语言特性,可以说是一门比较现代化的语言了。至于缺点, 我认为一个是 Pascal 的语法稍显啰嗦;此外,在试用 Delphi 一段时间后,我发现它还是不如其他 IDE 那样稳定,有时候会有一些恼人的小毛病,估计官方以后会出补丁包来修正这些问题。

Delphi 还有一个开源的兄弟:LazarusLazarus 从界面上看差不多相当于 Delphi 7,不是很现代化,不过它的优点在于完全开源免费,且支持 LinuxDelphi社区版是不支持Linux的)。它所使用的语言是 Free Pascal,与 Delphi 使用的 Object Pascal 相似但细节方面有很多不同。

在开始编写程序之前,我曾经花了一段时间来考虑选择哪种技术。本项目需要实现的主要是切换屏幕分辨率,这看起来并不是什么复杂的任务,参考其他项目的选择,用 Delphi 似乎是个合理的选择。当然,我并不建议读者都去用 Delphi,毕竟熟悉该环境的开发者现在已经比较稀有,技术上也存在断层。我把它作为个人的一个有效选项,是因为多年之前我还是比较熟悉且喜欢 Delphi 这个工具的,也对它有比较深的感情,尽管多年未碰过,重新捡起来还是相对容易的。

但最终我改变了想法。

开发

我用 Lazarus 编写了 Resolution Switcher 的第一个原型版本。但在编写过程中,我意识到问题比我最初想象的要复杂。如果仅仅是改变屏幕分辨率的话,只需要调用两个 API 函数即可,这是很容易的,也是 Delphi 完全支持的。但我希望的功能还包括:

  • 设置屏幕方向(横向/纵向)
  • 设置屏幕缩放比例
  • 获取显示器的最佳分辨率/缩放比例

这些功能是我参考的 Quick Change Resolution 项目所不具备的。之所以会有这样的要求,是因为我目前使用的笔记本默认缩放比例是 150%,而目标机器缩放是 100%,这两种比例下的显示效果还是有很大差别的。最后一个要求则是在支持的显示模式较多时,让用户更清楚地看到哪种才是显示器的最佳分辨率。获取这些信息要用到一个不太为人所知的 EDID。

在参考了一些资料后,我意识到要实现这些要求是个比较麻烦的工作:不仅需要调用大量 Win32 API,有些还是未公开的接口;某些比较复杂的结构(如 DEVMODE)在 Delphi 中的定义是不完整的。要把这些内容翻译到 Pascal 工作量有点大,当然这也可能和我重新捡起 Delphi 的时间有限,还没充分了解其中一些技术内幕有关。

最终我还是决定:用 C++/CLI 封装本地调用,WinForm 来做界面。有朋友可能会问,干嘛不用更新一点的 WPF?其实我也有考虑过,但是发现 WPF 竟然没有原生支持系统托盘图标(Tray Icon),还是要引入 WinForm 来解决,那还不如直接用 WinForm 好了。

本程序最终是基于 .Net6.0Visual Studio 2022 编写的。这也是编写该程序时新发布的平台,与传统的基于 .Net Framework 平台相比,在项目和代码结构上略有不同,好在差别不算太大,遇到的一些技术问题通过网络搜索也很简单地解决了。

使用

Resolution Switcher 启动后不显示窗口,而是添加到任务栏图标。右击图标会弹出如下菜单:

Tray menu of Resolution Switcher

选择 Settings 显示设置界面。在这里你可以定义要显示的目标分辨率、方向和缩放比例:

Main Screen of Resolution Switcher

在添加分辨率之后,你有两种方法来执行切换:要么通过上述右键菜单选择,或者也可以双击图标显示主界面,选择要设置的分辨率:

Main Screen of Resolution Switcher

如你所见,这是一个很简单的 UI,没有在设计上下太大功夫。由于切换屏幕分辨率是一个比较小众的需求,我不太清楚有多少用户会对该程序该兴趣,所以目前的设计只是满足我个人的要求,没有做什么优化。如果读者有类似要求、或者有好的想法,欢迎通过 Github 项目主页 和我联系。