簡體   English   中英

在Delphi中使用ChangeDisplaySettingsEx設置主監視器

[英]Using ChangeDisplaySettingsEx in Delphi to set primary monitor

我試圖在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? 還是有更好的方法來做到這一點?

你可以試試

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

它至少可以在Delphi 2009上編譯。但是我無法對其進行測試。

編輯:

根據網上的稀缺信息( 這是我能找到的最詳細的信息 ),更改主顯示器並不是一個簡單的過程,因此您可能會錯過一步。 我有兩個監視器,但是根本無法更改主要設備,即使使用控制面板也無法更改-看起來雙頭顯示卡驅動程序不允許這樣做。 因此,以下內容未經測試,但可能會為您提供幫助:

為了設置新的主顯示屏,您必須先將當前的主顯示屏移離(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));

這是在互聯網上瀏覽大量C ++和Delphi帖子后發現的。

  • 不想使用缺少字段的聯合選項聲明新的TMyDevMode類型
  • 使用現有的TDevMode類型,但使用Move()memcopy命令和32位帶符號臨時變量設置缺少的字段
  • 從0,0 pos移開當前的主桌面,尚未應用更改
  • 使用CDS_SET_PRIMARY標志將新的當前主桌面設置為0,0,尚不應用更改
  • xy的位置和寬度,高度不應重疊,但似乎Win7可以自行解決一些問題
  • 使用空參數調用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);

我尚未對其進行驗證,但是MSDN論壇上有一篇文章對此進行了介紹,其中包括C ++代碼。 “主要”監視器是位置0,0的監視器,因此您需要重新排列監視器的位置以實現此目的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM