Repository Wiki
nikkigallery/Whimbox

配置资源与平台支持/windows平台适配与dpi处理

本页说明已提供的 DPI 感知辅助实现:在 Windows 上尽早设置进程 DPI 感知,以避免坐标虚拟化影响截图;在 macOS 上,由平台路径管理器提供无操作处理。文中仅描述已提供源码片段可以核实的行为。

用途与范围

本页聚焦 DPI 初始化入口、Windows API 降级顺序、初始化标记及失败行为。配置资源加载、截图算法、平台工厂的选择规则以及 macOS 路径管理器的具体实现均不在已提供的源码片段中,因而不推断其内部行为。完整的平台适配与截图坐标变换需结合相应实现另行核查。

来源限制:本次任务提供了一个带行号的 DPI 辅助模块源码片段,但未提供仓库相对路径或 File Reference Base URL,也没有可调用的 ReadFile、Grep、ListFiles 工具。因此无法制作符合仓库链接规范的代码块来源引用;本页不复制代码示例,不虚构文件路径、配置项或未验证的实现。

概述

公开入口 enable_dpi_awareness() -> None 在函数内部导入 whimbox.platform.factory.get_path_manager,然后调用所得管理器的 enable_dpi_awareness()。模块注释说明:Windows 路径管理器会调用 Windows 专用的 _enable_dpi_win32() -> None;macOS 则由路径管理器执行无操作。调用方不必直接接触 Windows 的 ctypes.windll,但具体路径管理器的构造、缓存和分发规则无法从当前片段确认。

Windows 专用函数先检查模块级布尔值 _dpi_awareness_initialized,初始为 False。一旦任一设置途径被实现视为成功,便将其置为 True,记录所用级别并返回;以后调用此函数会直接返回。该标记属于当前 Python 模块的状态,并非从操作系统查询的 DPI 当前状态。

架构与职责

已确认的调用关系依次是:enable_dpi_awareness() → get_path_manager() → 所得管理器的 enable_dpi_awareness()。源码注释将 _enable_dpi_win32() 标为 WindowsPathManager.enable_dpi_awareness() 的 Windows 实现;该管理器方法本身未提供,不能进一步确认调用条件或生命周期。

Windows 专用路径通过 ctypes.windll.user32 获取 user32,优先调用 SetProcessDpiAwarenessContext;未完成时通过 ctypes.windll.shcore 调用 SetProcessDpiAwareness;仍未完成时调用 user32.SetProcessDPIAware。日志使用 whimbox.common.logger.logger,分别报告启用级别或最终失败。

这里将操作系统调用封装在平台路径管理器背后,意图是让公开入口能够用于不同平台,同时在 Windows 上争取更高等级的逐显示器感知。源码注释特别指出优先使用 Per-Monitor V2 是为了缩放显示器上的准确客户区矩形;入口文档字符串指出初始化应尽早执行,以避免 Windows 坐标虚拟化。

初始化流程

  1. 调用 enable_dpi_awareness() 时,先在函数内导入工厂函数,再取得路径管理器并调用同名方法。公开入口没有显式返回结果,故调用者不能从返回值获知启用级别。
  2. 若 Windows 专用函数已将 _dpi_awareness_initialized 置为 True,直接结束,不再次请求系统 API。
  3. 首次尝试 user32.SetProcessDpiAwarenessContext(ctypes.c_void_p(-4))。返回真值时,标记为已初始化,记录 Per-Monitor V2 并返回。
  4. 第一项没有成功或抛出异常时,尝试 shcore.SetProcessDpiAwareness(2)。返回值为 0 或 0x00000005 时均按成功处理,记录 Per-Monitor 并返回。源码没有解释第二个返回值的含义,不应据此断言操作系统状态一定发生改变。
  5. 再尝试 user32.SetProcessDPIAware();返回真值时标记成功并记录 System。
  6. 三项均未被代码判定成功时,记录警告“未能启用 DPI 感知,截图可能受系统缩放影响”。函数没有显式抛错或返回失败标志。

每次尝试都有独立的 try/except Exception,异常被忽略以便继续尝试下一级。注意 ctypes.windll.user32 的获取发生在这些 try 块之前:若获取 user32 本身失败,该异常不会被本函数的降级逻辑捕获。这也是不能把该函数描述为“任何失败都只记录警告”的原因。

关键状态与边界条件

项目已核实行为工程含义
_dpi_awareness_initialized模块级变量,初始 False;仅在一种 API 路径被判定成功时改为 True成功后同一模块中重复调用不再执行 Windows API;失败后重试仍会走尝试链
Per-Monitor V2ctypes.c_void_p(-4),SetProcessDpiAwarenessContext 返回真值才判成功第一优先级;异常或假值使流程继续
Per-Monitor数值参数 2,返回 0 或 0x00000005 被接受作为 V2 的后备方案;接受条件是代码判断,不等于额外核验实际状态
SystemSetProcessDPIAware() 返回真值才判成功最后一级后备方案
日志成功用 logger.info;所有尝试未成功用 logger.warning可以从日志识别代码选中的级别或降级失败
公开入口调用所选路径管理器的同名方法不直接执行平台判断;工厂的选择细节尚未核实

这段代码没有锁或其他同步原语。因此不能宣称 _dpi_awareness_initialized 的检查与更新对多个线程是原子的;如果多个调用同时进入,可能各自尝试系统 API。源码也没有对成功后的 DPI 设置进行重新验证或提供重置入口。关于 Windows DPI API 的系统版本要求、外部进程设置以及 GUI 框架初始化时序,当前片段没有给出可核实的约束,不能作为此处的既定保证。

API 参考

enable_dpi_awareness() -> None

公开的跨平台入口。无参数;通过 get_path_manager() 获取管理器并调用其 enable_dpi_awareness();没有显式结果值。其文档字符串要求尽早启用 DPI 感知,以避免 Windows 坐标虚拟化。此函数没有自己的异常处理;工厂或路径管理器抛出的异常能否传播取决于未提供的实现。

_enable_dpi_win32() -> None

Windows 专用实现。无参数;使用模块级标记避免已成功后的重复初始化,按 Per-Monitor V2、Per-Monitor、System 顺序尝试,最后记录警告。它捕获每一级尝试中发生的 Exception,但不会对调用者返回启用级别。其作为 WindowsPathManager.enable_dpi_awareness() 调用目标的关系只由该函数的文档字符串说明,尚未通过管理器实现交叉核实。

使用示例与验证范围

本次提供的源码只包含上述两个函数,没有提供调用方、测试、配置文件或可引用的仓库文件路径。为遵守代码示例必须来自仓库且附带实际来源链接的要求,此处不放置无法准确归属的代码块。实际集成时应查找应用启动入口对 enable_dpi_awareness() 的调用,并核实该调用是否发生在截图坐标相关操作之前;当前资料不足以证明应用已经这样调用。

故障排查与扩展边界

  • 若日志记录 Per-Monitor V2、Per-Monitor 或 System,只说明相应调用满足本模块的成功条件;本模块不输出 DPI 值、显示器信息或坐标转换结果。
  • 若记录最终警告,表示本轮全部设置尝试均未按代码标准成功,模块标记仍为 False,后续调用会再次尝试;源码明确提示截图可能受系统缩放影响。
  • 若未产生上述成功或失败日志,要区分路径管理器是否调用了 Windows 实现,以及是否在进入第一个 try 前获取 user32 时失败;这些情况无法仅由最终警告覆盖。
  • 若需修改回退顺序或成功判定,应在 Windows 专用函数中核查三种系统调用及其日志分支;若需改变跨平台策略,应先阅读工厂及各平台路径管理器的真实实现。当前资料没有测试证据,不能承诺多屏缩放、重复调用或并发调用的测试覆盖。

相关链接

当前运行上下文没有提供仓库引用基址和可确认的相关目录页面链接,因此不构造未经验证的 URL。相关实现标识为 whimbox.platform.factory.get_path_manager、WindowsPathManager.enable_dpi_awareness 及 whimbox.common.logger.logger;后续应以仓库实际文件为准补充交叉引用。

Sources

(1 files)