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

如何用Delphi实现Windows 10桌面显示器的开关控制?

Windows 10下用Delphi控制显示器开关的解决方案

旧版系统中使用的SendMessage(Application.Handle, WM_SYSCOMMAND, SC_MONITORPOWER, -1)在Windows 10失效,核心原因是系统对WM_SYSCOMMAND的接收窗口限制更严格,发送到应用窗口不再生效。以下是两种可行的实现方式:

方法一:发送消息到桌面窗口

将消息发送到系统桌面窗口(而非应用窗口),Windows 10能正确处理该命令,实现简单:

uses
  Windows;

const
  SC_MONITORPOWER = $F170;
  // 参数说明:
  // -1: 开启显示器
  // 1: 进入低功耗模式
  // 2: 关闭显示器

procedure TurnOffMonitor;
begin
  SendMessage(GetDesktopWindow(), WM_SYSCOMMAND, SC_MONITORPOWER, 2);
end;

procedure TurnOnMonitor;
begin
  SendMessage(GetDesktopWindow(), WM_SYSCOMMAND, SC_MONITORPOWER, -1);
end;

该方法兼容性较好,大部分Win10环境下都能正常工作。如果仍失效,可尝试下面的官方API方案。

方法二:使用Display Config API(推荐Win10+)

通过系统原生的Display Config API修改显示配置,稳定性更高,适合Windows 10及以上系统,支持多显示器场景的精细控制:

首先补充声明相关API和结构体(Delphi默认Windows单元可能未完全包含):

uses
  Windows;

type
  LUID = record
    LowPart: DWORD;
    HighPart: LONG;
  end;

  DISPLAYCONFIG_SOURCE_DEVICE_NAME = record
    header: DISPLAYCONFIG_DEVICE_INFO_HEADER;
    viewGdiDeviceName: array[0..CCHDEVICENAME-1] of WCHAR;
  end;

  DISPLAYCONFIG_TARGET_DEVICE_NAME = record
    header: DISPLAYCONFIG_DEVICE_INFO_HEADER;
    outputTechnology: DWORD;
    edidManufactureId: DWORD;
    edidProductCodeId: DWORD;
    connectorInstance: DWORD;
    monitorFriendlyDeviceName: array[0..CCHDEVICENAME-1] of WCHAR;
    monitorDevicePath: array[0..MAX_PATH-1] of WCHAR;
  end;

  DISPLAYCONFIG_PATH_INFO = record
    sourceInfo: DISPLAYCONFIG_SOURCE_DEVICE_NAME;
    targetInfo: DISPLAYCONFIG_TARGET_DEVICE_NAME;
    flags: DWORD;
  end;

  DISPLAYCONFIG_SOURCE_MODE = record
    width: UINT32;
    height: UINT32;
    pixelFormat: UINT32;
    position: POINTL;
  end;

  DISPLAYCONFIG_TARGET_MODE = record
    targetVideoSignalInfo: DISPLAYCONFIG_VIDEO_SIGNAL_INFO;
  end;

  DISPLAYCONFIG_DESKTOP_IMAGE_INFO = record
    pathSourceSize: SIZE;
    desktopImageRegion: RECTL;
  end;

  DISPLAYCONFIG_MODE_INFO = record
    infoType: DWORD;
    id: DWORD;
    adapterId: LUID;
    mode: record
      case Integer of
        0: (sourceMode: DISPLAYCONFIG_SOURCE_MODE);
        1: (targetMode: DISPLAYCONFIG_TARGET_MODE);
        2: (desktopImageInfo: DISPLAYCONFIG_DESKTOP_IMAGE_INFO);
    end;
  end;

const
  QDC_ALL_PATHS = 1;
  SDC_APPLY = $00000080;
  SDC_USE_SUPPLIED_DISPLAY_CONFIG = $00000001;
  DISPLAYCONFIG_PATH_ACTIVE = $00000001;

function QueryDisplayConfig(flags: DWORD; var numPathArrayElements: UINT; var pathArray: PDISPLAYCONFIG_PATH_INFO; var numModeInfoArrayElements: UINT; var modeInfoArray: PDISPLAYCONFIG_MODE_INFO; var currentTopologyId: PDWORD): LONG; stdcall; external 'user32.dll';
function SetDisplayConfig(numPathArrayElements: UINT; pathArray: PDISPLAYCONFIG_PATH_INFO; numModeInfoArrayElements: UINT; modeInfoArray: PDISPLAYCONFIG_MODE_INFO; flags: DWORD): LONG; stdcall; external 'user32.dll';

然后实现开关显示器的函数:

procedure TurnOffMonitor;
var
  numPaths, numModes: UINT;
  paths: array of DISPLAYCONFIG_PATH_INFO;
  modes: array of DISPLAYCONFIG_MODE_INFO;
  i: Integer;
begin
  // 获取当前显示路径和模式的数量
  QueryDisplayConfig(QDC_ALL_PATHS, numPaths, nil, numModes, nil, nil);
  SetLength(paths, numPaths);
  SetLength(modes, numModes);
  QueryDisplayConfig(QDC_ALL_PATHS, numPaths, @paths[0], numModes, @modes[0], nil);

  // 禁用所有活动显示路径
  for i := 0 to numPaths - 1 do
    paths[i].flags := paths[i].flags and not DISPLAYCONFIG_PATH_ACTIVE;

  // 应用修改后的配置
  SetDisplayConfig(numPaths, @paths[0], numModes, @modes[0], SDC_USE_SUPPLIED_DISPLAY_CONFIG or SDC_APPLY);
end;

procedure TurnOnMonitor;
var
  numPaths, numModes: UINT;
  paths: array of DISPLAYCONFIG_PATH_INFO;
  modes: array of DISPLAYCONFIG_MODE_INFO;
  i: Integer;
begin
  QueryDisplayConfig(QDC_ALL_PATHS, numPaths, nil, numModes, nil, nil);
  SetLength(paths, numPaths);
  SetLength(modes, numModes);
  QueryDisplayConfig(QDC_ALL_PATHS, numPaths, @paths[0], numModes, @modes[0], nil);

  // 启用所有显示路径
  for i := 0 to numPaths - 1 do
    paths[i].flags := paths[i].flags or DISPLAYCONFIG_PATH_ACTIVE;

  SetDisplayConfig(numPaths, @paths[0], numModes, @modes[0], SDC_USE_SUPPLIED_DISPLAY_CONFIG or SDC_APPLY);
end;

注意事项

  • 部分环境下,Display Config API可能需要程序以管理员权限运行,可在项目设置中添加UAC清单。
  • 多显示器场景下,若需单独控制某台显示器,可通过筛选特定的targetInfo(如显示器名称、设备路径)来实现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 11:25:14