初探Windows API - 切换分辨率的实现
直接调用Windows API是不安全的行为,所以相关操作都必须在unsafe块进行
获取当前计算机分辨率信息
1 | pub fn get_current_display_mode() -> Result<DisplayMode, DisplayError> { |
Windows API 期望结构体以特定方式初始化,以免结构体中包含垃圾值
let mut devmode: DEVMODEW = mem::zeroed();
为什么?因为程序运行的时候,被分配的一块内存也有可能是上一个程序用过的,你只定义了结构体的一部分字段,但是其他字段可能还有内存本来存在的值。
所以要调用zeroed()方法用 0 字节填充所有字段,避免了使用未初始化内存的风险。
devmode.dmSize = mem::size_of::<DEVMODEW>() as u16;
- 为什么:
- API 约定: Windows API 函数(如
EnumDisplaySettingsW)在接收DEVMODEW结构体时,需要知道这个结构体的大小,以便正确地读取和写入数据。dmSize字段就是用来告知 API 结构体实际大小的。 - 版本兼容性:
DEVMODEW结构体可能会在不同的 Windows 版本中有所变化(增加字段)。通过设置dmSize,API 可以知道它正在处理的是哪个版本的结构体,从而避免读取超出实际大小的内存。 - Rust 类型转换:
mem::size_of::<DEVMODEW>()返回的是usize类型,而dmSize需要的是u16类型,所以需要进行as u16的类型转换。
- API 约定: Windows API 函数(如
更改分辨率
1 | pub fn change_display_mode(mode: &DisplayMode, permanent: bool) -> Result<(), DisplayError> { |
指定显示器版本
1 | pub fn change_display_mode_for_monitor( |
1 | pub fn restore_default_settings() -> Result<(), DisplayError> { |
列举显示器
用于给change_display_mode_for_monitor()提供精确的显示器名字
1 | pub fn enumerate_monitors() -> HashMap<String, String> { |
EnumDisplayDevicesW: 这是核心的 Windows API 函数。- 第一个参数
PCWSTR::null(): 通常用于指定要枚举的设备路径。在这里传递null表示枚举所有与系统相关的显示设备。 - 第二个参数
device_index: 当前要枚举的设备的索引。 - 第三个参数
&mut device: 一个指向DISPLAY_DEVICEW结构体的可变引用,API 将把找到的设备信息填充到这个结构体中。 - 第四个参数
0: 标志位,通常用于控制枚举行为。0表示默认行为。
- 第一个参数