在Delphi中使用ChangeDisplaySettingsEx来设置主监视器

时间:2009-06-05 16:32:57

标签: windows delphi

我正在尝试在Delphi 7中使用ChangeDisplaySettingsEx将特定监视器设置为Primary。 在Windows.pas中,它被定义为

function ChangeDisplaySettingsEx(lpszDeviceName: PChar; var lpDevMode: TDeviceMode;
        wnd: HWND; dwFlags: DWORD; lParam: Pointer): Longint; stdcall;

MSDN中,ChangeDisplaySettingsEx的文档对lpDevMode有以下注释:“如果lpDevMode为NULL,则注册表中当前的所有值都将用于显示设置。”

我的目标是在具有两个活动监视器的系统上更改主监视器,而不更改任何其他内容 - 分辨率,位深度等,都应保持不变。似乎将lpDevMode传递为null(nil)是为实现此目的而提供的方法。

但是,在Delphi的Windows.pas中,lpDevMode被定义为打包记录类型(TDeviceMode),而不是指针类型。显然,Windows API的Delphi接口执行Windows API“幕后”指针的转换。

我试着这样称呼它:

var
   alldevs : array[0..maxdev] of TDisplayDevice;
   lpDevMode : pointer;

begin
   lpDevMode := nil;
   lparam := nil;
   my_hwnd := nil;

  {... snip....}

  with alldevs[NewPri] do
      ChangeDisplaySettingsEx(devicename,TDeviceMode(lpDevMode),my_hwnd,CDS_SET_PRIMARY,lparam);

这给了我一个关于“TDeviceMode(lpDevMode)”的无效的类型转换错误。如何将空指针传递给ChangeDisplaySettingsEx?或者有更好的方法吗?

3 个答案:

答案 0 :(得分:1)

你可以尝试

ChangeDisplaySettingsEx(devicename, PDeviceMode(0)^, my_hwnd, CDS_SET_PRIMARY,
  lparam);

它至少在Delphi 2009上编译。我无法测试它。

修改

根据网上的稀缺信息(this is the most detailed I could find),更改主显示不是一个简单的过程,因此您可能会错过一个步骤。我有两个显示器,但根本无法更改主设备,甚至没有控制面板 - 看起来像双头显示卡驱动程序不允许它。因此,以下内容未经过测试,但可能会对您有所帮助:

要设置新的主显示器,您必须先将当前主显示器从(0,0)位置移开。这比它需要的更棘手,因为Delphi Windows.pas文件具有不完整的TDeviceMode类型。它以

给出
_devicemodeA = record
  dmDeviceName: array[0..CCHDEVICENAME - 1] of AnsiChar;
  ...
  dmOrientation: SHORT;
  dmPaperSize: SHORT;
  dmPaperLength: SHORT;
  dmPaperWidth: SHORT;
  dmScale: SHORT;
  dmCopies: SHORT;
  dmDefaultSource: SHORT;
  dmPrintQuality: SHORT;
  dmColor: SHORT;
  ...
end;

应该是

_devicemodeA = record
  dmDeviceName: array[0..CCHDEVICENAME - 1] of AnsiChar;
  ...
  case boolean of
    FALSE: (
      dmOrientation: SHORT;
      dmPaperSize: SHORT;
      dmPaperLength: SHORT;
      dmPaperWidth: SHORT;
      dmScale: SHORT;
      dmCopies: SHORT;
      dmDefaultSource: SHORT;
      dmPrintQuality: SHORT;
    );
    TRUE: (
      dmPosition: TPoint;
      dmDisplayOrientation: DWORD;
      dmDisplayFixedOutput: DWORD;
    );
    dmColor: SHORT;
  ...
end;

您应该将固定记录类型添加到源,因为您需要dmPosition来调整显示的来源。它应该是这样的:

// get current display settings
EnumDisplaySettings(PChar(AOldPrimaryDevice), ENUM_REGISTRY_SETTINGS, DevMode1);
EnumDisplaySettings(PChar(ANewPrimaryDevice), ENUM_REGISTRY_SETTINGS, DevMode2);

// move old primary display to new position
DevMode1.dmFields := DM_POSITION;
DevMode1.dmPosition.x := DevMode2.dmPelsWidth;
DevMode1.dmPosition.y := 0;
Win32Check(ChangeDisplaySettingsEx(PChar(AOldPrimaryDevice), DevMode1, 0,
  CDS_UPDATEREGISTRY or CDS_NORESET, nil)):

// move old secondary display to (0, 0) and make the primary display
DevMode2.dmFields := DM_POSITION;
DevMode2.dmPosition.x := 0;
DevMode2.dmPosition.y := 0;
Win32Check(ChangeDisplaySettingsEx(PChar(ANewPrimaryDevice), DevMode2, 0,
  CDS_SET_PRIMARY or CDS_UPDATEREGISTRY or CDS_NORESET or DM_DISPLAYFLAGS, nil)):

// magic ???
Win32Check(ChangeDisplaySettingsEx(nil, PDeviceMode(0)^, 0, 0, nil));

答案 1 :(得分:0)

我还没有验证它,但MSDN forums中有一篇文章涵盖了这一内容并包含了C ++代码。 “主要”监视器是位于0,0的监视器,因此您需要重新排列监视器的位置以实现此目的。

答案 2 :(得分:0)

这是我浏览互联网上众多C ++和Delphi帖子后的调查结果。

  • 不想声明一个新的TMyDevMode类型,其中包含缺少字段的联合选项
  • 使用现有的TDevMode类型,但使用Move()memcopy命令和32位签名临时变量设置缺少的字段
  • 从0,0 pos移开当前主桌面,不要应用更改
  • 使用CDS_SET_PRIMARY标记将新的当前主桌面设置为0,0,不要应用更改
  • xy位置和宽度,高度不应重叠,但似乎Win7可以自行解决一些问题
  • 使用null参数调用ChangeDisplaySettingsEx以应用所有挂起的更改

设置dmPosition.x和dmPosition.y值,使用内存偏移量:

var dm: TDevMode;
var tempx, tempy: Integer;
Move(tempx, dm.dmOrientation, sizeOf(tempx));
Move(tempy, dm.dmPaperLength, sizeOf(tempy));

获取dmPosition.x和dmPosition.y值,使用内存偏移量:

var dm: TDevMode;
var tempx, tempy: Integer;
Move(dm.dmOrientation, tempx, sizeOf(tempx));
Move(dm.dmPaperLength, tempy, sizeOf(tempy));

将主桌面从display1设置为display2实例。进行更改然后应用所有挂起的更改:

flags := CDS_UPDATEREGISTRY or CDS_NORESET;
ChangeDisplaySettingsEx('\\.\DISPLAY1', devMode1, 0, flags, nil);
flags := CDS_UPDATEREGISTRY or CDS_SET_PRIMARY or CDS_NORESET;
ChangeDisplaySettingsEx('\\.\DISPLAY2', devMode2, 0, flags, nil);
ChangeDisplaySettingsEx(nil, PDeviceMode(0)^, 0, 0, nil);