Большой архив статей, книг, документации по программированию, вебдизайну, компьютерной графике, сетям, операционным системам и многому другому
 
<Добавить в Избранное>    <Сделать стартовой>    <Реклама на сайте>    <Контакты>
  Главная Документация Программы Обои   Экспорт RSS E-Books
 
 

   Программирование -> Delphi/Pascal -> Получение и установка видеорежимов в Windows

Mike Goblin, Lel


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

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


Получить видеорежимы можно серией вызовов 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
Возвращаемое значение:

Value

Meaning

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;
 

 
Интересное в сети
 
10 новых программ
CodeLobster PHP Edition 3.7.2
WinToFlash 0.7.0008
Free Video to Flash Converter 4.7.24
Total Commander v7.55
aTunes 2.0.1
Process Explorer v12.04
Backup42 v3.0
Predator 2.0.1
FastStone Image Viewer 4.1
Process Lasso 3.70.4
FastStone Image Viewer 4.0
Xion Audio Player 1.0.125
Notepad GNU v.2.2.8.7.7
K-Lite Codec Pack 5.3.0 Full


Наши сервисы
Рассылка новостей. Подпишитесь на рассылку сейчас и вы всегда будете в курсе последних событий в мире информационных технологий.
Новостные информеры. Поставьте наши информеры к себе и у вас на сайте появится дополнительный постоянно обновляемый раздел.
Добавление статей. Если вы являетесь автором статьи или обзора на тему ИТ присылайте материал нам, мы с удовольствием опубликуем его у себя на сайте.
Реклама на сайте. Размещая рекламу у нас, вы получите новых посетителей, которые могут стать вашими клиентами.
 
Это интересно
 

Copyright © CompDoc.Ru
При цитировании и перепечатке ссылка на www.compdoc.ru обязательна. Карта сайта.