Получение и установка видеорежимов в Windows

Статьи » Система » Получение и установка видеорежимов в Windows

При разработке приложений, которые затем будут использоваться на большом числе различных ПК очень полезно иметь возможность не только получения информации о текущем видеорежиме, но и возможность получить все доступные видеорежимы для данного ПК. Еще одна область, где используется переключение видеорежимов при написании игр без использования DirectX.

https://mekka.spb.ru бумага для печати 500 листов купить купить бумагу а3 500 листов.

Получение списка видеорежимов

Получить видеорежимы можно серией вызовов EnumDisplaySettings. Функция EnumDisplaySettings возвращает информацию о видеорежиме, указанном в параметре IModeNode. Функции необходимо передать структуру типа TDevMode, в которую будет записана информация о видеорежиме. Данная структура имеет поля, характеризующие видеорежим: разрешение (dmPelsWidth, dmPelsHeight), количество битов цветности (dmBitsPerPel), частота обновления экрана (dmDisplayFrequency) и др.

function EnumDisplaySettings(lpszDeviceName: PWideChar; iModeNum: DWORD;
  var lpDevMode: TdeviceMode): BOOL; stdcall;

Параметры

lpszDeviceName
Указатель на нуль-терминальную строку, определяющую экранное устройство, видеорежимы которого мы хотим получить. В Windows 95 and 98 (и в наших приложениях :)) ), lpszDeviceName должно быть равно Nil.
iModeNum
Номер видеорежима
lpDevMode
Структура, в которой будет возвращена информация о видеорежиме. Cтруктура довольно сложна и используется не только для видео устройств, но нам понадобятся только следующие ее поля.

Поле Описание

DmBitsPerPel
Количество бит на пиксел
DmPelsWidth
Ширина в пикселях
DmPelsHeight
Высота в пикселях
DmDisplayFlags
  • DM_GRAYSCALE - Черно-белое устройство
  • DM_INTERLACED - Черезстрочная развертка.
  • Если флаг не установлен, подразумевается построчная развертка
dmDisplayFrequency
Частота обновления экрана
DmPosition
Windows 98, Windows 2000: Номер монитора для конфигураций с несколькими мониторами
DmFields
Поле dmFields используется при смене видеорежима для указания, какие именно из параметров устройства мы хотим изменить. Каждый бит поля определяет необходимость смены одного из параметров. Возможные значения:
  • DM_BITSPERPEL - Изменить количество бит на пиксель на значение указанное в поле dmBitsPerPel.
  • DM_PELSWIDTH - Изменить ширинку экрана на значение указанное в поле dmPelsWidth.
  • DM_PELSHEIGHT - Изменить выстоу экрана на значение указанное в поле dmPelsHeight
  • DM_DISPLAYFLAGS - Изменить флаги.
  • DM_DISPLAYFREQUENCY - Изменить частоту обновления dmDisplayFrequency.
  • DM_POSITION - Windows 98, Windows 2000: изменить номер монитора.

Если lpDevMode равно nil, из реестра берется информация о видеорежиме установленном по умолчанию. Передавая в lpDevMode nil и в dwFlags 0 можно получить настройки текущего видеорежима.

Ниже приведена процедура, получающая и отображающая в ListBox все возможные видеорежимы.

procedure TForm1.FormCreate(Sender: TObject);
var
  i: Integer;
  DevMode : TDeviceMode;
begin
  i:=0;
  while EnumDisplaySettings(nil,i,DevMode) do
  begin
    with Devmode do
      ListBox1.Items.Add(Format('%dx%d %d Colors',
      [dmPelsWidth,dmPelsHeight,Int64(1) shl dmBitsperPel]));
    Inc(i);
  end;
end;

Получение параметров текущего видеорежима

Помимо вызова EnumDisplaySettings инфомацию о текущем видеорежиме можно получать и другими способами.Получить количество битов цвета текущего видеорежима можно и другим способом:

GetDeviceCaps(Form1.Canvas.Handle, BITSPIXEL) *
GetDeviceCaps(Form1.Canvas.Handle, PLANES)

Получаемые значения при этом:

  • 1 = 2 бита на точку
  • 4 = 16 бита на точку
  • 8 = 256 бита на точку
  • 15 = 32768 бита на точку (возвркащает 16 для большинства драйверов экранных устройств)
  • 16 = 65535 бита на точку
  • 24 = 16,777,216 бита на точку
  • 32 = 16,777,216 бита на точку (то же 24)

Непосредственно количество цветов можно так же легко подсчитать:

NumberOfColors := (1 shl
(GetDeviceCaps(Form1.Canvas.Handle, BITSPIXEL) *
GetDeviceCaps(Form1.Canvas.Handle, PLANES));

Текущее разрешение экрана можно узнать с помощью вызова GetSystemMetrics() в качестве параметров передается:

SM_CXSCREEN
высота рабочей области экрана в пикселах
SM_CYSCREEN
ширина рабочей области экрана в пикселах
SM_CXFULLSCREEN
высота всей экранной области в пикселах
SM_CYFULLSCREEN
ширина всей экранной области в пикселах

Ниже приведен пример получения высоты и ширины рабочей области экрана (для всей экранной области надо просто поменять параметры вызова GetSystemMetrics):

var
  x, y: Integer;
  Mode: string;
begin
  x:=GetSystemMetrics(Sm_Cxscreen);
  y:=GetSystemMetrics(Sm_CYscreen);
  Mode:=Format('%d x %d',[x,y]);
  if y=480 then
    Mode:=Mode+('Standard VGA')
  else
    Mode:=Mode+('Super VGA');
  StaticText1.Caption:=Mode;
end;

Установка видеорежима

Как мы убедились получения списка и параметров видеорежимов не проблема. Теперь разберемся с программной сменой видеорежимов. Функция ChangeDisplaySettings предназначена для изменения текущего видеорежима экрана и при необходимости обновления этой информации в реестре Windows.

function ChangeDisplaySettings(var lpDevMode: TDeviceMode;
dwFlags: DWORD): Longint; stdcall;

Параметры:

lpDevMode
Структура с описанием видеорежима, на который мы хотим переключиться. Поля структуры были рассмотрены ранее.
dwFlags
Определяет как будет изменен видеорежим.
  • 0 - Немедленное изменение видеорежима. Установка данного флага возвращает в видеорежим по умолчанию, установленному в реестре, если он был изменен с применением флага CDS_FULLSCREEN, при этом первый параметр функции должен быть nil и флаги равны 0.
  • CDS_UPDATEREGISTRY - Видеорежим будет изменен немедленно и информация записана в реестр в пользовательский профиль.
  • CDS_TEST - Запрос теста видеорежима средствами Windows
  • CDS_FULLSCREEN - Установка видеорежима временна.
  • CDS_GLOBAL - Видеорежим будет изменен для всех пользователей данной машины. Иначе видеорежим меняется только для текущего пользователя. Используется вместе с флагом CDS_UPDATEREGISTRY.
  • CDS_SET_PRIMARY - Видеорежим становится первичным.
  • CDS_RESET - Параметры видеорежима будут изменены, даже если совпадают с текущими.
  • CDS_NORESET - Изменения будут записаны в реестр, но не вступят в силу. Используется с флагом CDS_UPDATEREGISTRY
Возвращаемое значение:
  • DISP_CHANGE_SUCCESSFUL Изменения прошли успешно.
  • DISP_CHANGE_RESTART Необходима перезагрузка для вступления изменений в силу
  • DISP_CHANGE_BADFLAGS Передан неверный набор флагов
  • DISP_CHANGE_BADPARAM Неверные параметры.
  • DISP_CHANGE_FAILED Драйвер видеоустройства не смог установить режим
  • DISP_CHANGE_BADMODE Видеорежим не поддерживается
  • DISP_CHANGE_NOTUPDATED Windows NT/2000: Ошибка записи в реестр

При немедленном изменении видеорежима всем запущенным приложениям рассылается сообщение WM_DISPLAYCHANGE.

А вот и пример смены видеорежима:

{...}

type
  TForm1 = class(TForm)
    Button1: TButton;
    ListView1: TListView;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure ListView1DblClick(Sender: TObject);
  private
    { Private declarations }
    {Массив для хранения информации о видеорежимах}
    DevMode : array[0..20] of TDeviceMode;
  public
    { Public declarations }
end;

{...}

procedure TForm1.FormCreate(Sender: TObject);
begin
  {Настройка ListView}
  ListView1.ViewStyle := vsReport;

  ListView1.RowSelect := TRUE;

  ListView1.Columns.Add;
  ListView1.Columns.Add;
  ListView1.Columns[0].Caption := 'Width x Height';
  ListView1.Columns[0].Width := 100;
  ListView1.Columns[1].Caption := 'Colors';
  ListView1.Columns[1].Width := 100;
end;

{Процедура получения списка режимов}
procedure TForm1.Button1Click(Sender: TObject);
var
  tmpStr1, tmpStr2 : string;
  tmpDC : HDC;
  x, Selection, cxScreen, cyScreen, Resolution : Integer;
begin
  { Запоминаем текущие настройки}
  tmpDC := getDC(Handle);
  try
    cxScreen := GetSystemMetrics(SM_CXSCREEN);
    cyScreen := GetSystemMetrics(SM_CYSCREEN);
    Resolution := GetDeviceCaps(tmpDC, BITSPIXEL);
  finally
    ReleaseDC(Handle, tmpDC);
  end;

  ListView1.Items.Clear;
  x := 0;

  { Получаем список видеорежимов}
  while EnumDisplaySettings(nil,x,DevMode[x]) do
  begin

    { Разрешение экрана }
    tmpStr1 := IntToStr(DevMode[x].dmPelsWidth) + 'x' +
    IntToStr(DevMode[x].dmPelsHeight);

    { Цвета }
    case DevMode[x].dmBitsPerPel of
      4 : tmpStr2 := '16 Colors';
      8 : tmpStr2 := '256 Colors';
      16 : tmpStr2 := 'High Color (16 Bit)';
      32 : tmpStr2 := 'True Color (32 Bit)';
    end;

    { А теперь полученную информацию надо отобразить }
    with ListView1.Items.Add do
    begin
      Caption := tmpStr1;
      SubItems.Add(tmpStr2);
    end;

    { В ListView надо встать не строку с описанием текущего режима,
    для этого сохраним индекс элемента с описанием этого режима }
    if ( cxScreen = DevMode[x].dmPelsWidth ) and
    ( cyScreen = DevMode[x].dmPelsHeight ) and
    ( Resolution = DevMode[x].dmBitsPerPel ) then
      Selection := x;

    inc(x);

    if x = 20 then
      Break;
  end;

  { В ListView перемещаемся на строчку с описанием текущего режима }
  ActiveControl := ListView1;
  ListView1.Selected := ListView1.Items.Item[Selection];
end;


{Установка выбранного пользователем видеорежима}
procedure TForm1.ListView1DblClick(Sender: TObject);
var
  tmpDevMode : TDevMode;
begin
  { Получаем сохраненную ранее информацию по выбранному режиму}
  tmpDevMode := DevMode[ListView1.Items.IndexOf(ListView1.Selected)];

  { Скажем Windows, какие параметры надо сменить }
  tmpDevMode.dmFields := DM_BITSPERPEL or DM_PELSWIDTH or
    DM_PELSHEIGHT or DM_DISPLAYFLAGS or DM_DISPLAYFREQUENCY;

  { Очень неплохо будет протестировать видеорежим
  и записать изменения в реестр}
  if ChangeDisplaySettings(tmpDevMode, CDS_TEST) =
  DISP_CHANGE_SUCCESSFUL then
    ChangeDisplaySettings(tmpDevMode, CDS_UPDATEREGISTRY);
end;

Замечание 1:

Не рекомендуется устанавливать видеорежимы, отличные от полученных вызовами EnumDisplaySettings. Возможна ситуация, когда пользователь вместо рабочего стола увидит лишь черный экран.

Замечание 2:

Многие драйвера, особенно старые не поддерживают изменения видеорежима без перезагрузки компьютера.

Обнаружение изменений видеорежима

При изменениях видеорежима генерируется сообщение WM_DISPLAYCHANGE. Необходимо создать обработчик данного сообщения в вашем приложении.

...
type
  TForm1 = class(TForm)
  ListBox1: TListBox;
...
private
  procedure WMDisplayChange(var message:TMessage); message WM_DISPLAYCHANGE;
...

procedure TForm1.WMDisplayChange(var message: TMessage);
begin
  ShowMessage('Changes in display detected!');
  inherited;
end;

Другое по теме:

Категории

Статьи

Советы

Copyright © 2023 - All Rights Reserved - www.delphirus.com