You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Windows API实现指定显示器的开关控制

实现Windows「仅在指定显示器显示」的正确方案

问题背景

需要模拟Windows系统自带的「仅在1/2屏幕显示」功能,尝试用ChangeDisplaySettingsEx控制单显示器开关:将dmPelsWidth和dmPelsHeight设为0能成功关闭目标显示器,但恢复原有设置时完全没反应;用SendMessage则会影响所有显示器,达不到单屏切换的效果。

原代码问题分析

  1. 恢复设置时未明确标记DEVMODE的dmFields:系统无法识别需要恢复哪些显示参数,导致操作被忽略
  2. 使用CDS_UPDATEREGISTRY | CDS_GLOBAL参数过于强制,可能干扰系统的显示配置逻辑
  3. 关闭显示器的操作未明确指定修改字段,虽然能生效,但给后续恢复埋下隐患

修复方案

  1. 完整保存显示配置:通过EnumDisplaySettings获取当前显示器的全量配置,包括分辨率、位置、刷新率等,确保old_settings保留所有必要参数和dmFields标记
  2. 精准控制参数字段:禁用显示器时,明确设置dmFields = DM_PELSWIDTH | DM_PELSHEIGHT,告诉系统只修改分辨率参数
  3. 调整API调用标志:恢复时使用CDS_RESET强制系统重新加载配置,避免缓存导致的恢复失败

修复后的完整代码

#include <iostream>
#include <windows.h>
#include <cstring>
using namespace std;

int main() {
    DISPLAY_DEVICEA device;
    DEVMODE settings;
    DEVMODE old_settings;
    int iDevNum = 0;

    ZeroMemory(&device, sizeof(device));
    ZeroMemory(&settings, sizeof(settings));
    ZeroMemory(&old_settings, sizeof(old_settings));

    device.cb = sizeof(DISPLAY_DEVICEA);
    settings.dmSize = sizeof(DEVMODE);
    old_settings.dmSize = sizeof(DEVMODE);

    while (EnumDisplayDevices(NULL, iDevNum, &device, EDD_GET_DEVICE_INTERFACE_NAME)) {
        if (strcmp(device.DeviceName, "\\\\.\\DISPLAY1") == 0) {
            // 获取当前显示器的完整配置
            if (!EnumDisplaySettings(device.DeviceName, ENUM_CURRENT_SETTINGS, &old_settings)) {
                cout << "获取当前显示设置失败,错误码:" << GetLastError() << endl;
                break;
            }

            // 配置禁用显示器的参数
            settings = old_settings;
            settings.dmPelsWidth = 0;
            settings.dmPelsHeight = 0;
            settings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; // 明确指定修改字段

            // 执行禁用操作
            LONG result = ChangeDisplaySettingsEx(device.DeviceName, &settings, NULL, CDS_UPDATEREGISTRY, NULL);
            if (result != DISP_CHANGE_SUCCESSFUL) {
                cout << "禁用显示器失败,错误码:" << result << endl;
            } else {
                cout << "显示器已禁用,按任意键恢复..." << endl;
                cin.get();

                // 恢复原有配置,强制系统重新加载
                result = ChangeDisplaySettingsEx(device.DeviceName, &old_settings, NULL, CDS_RESET | CDS_UPDATEREGISTRY, NULL);
                if (result != DISP_CHANGE_SUCCESSFUL) {
                    cout << "恢复显示器失败,错误码:" << result << endl;
                } else {
                    cout << "显示器已恢复正常" << endl;
                }
            }
            break;
        }
        iDevNum++;
    }

    return 0;
}

额外注意事项

  • 设备名称验证:\\\\.\\DISPLAY1是示例设备名,实际使用前可通过遍历EnumDisplayDevices确认目标显示器的正确名称
  • 权限要求:修改显示配置需要管理员权限,否则会操作失败
  • 多屏切换逻辑:如果要实现「仅在某显示器显示」,需遍历所有显示器,禁用非目标设备同时将目标设备设为主显示器(可通过设置dmPosition和dmDisplayFlags实现)
  • 错误排查:务必检查API返回值,ChangeDisplaySettingsEx的返回值如DISP_CHANGE_RESTART表示需要重启生效,需特殊处理

内容的提问来源于stack exchange,提问作者inpostor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 09:43:12