delphi 程序实现主屏与扩展屏的切换
delphi 程序实现双屏显示主屏与扩展屏的切换;
InitDevice: 初始化显示屏列表,成功返回显示屏数量;
ActiveScreen:设置主显示屏,AIndex为显示屏索引,Align为扩展屏相对于主屏的位置(1:左 2:右 3:上 4:下);
使用到的winAPI:EnumDisplayDevicesA、EnumDisplaySettingsA、ChangeDisplaySettingsExA。
常量列表:
CCHDEVICENAME = 32;
DISPLAY_DEVICE_ATTACHED_TO_DESKTOP = $00000001;
DISPLAY_DEVICE_PRIMARY_DEVICE = $00000004;
CDS_UPDATEREGISTRY = $00000001;
CDS_SET_PRIMARY = $00000010;
DM_POSITION = $20;
实现代码:
1 unit UDisplayer; 2 3 interface 4 uses 5 windows; 6 7 type 8 PTUDevMode = ^TUDevMode; 9 TUDevMode = record 10 dmDeviceName: array[0..CCHDEVICENAME - 1] of AnsiChar; 11 dmSpecVersion: Word; 12 dmDriverVersion: Word; 13 dmSize: Word; 14 dmDriverExtra: Word; 15 dmFields: DWORD; 16 dmPosition: TPOINT; 17 dmDisplayOrientation: DWORD; 18 dmDisplayFixedOutput: DWORD; 19 dmColor: SHORT; 20 dmDuplex: SHORT; 21 dmYResolution: SHORT; 22 dmTTOption: SHORT; 23 dmCollate: SHORT; 24 dmFormName: array[0..CCHFORMNAME - 1] of AnsiChar; 25 dmLogPixels: Word; 26 dmBitsPerPel: DWORD; 27 dmPelsWidth: DWORD; 28 dmPelsHeight: DWORD; 29 dmDisplayFlags: DWORD; 30 dmDisplayFrequency: DWORD; 31 dmICMMethod: DWORD; 32 dmICMIntent: DWORD; 33 dmMediaType: DWORD; 34 dmDitherType: DWORD; 35 dmICCManufacturer: DWORD; 36 dmICCModel: DWORD; 37 dmPanningWidth: DWORD; 38 dmPanningHeight: DWORD; 39 end; 40 41 PUDevice = ^TUDevice; 42 TUDevice = record 43 i: Integer; 44 dev: TDisplayDeviceA;//_DISPLAY_DEVICEA 45 mode: TUDevMode; 46 IsPrimary: Boolean; 47 end; 48 49 //初始化显示屏列表 50 function InitDevice: Integer; 51 //设置主显示屏,Align扩展屏相对于主屏位置(1:左 2:右 3:上 4:下) 52 function ActiveScreen(AIndex: Integer; Align: Integer): Boolean; 53 54 implementation 55 56 57 var 58 gDevices: array of TUDevice; //屏幕列表 59 gDevCount: Integer = 0; //数量 60 61 62 function InitDevice: Integer; 63 var 64 i: Integer; 65 dev: TDisplayDeviceA; 66 begin 67 i := 0; 68 gDevCount := 0; 69 SetLength(gDevices, 0); 70 FillChar(dev, SizeOf(dev), 0); 71 dev.cb := SizeOf(dev); 72 while EnumDisplayDevicesA(nil, i, dev, 0) do 73 begin 74 if (dev.StateFlags and DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) = DISPLAY_DEVICE_ATTACHED_TO_DESKTOP then 75 begin 76 SetLength(gDevices, gDevCount + 1); 77 gDevices[gDevCount].i := gDevCount; 78 gDevices[gDevCount].dev := dev; 79 FillChar(gDevices[gDevCount].mode, SizeOf(gDevices[gDevCount].mode), 0); 80 gDevices[gDevCount].mode.dmSize := SizeOf(gDevices[gDevCount].mode); 81 EnumDisplaySettingsA(dev.DeviceName, DWORD(-2), TDeviceModeA(gDevices[gDevCount].mode)); 82 gDevices[gDevCount].IsPrimary := (dev.StateFlags and DISPLAY_DEVICE_PRIMARY_DEVICE) = DISPLAY_DEVICE_PRIMARY_DEVICE; 83 gDevCount := gDevCount + 1; 84 end; 85 FillChar(dev, SizeOf(dev), 0); 86 dev.cb := SizeOf(dev); 87 i := i + 1; 88 end; 89 Result := gDevCount; 90 end; 91 92 function ActiveScreen(AIndex: Integer; Align: Integer): Boolean; 93 var 94 i, tag: Integer; 95 md: TUDevMode; 96 begin 97 Result := False; 98 if (AIndex < 0)or(AIndex >= gDevCount) then Exit; 99 100 Result := gDevices[AIndex].IsPrimary; 101 if Result then Exit; 102 103 tag := -1; 104 for i := 0 to gDevCount - 1 do 105 if gDevices[i].IsPrimary then 106 begin 107 tag := i; 108 Break; 109 end; 110 if tag = -1 then Exit; 111 112 //移动旧屏 113 FillChar(md, SizeOf(md), 0); 114 md.dmSize := SizeOf(md); 115 md.dmFields := DM_POSITION; 116 case Align of 117 3: //上 118 begin 119 md.dmPosition.Y := (-1) * Integer(gDevices[tag].mode.dmPelsHeight); 120 md.dmPosition.X := 0; 121 end; 122 4: //下 123 begin 124 md.dmPosition.Y := Integer(gDevices[tag].mode.dmPelsHeight); 125 md.dmPosition.X := 0; 126 end; 127 1: //左 128 begin 129 md.dmPosition.Y := 0; 130 md.dmPosition.X := (-1) * Integer(gDevices[tag].mode.dmPelsWidth); 131 end; 132 2: //右 133 begin 134 md.dmPosition.Y := 0; 135 md.dmPosition.X := Integer(gDevices[tag].mode.dmPelsWidth); 136 end; 137 else begin 138 md.dmPosition.Y := 0; 139 md.dmPosition.X := Integer(gDevices[tag].mode.dmPelsWidth); 140 end; 141 end; 142 ChangeDisplaySettingsExA(gDevices[tag].dev.DeviceName, TDeviceModeA(md), 0, CDS_UPDATEREGISTRY, nil); 143 gDevices[tag].mode := md; 144 //设置新屏 145 FillChar(md, SizeOf(md), 0); 146 md.dmSize := SizeOf(md); 147 md.dmFields := DM_POSITION; 148 md.dmPosition.X := 0; 149 md.dmPosition.Y := 0; 150 ChangeDisplaySettingsExA(gDevices[AIndex].dev.DeviceName, TDeviceModeA(md), 0, CDS_SET_PRIMARY or CDS_UPDATEREGISTRY, nil); 151 gDevices[AIndex].mode := md; 152 //提交设置 153 ChangeDisplaySettingsExA(gDevices[tag].dev.DeviceName, TDeviceModeA(gDevices[tag].mode), 0, CDS_UPDATEREGISTRY, nil); 154 ChangeDisplaySettingsExA(gDevices[AIndex].dev.DeviceName, TDeviceModeA(gDevices[AIndex].mode), 0, CDS_SET_PRIMARY or CDS_UPDATEREGISTRY, nil); 155 //ChangeDisplaySettingsA(TDeviceModeA(gDevices[AIndex].mode), CDS_SET_PRIMARY); 156 //刷新列表 157 InitDevice; 158 Result := True; 159 end; 160 161 end.
另附 win + p 功能代码实现:
引入 API: use ShellAPI。
1、仅计算机:ShellExecue(0, 'open', 'DisplaySwitch.exe', '/internal', nil, SW_HIDE);
2、复制:ShellExecue(0, 'open', 'DisplaySwitch.exe', '/clone', nil, SW_HIDE);
3、扩展:ShellExecue(0, 'open', 'DisplaySwitch.exe', '/extend', nil, SW_HIDE);
4、仅投影:ShellExecue(0, 'open', 'DisplaySwitch.exe', '/external', nil, SW_HIDE);