如何通过Windows API实现指定显示器的开关控制
实现Windows「仅在指定显示器显示」的正确方案
问题背景
需要模拟Windows系统自带的「仅在1/2屏幕显示」功能,尝试用ChangeDisplaySettingsEx控制单显示器开关:将dmPelsWidth和dmPelsHeight设为0能成功关闭目标显示器,但恢复原有设置时完全没反应;用SendMessage则会影响所有显示器,达不到单屏切换的效果。
原代码问题分析
- 恢复设置时未明确标记
DEVMODE的dmFields:系统无法识别需要恢复哪些显示参数,导致操作被忽略 - 使用
CDS_UPDATEREGISTRY | CDS_GLOBAL参数过于强制,可能干扰系统的显示配置逻辑 - 关闭显示器的操作未明确指定修改字段,虽然能生效,但给后续恢复埋下隐患
修复方案
- 完整保存显示配置:通过
EnumDisplaySettings获取当前显示器的全量配置,包括分辨率、位置、刷新率等,确保old_settings保留所有必要参数和dmFields标记 - 精准控制参数字段:禁用显示器时,明确设置
dmFields = DM_PELSWIDTH | DM_PELSHEIGHT,告诉系统只修改分辨率参数 - 调整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
相关产品推荐
相关产品推荐

