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);

posted @ 2015-12-07 10:39  伯通心智  阅读(2288)  评论(0编辑  收藏  举报