[英]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帖子后發現的。
設置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.