Конференция "WinAPI" » Отключить второй монитор
 
  • gog © (07.10.15 15:07) [0]
    Добрый день.
       Нужно написать программу (Delphi XE, программа будет работать под Win7, Win8), которая при клике на одну кнопку отключит второй монитор (если такой имеется), и только при клике на другую кнопку, или завершении работы, снова его включит. Отключенный монитор не должен включаться движением мышки или работой на клавиатуре.
       Пробовал несколько вариантов, но либо отключаются оба монитора и включаются движением мышки, либо ничего не происходит.
     Помогите пожалуйста.
  • Rouse_ © (07.10.15 19:19) [1]
    На вот на скорую руку накидал, вроде работает.

    unit Unit1;

    interface

    uses
     Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
     Dialogs, StdCtrls;

    type
     TForm1 = class(TForm)
       Button1: TButton;
       Button2: TButton;
       procedure Button1Click(Sender: TObject);
       procedure Button2Click(Sender: TObject);
     end;

    var
     Form1: TForm1;

    implementation

    {$R *.dfm}

    const
     EDD_GET_DEVICE_INTERFACE_NAME = 1;
     ENUM_REGISTRY_SETTINGS = DWORD(-2);

    procedure TForm1.Button1Click(Sender: TObject);
    var
     Display: TDisplayDevice;
     DevMode: TDevMode;
    begin
     // выключить второй монитор
     Display.cb := SizeOf(TDisplayDevice);
     EnumDisplayDevices(nil, 1 {второй монитор, для первого ноль},
       Display, EDD_GET_DEVICE_INTERFACE_NAME);
     ZeroMemory(@DevMode, SizeOf(TDevMode));
     DevMode.dmSize := SizeOf(TDevMode);
     DevMode.dmBitsPerPel := 32;
     DevMode.dmFields := DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT or
       DM_DISPLAYFREQUENCY or DM_DISPLAYFLAGS or DM_POSITION;
     ChangeDisplaySettingsEx(PChar(@Display.DeviceName[0]),
       DevMode, 0, CDS_UPDATEREGISTRY or CDS_NORESET, nil);
     ChangeDisplaySettingsEx(nil, PDevMode(nil)^, 0, 0, nil);
    end;

    procedure TForm1.Button2Click(Sender: TObject);
    var
     Display: TDisplayDevice;
     DevMode: TDevMode;
    begin
     // включить второй монитор
     Display.cb := SizeOf(TDisplayDevice);
     EnumDisplayDevices(nil, 1 {второй монитор, для первого ноль},
       Display, EDD_GET_DEVICE_INTERFACE_NAME);
     EnumDisplaySettings(PChar(@Display.DeviceName[0]),
       ENUM_REGISTRY_SETTINGS, DevMode);
     DevMode.dmFields := DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT or
       DM_DISPLAYFREQUENCY or DM_DISPLAYFLAGS or DM_POSITION;
     ChangeDisplaySettingsEx(PChar(@Display.DeviceName[0]),
       DevMode, 0, CDS_UPDATEREGISTRY or CDS_NORESET, nil);
     ChangeDisplaySettingsEx(nil, PDevMode(nil)^, 0, 0, nil);
    end;

    end.
  • Rouse_ © (07.10.15 19:28) [2]
    ЗЫ: ну и для понимания работы кода, смотри: https://msdn.microsoft.com/en-us/library/windows/desktop/dd183413(v=vs.85).aspx

    а именно:

    > To detach the monitor, set DEVMODE.dmFields to DM_POSITION
    > but set DEVMODE.dmPelsWidth and DEVMODE.dmPelsHeight to
    > zero.


    т.е. данный код не то чтобы выключает монитор, а отключает его напрочь из системы (через настройки его потом у меня подключить не получилось почему-то, хотя может не там смотрел).

    Но по факту - результат именно тот, что ты и хотел.
  • gog © (08.10.15 08:30) [3]
    Огромное спасибо.
    Работает прекрасно
  • gog © (08.10.15 10:04) [4]
    Одна маленькая проблема.
    При запуске, программа прячет таскбар и разварачивается на весь экран (WindowState  = wsMaximized, BorderStyle = bsSingle) включая область спрятанного таскбара. Однако после выключения второго монитора, она чуть уменьшается, оставляя место под таскбар (сам таскбар не виден). ShowWindow(MyWindowHandle, SW_MAXIMIZED) не помогает.
    А нужно что она снова занимала бы весь экран.
    Можете подсказать как это сделать?
  • Rouse_ © (08.10.15 11:00) [5]
    Ну ручками размеры ей выставь. Ты же знаешь разрешение основного монитора. т.е. не максимизируй, а играйся с Width+Height
  • gog © (08.10.15 14:26) [6]
    Поставил после выключения второго экрана код:
     frmMain.Top:= 0;
     frmMain.Left:= 0;
     frmMain.Width:= Screen.Width;
     frmMain.Height:= Screen.Height;
    даже BorderStyle изменил на bsSizeable, а WindowState на wsNormal, все по старому. Только вот что уловил, когда прохожу дебаггером, форма развертывается на полный экран на какое то мгновение и потом уменьшается.
  • Rouse_ © (08.10.15 14:52) [7]
    Встань бряком на procedure TControl.Resize и посмотри по стеку откуда идет вызов в тот момент, когда происходит уменьшение.
  • Rouse_ © (08.10.15 14:58) [8]
    Вот теперь пример, проверь, у меня все работает штатно: http://rouse.drkb.ru/tmp/display_test.zip
  • Rouse_ © (08.10.15 14:59) [9]
    ЗЫ: в архиве исходный код и скомпилированный экзешник, поэтому Хром будет ругаться мол "не рекомендуется скачивать". Не обращай внимания - конечно там вирус :)
  • K-1000 © (17.10.15 14:24) [10]

    > Rouse_ ©   (08.10.15 14:59) [9]


    Ещё вот такой вариант есть, но с ограничением на версию Windows:
    http://habrahabr.ru/sandbox/38555/
 
Конференция "WinAPI" » Отключить второй монитор
Есть новые Нет новых   [118638   +31][b:0][p:0.001]